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 
23 namespace panda::ecmascript::kungfu {
24 
Int8Equal(GateRef x, GateRef y)25 GateRef CircuitBuilder::Int8Equal(GateRef x, GateRef y)
26 {
27     return Equal(x, y);
28 }
29 
Int32NotEqual(GateRef x, GateRef y)30 GateRef CircuitBuilder::Int32NotEqual(GateRef x, GateRef y)
31 {
32     return NotEqual(x, y);
33 }
34 
Int64NotEqual(GateRef x, GateRef y)35 GateRef CircuitBuilder::Int64NotEqual(GateRef x, GateRef y)
36 {
37     return NotEqual(x, y);
38 }
39 
Int64Equal(GateRef x, GateRef y)40 GateRef CircuitBuilder::Int64Equal(GateRef x, GateRef y)
41 {
42     return Equal(x, y);
43 }
44 
Int32Equal(GateRef x, GateRef y)45 GateRef CircuitBuilder::Int32Equal(GateRef x, GateRef y)
46 {
47     return Equal(x, y);
48 }
49 
IntPtrGreaterThan(GateRef x, GateRef y)50 GateRef CircuitBuilder::IntPtrGreaterThan(GateRef x, GateRef y)
51 {
52     return env_->Is32Bit() ? Int32GreaterThan(x, y) : Int64GreaterThan(x, y);
53 }
54 
IntPtrAnd(GateRef x, GateRef y)55 GateRef CircuitBuilder::IntPtrAnd(GateRef x, GateRef y)
56 {
57     return env_->Is32Bit() ? Int32And(x, y) : Int64And(x, y);
58 }
59 
IntPtrNot(GateRef x)60 GateRef CircuitBuilder::IntPtrNot(GateRef x)
61 {
62     return env_->Is32Bit() ? Int32Not(x) : Int64Not(x);
63 }
64 
IntPtrEqual(GateRef x, GateRef y)65 GateRef CircuitBuilder::IntPtrEqual(GateRef x, GateRef y)
66 {
67     return env_->Is32Bit() ? Int32Equal(x, y) : Int64Equal(x, y);
68 }
69 
IntPtrLSR(GateRef x, GateRef y)70 GateRef 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 
IntPtrLSL(GateRef x, GateRef y)76 GateRef 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 
Int16ToBigEndianInt16(GateRef x)82 GateRef 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 
Int32ToBigEndianInt32(GateRef x)90 GateRef 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 
Int64ToBigEndianInt64(GateRef x)101 GateRef 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 
IntPtrOr(GateRef x, GateRef y)127 GateRef 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 
IntPtrDiv(GateRef x, GateRef y)133 GateRef CircuitBuilder::IntPtrDiv(GateRef x, GateRef y)
134 {
135     return env_->Is32Bit() ? Int32Div(x, y) : Int64Div(x, y);
136 }
137 
GetInt64OfTInt(GateRef x)138 GateRef CircuitBuilder::GetInt64OfTInt(GateRef x)
139 {
140     GateRef tagged = ChangeTaggedPointerToInt64(x);
141     return Int64And(tagged, Int64(~JSTaggedValue::TAG_MARK));
142 }
143 
GetInt32OfTInt(GateRef x)144 GateRef CircuitBuilder::GetInt32OfTInt(GateRef x)
145 {
146     GateRef tagged = ChangeTaggedPointerToInt64(x);
147     return TruncInt64ToInt32(tagged);
148 }
149 
GetInt32OfTNumber(GateRef x)150 GateRef 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 
TaggedCastToIntPtr(GateRef x)175 GateRef CircuitBuilder::TaggedCastToIntPtr(GateRef x)
176 {
177     return env_->Is32Bit() ? GetInt32OfTInt(x) : GetInt64OfTInt(x);
178 }
179 
GetDoubleOfTInt(GateRef x)180 GateRef CircuitBuilder::GetDoubleOfTInt(GateRef x)
181 {
182     return ChangeInt32ToFloat64(GetInt32OfTInt(x));
183 }
184 
GetDoubleOfTDouble(GateRef x)185 GateRef 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 
GetBooleanOfTBoolean(GateRef x)192 GateRef CircuitBuilder::GetBooleanOfTBoolean(GateRef x)
193 {
194     GateRef tagged = ChangeTaggedPointerToInt64(x);
195     return TruncInt64ToInt1(tagged);
196 }
197 
Int32ToTaggedInt(GateRef x)198 GateRef CircuitBuilder::Int32ToTaggedInt(GateRef x)
199 {
200     GateRef val = SExtInt32ToInt64(x);
201     return Int64Or(val, Int64(JSTaggedValue::TAG_INT));
202 }
203 
Int32ToTaggedPtr(GateRef x)204 GateRef CircuitBuilder::Int32ToTaggedPtr(GateRef x)
205 {
206     GateRef val = SExtInt32ToInt64(x);
207     return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_INT)));
208 }
209 
Int64ToTaggedPtr(GateRef x)210 GateRef CircuitBuilder::Int64ToTaggedPtr(GateRef x)
211 {
212     return GetCircuit()->NewGate(circuit_->Int64ToTagged(),
213         MachineType::I64, { x }, GateType::TaggedValue());
214 }
215 
ToTaggedInt(GateRef x)216 GateRef CircuitBuilder::ToTaggedInt(GateRef x)
217 {
218     return Int64Or(x, Int64(JSTaggedValue::TAG_INT));
219 }
220 
ToTaggedIntPtr(GateRef x)221 GateRef CircuitBuilder::ToTaggedIntPtr(GateRef x)
222 {
223     return Int64ToTaggedPtr(Int64Or(x, Int64(JSTaggedValue::TAG_INT)));
224 }
225 
DoubleToTaggedDoublePtr(GateRef x)226 GateRef CircuitBuilder::DoubleToTaggedDoublePtr(GateRef x)
227 {
228     GateRef val = CastDoubleToInt64(x);
229     return Int64ToTaggedPtr(Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET)));
230 }
231 
DoubleIsImpureNaN(GateRef x)232 GateRef 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 
BooleanToTaggedBooleanPtr(GateRef x)239 GateRef CircuitBuilder::BooleanToTaggedBooleanPtr(GateRef x)
240 {
241     auto val = ZExtInt1ToInt64(x);
242     return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_BOOLEAN_MASK)));
243 }
244 
BooleanToInt32(GateRef x)245 GateRef CircuitBuilder::BooleanToInt32(GateRef x)
246 {
247     return ZExtInt1ToInt32(x);
248 }
249 
BooleanToFloat64(GateRef x)250 GateRef CircuitBuilder::BooleanToFloat64(GateRef x)
251 {
252     return ChangeInt32ToFloat64(ZExtInt1ToInt32(x));
253 }
254 
Float32ToTaggedDoublePtr(GateRef x)255 GateRef CircuitBuilder::Float32ToTaggedDoublePtr(GateRef x)
256 {
257     GateRef val = ExtFloat32ToDouble(x);
258     return DoubleToTaggedDoublePtr(val);
259 }
260 
TaggedDoublePtrToFloat32(GateRef x)261 GateRef CircuitBuilder::TaggedDoublePtrToFloat32(GateRef x)
262 {
263     GateRef val = GetDoubleOfTDouble(x);
264     return TruncDoubleToFloat32(val);
265 }
266 
TaggedIntPtrToFloat32(GateRef x)267 GateRef CircuitBuilder::TaggedIntPtrToFloat32(GateRef x)
268 {
269     GateRef val = GetInt32OfTInt(x);
270     return ChangeInt32ToFloat32(val);
271 }
272 
DoubleToTaggedDouble(GateRef x)273 GateRef CircuitBuilder::DoubleToTaggedDouble(GateRef x)
274 {
275     GateRef val = CastDoubleToInt64(x);
276     return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
277 }
278 
DoubleIsNAN(GateRef x)279 GateRef CircuitBuilder::DoubleIsNAN(GateRef x)
280 {
281     GateRef diff = DoubleEqual(x, x);
282     return Equal(SExtInt1ToInt32(diff), Int32(0));
283 }
284 
DoubleToTagged(GateRef x)285 GateRef 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 
292 template<OpCode Op, MachineType Type>
BinaryOp(GateRef x, GateRef y)293 GateRef 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 
306 template<OpCode Op, MachineType Type>
BinaryOpWithOverflow(GateRef x, GateRef y)307 GateRef 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 
Equal(GateRef x, GateRef y, const char* comment)320 GateRef 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 
NotEqual(GateRef x, GateRef y, const char* comment)341 GateRef 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