1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H
17#define ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H
18
19#include "ecmascript/compiler/circuit_builder.h"
20#include "ecmascript/compiler/circuit_builder_helper.h"
21#include "ecmascript/compiler/share_gate_meta_data.h"
22
23namespace panda::ecmascript::kungfu {
24
25GateRef CircuitBuilder::Int8Equal(GateRef x, GateRef y)
26{
27    return Equal(x, y);
28}
29
30GateRef CircuitBuilder::Int32NotEqual(GateRef x, GateRef y)
31{
32    return NotEqual(x, y);
33}
34
35GateRef CircuitBuilder::Int64NotEqual(GateRef x, GateRef y)
36{
37    return NotEqual(x, y);
38}
39
40GateRef CircuitBuilder::Int64Equal(GateRef x, GateRef y)
41{
42    return Equal(x, y);
43}
44
45GateRef CircuitBuilder::Int32Equal(GateRef x, GateRef y)
46{
47    return Equal(x, y);
48}
49
50GateRef CircuitBuilder::IntPtrGreaterThan(GateRef x, GateRef y)
51{
52    return env_->Is32Bit() ? Int32GreaterThan(x, y) : Int64GreaterThan(x, y);
53}
54
55GateRef CircuitBuilder::IntPtrAnd(GateRef x, GateRef y)
56{
57    return env_->Is32Bit() ? Int32And(x, y) : Int64And(x, y);
58}
59
60GateRef CircuitBuilder::IntPtrNot(GateRef x)
61{
62    return env_->Is32Bit() ? Int32Not(x) : Int64Not(x);
63}
64
65GateRef CircuitBuilder::IntPtrEqual(GateRef x, GateRef y)
66{
67    return env_->Is32Bit() ? Int32Equal(x, y) : Int64Equal(x, y);
68}
69
70GateRef CircuitBuilder::IntPtrLSR(GateRef x, GateRef y)
71{
72    auto ptrSize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
73    return BinaryArithmetic(circuit_->Lsr(), ptrSize, x, y);
74}
75
76GateRef CircuitBuilder::IntPtrLSL(GateRef x, GateRef y)
77{
78    auto ptrSize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
79    return BinaryArithmetic(circuit_->Lsl(), ptrSize, x, y);
80}
81
82GateRef CircuitBuilder::Int16ToBigEndianInt16(GateRef x)
83{
84    GateRef int16toint32 = ZExtInt16ToInt32(x);
85    GateRef high8bits = Int32LSL(Int32And(int16toint32, Int32(0x00FF)), Int32(8));
86    GateRef low8bits = Int32LSR(Int32And(int16toint32, Int32(0xFF00)), Int32(8));
87    return TruncInt32ToInt16(Int32Add(high8bits, low8bits));
88}
89
90GateRef CircuitBuilder::Int32ToBigEndianInt32(GateRef x)
91{
92    GateRef first8bits = Int32LSL(Int32And(x, Int32(0x000000FF)), Int32(24));
93    GateRef second8bits = Int32LSL(Int32And(x, Int32(0x0000FF00)), Int32(8));
94    GateRef third8bits = Int32LSR(Int32And(x, Int32(0x00FF0000)), Int32(8));
95    GateRef fourth8bits = Int32LSR(Int32And(x, Int32(0xFF000000)), Int32(24));
96    GateRef firstHalf = Int32Add(first8bits, second8bits);
97    GateRef secondHalf = Int32Add(third8bits, fourth8bits);
98    return Int32Add(firstHalf, secondHalf);
99}
100
101GateRef CircuitBuilder::Int64ToBigEndianInt64(GateRef x)
102{
103    GateRef first8bits = Int64LSL(Int64And(x, Int64(0x00000000000000FF)), Int64(56));
104    GateRef second8bits = Int64LSL(Int64And(x, Int64(0x000000000000FF00)), Int64(40));
105    // 0-16bits
106    GateRef first16bits = Int64Add(first8bits, second8bits);
107    GateRef third8bits = Int64LSL(Int64And(x, Int64(0x0000000000FF0000)), Int64(24));
108    GateRef fourth8bits = Int64LSL(Int64And(x, Int64(0x00000000FF000000)), Int64(8));
109    // 16-32bits
110    GateRef second16bits = Int64Add(third8bits, fourth8bits);
111    // 0-32bits
112    GateRef firstHalf = Int64Add(first16bits, second16bits);
113    GateRef fifth8bits = Int64LSR(Int64And(x, Int64(0x000000FF00000000)), Int64(8));
114    GateRef sixth8bits = Int64LSR(Int64And(x, Int64(0x0000FF0000000000)), Int64(24));
115    //32-48bits
116    GateRef third16bits = Int64Add(fifth8bits, sixth8bits);
117    GateRef seventh8bits = Int64LSR(Int64And(x, Int64(0x00FF000000000000)), Int64(40));
118    GateRef eighth8bits = Int64LSR(Int64And(x, Int64(0xFF00000000000000)), Int64(56));
119    //48-64bits
120    GateRef fourth16bits = Int64Add(seventh8bits, eighth8bits);
121    //32-64bits
122    GateRef secondHalf = Int64Add(third16bits, fourth16bits);
123    //0-64bits
124    return Int64Add(firstHalf, secondHalf);
125}
126
127GateRef CircuitBuilder::IntPtrOr(GateRef x, GateRef y)
128{
129    auto ptrsize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
130    return BinaryArithmetic(circuit_->Or(), ptrsize, x, y);
131}
132
133GateRef CircuitBuilder::IntPtrDiv(GateRef x, GateRef y)
134{
135    return env_->Is32Bit() ? Int32Div(x, y) : Int64Div(x, y);
136}
137
138GateRef CircuitBuilder::GetInt64OfTInt(GateRef x)
139{
140    GateRef tagged = ChangeTaggedPointerToInt64(x);
141    return Int64And(tagged, Int64(~JSTaggedValue::TAG_MARK));
142}
143
144GateRef CircuitBuilder::GetInt32OfTInt(GateRef x)
145{
146    GateRef tagged = ChangeTaggedPointerToInt64(x);
147    return TruncInt64ToInt32(tagged);
148}
149
150GateRef CircuitBuilder::GetInt32OfTNumber(GateRef x)
151{
152    Label subentry(env_);
153    SubCfgEntry(&subentry);
154    Label isInt(env_);
155    Label isDouble(env_);
156    Label exit(env_);
157    DEFVALUE(result, env_, VariableType::INT32(), Int32(0));
158    BRANCH_CIR2(TaggedIsInt(x), &isInt, &isDouble);
159    Bind(&isInt);
160    {
161        result = GetInt32OfTInt(x);
162        Jump(&exit);
163    }
164    Bind(&isDouble);
165    {
166        result = DoubleCheckINFInRangeInt32(GetDoubleOfTDouble(x));
167        Jump(&exit);
168    }
169    Bind(&exit);
170    GateRef ret = *result;
171    SubCfgExit();
172    return ret;
173}
174
175GateRef CircuitBuilder::TaggedCastToIntPtr(GateRef x)
176{
177    return env_->Is32Bit() ? GetInt32OfTInt(x) : GetInt64OfTInt(x);
178}
179
180GateRef CircuitBuilder::GetDoubleOfTInt(GateRef x)
181{
182    return ChangeInt32ToFloat64(GetInt32OfTInt(x));
183}
184
185GateRef CircuitBuilder::GetDoubleOfTDouble(GateRef x)
186{
187    GateRef tagged = ChangeTaggedPointerToInt64(x);
188    GateRef val = Int64Sub(tagged, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
189    return CastInt64ToFloat64(val);
190}
191
192GateRef CircuitBuilder::GetBooleanOfTBoolean(GateRef x)
193{
194    GateRef tagged = ChangeTaggedPointerToInt64(x);
195    return TruncInt64ToInt1(tagged);
196}
197
198GateRef CircuitBuilder::Int32ToTaggedInt(GateRef x)
199{
200    GateRef val = SExtInt32ToInt64(x);
201    return Int64Or(val, Int64(JSTaggedValue::TAG_INT));
202}
203
204GateRef CircuitBuilder::Int32ToTaggedPtr(GateRef x)
205{
206    GateRef val = SExtInt32ToInt64(x);
207    return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_INT)));
208}
209
210GateRef CircuitBuilder::Int64ToTaggedPtr(GateRef x)
211{
212    return GetCircuit()->NewGate(circuit_->Int64ToTagged(),
213        MachineType::I64, { x }, GateType::TaggedValue());
214}
215
216GateRef CircuitBuilder::ToTaggedInt(GateRef x)
217{
218    return Int64Or(x, Int64(JSTaggedValue::TAG_INT));
219}
220
221GateRef CircuitBuilder::ToTaggedIntPtr(GateRef x)
222{
223    return Int64ToTaggedPtr(Int64Or(x, Int64(JSTaggedValue::TAG_INT)));
224}
225
226GateRef CircuitBuilder::DoubleToTaggedDoublePtr(GateRef x)
227{
228    GateRef val = CastDoubleToInt64(x);
229    return Int64ToTaggedPtr(Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET)));
230}
231
232GateRef CircuitBuilder::DoubleIsImpureNaN(GateRef x)
233{
234    GateRef impureNaN = Int64(JSTaggedValue::TAG_INT - JSTaggedValue::DOUBLE_ENCODE_OFFSET);
235    GateRef val = CastDoubleToInt64(x);
236    return Int64UnsignedGreaterThanOrEqual(val, impureNaN);
237}
238
239GateRef CircuitBuilder::BooleanToTaggedBooleanPtr(GateRef x)
240{
241    auto val = ZExtInt1ToInt64(x);
242    return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_BOOLEAN_MASK)));
243}
244
245GateRef CircuitBuilder::BooleanToInt32(GateRef x)
246{
247    return ZExtInt1ToInt32(x);
248}
249
250GateRef CircuitBuilder::BooleanToFloat64(GateRef x)
251{
252    return ChangeInt32ToFloat64(ZExtInt1ToInt32(x));
253}
254
255GateRef CircuitBuilder::Float32ToTaggedDoublePtr(GateRef x)
256{
257    GateRef val = ExtFloat32ToDouble(x);
258    return DoubleToTaggedDoublePtr(val);
259}
260
261GateRef CircuitBuilder::TaggedDoublePtrToFloat32(GateRef x)
262{
263    GateRef val = GetDoubleOfTDouble(x);
264    return TruncDoubleToFloat32(val);
265}
266
267GateRef CircuitBuilder::TaggedIntPtrToFloat32(GateRef x)
268{
269    GateRef val = GetInt32OfTInt(x);
270    return ChangeInt32ToFloat32(val);
271}
272
273GateRef CircuitBuilder::DoubleToTaggedDouble(GateRef x)
274{
275    GateRef val = CastDoubleToInt64(x);
276    return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
277}
278
279GateRef CircuitBuilder::DoubleIsNAN(GateRef x)
280{
281    GateRef diff = DoubleEqual(x, x);
282    return Equal(SExtInt1ToInt32(diff), Int32(0));
283}
284
285GateRef CircuitBuilder::DoubleToTagged(GateRef x)
286{
287    GateRef val = CastDoubleToInt64(x);
288    acc_.SetGateType(val, GateType::TaggedValue());
289    return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
290}
291
292template<OpCode Op, MachineType Type>
293GateRef CircuitBuilder::BinaryOp(GateRef x, GateRef y)
294{
295    if (Op == OpCode::ADD) {
296        return BinaryArithmetic(circuit_->Add(), Type, x, y);
297    } else if (Op == OpCode::SUB) {
298        return BinaryArithmetic(circuit_->Sub(), Type, x, y);
299    } else if (Op == OpCode::MUL) {
300        return BinaryArithmetic(circuit_->Mul(), Type, x, y);
301    }
302    UNREACHABLE();
303    return Circuit::NullGate();
304}
305
306template<OpCode Op, MachineType Type>
307GateRef CircuitBuilder::BinaryOpWithOverflow(GateRef x, GateRef y)
308{
309    if (Op == OpCode::ADD) {
310        return BinaryArithmetic(circuit_->AddWithOverflow(), Type, x, y);
311    } else if (Op == OpCode::SUB) {
312        return BinaryArithmetic(circuit_->SubWithOverflow(), Type, x, y);
313    } else if (Op == OpCode::MUL) {
314        return BinaryArithmetic(circuit_->MulWithOverflow(), Type, x, y);
315    }
316    UNREACHABLE();
317    return Circuit::NullGate();
318}
319
320GateRef CircuitBuilder::Equal(GateRef x, GateRef y, const char* comment)
321{
322    auto xType = acc_.GetMachineType(x);
323    switch (xType) {
324        case ARCH:
325        case FLEX:
326        case I1:
327        case I8:
328        case I16:
329        case I32:
330        case I64:
331            return BinaryCmp(circuit_->Icmp(static_cast<uint64_t>(ICmpCondition::EQ)), x, y, comment);
332        case F32:
333        case F64:
334            return BinaryCmp(circuit_->Fcmp(static_cast<uint64_t>(FCmpCondition::OEQ)), x, y, comment);
335        default:
336            LOG_ECMA(FATAL) << "this branch is unreachable";
337            UNREACHABLE();
338    }
339}
340
341GateRef CircuitBuilder::NotEqual(GateRef x, GateRef y, const char* comment)
342{
343    auto xType = acc_.GetMachineType(x);
344    switch (xType) {
345        case ARCH:
346        case FLEX:
347        case I1:
348        case I8:
349        case I16:
350        case I32:
351        case I64:
352            return BinaryCmp(circuit_->Icmp(static_cast<uint64_t>(ICmpCondition::NE)), x, y, comment);
353        case F32:
354        case F64:
355            return BinaryCmp(circuit_->Fcmp(static_cast<uint64_t>(FCmpCondition::ONE)), x, y, comment);
356        default:
357            LOG_ECMA(FATAL) << "this branch is unreachable";
358            UNREACHABLE();
359    }
360}
361
362}
363
364#endif  // ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H
365