• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_helper.h"
20 #include "ecmascript/mem/region.h"
21 #include "ecmascript/method.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 
IntPtrLSR(GateRef x,GateRef y)65 GateRef CircuitBuilder::IntPtrLSR(GateRef x, GateRef y)
66 {
67     auto ptrSize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
68     return BinaryArithmetic(circuit_->Lsr(), ptrSize, x, y);
69 }
70 
IntPtrLSL(GateRef x,GateRef y)71 GateRef CircuitBuilder::IntPtrLSL(GateRef x, GateRef y)
72 {
73     auto ptrSize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
74     return BinaryArithmetic(circuit_->Lsl(), ptrSize, x, y);
75 }
76 
IntPtrOr(GateRef x,GateRef y)77 GateRef CircuitBuilder::IntPtrOr(GateRef x, GateRef y)
78 {
79     auto ptrsize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64;
80     return BinaryArithmetic(circuit_->Or(), ptrsize, x, y);
81 }
82 
IntPtrDiv(GateRef x,GateRef y)83 GateRef CircuitBuilder::IntPtrDiv(GateRef x, GateRef y)
84 {
85     return env_->Is32Bit() ? Int32Div(x, y) : Int64Div(x, y);
86 }
87 
GetInt64OfTInt(GateRef x)88 GateRef CircuitBuilder::GetInt64OfTInt(GateRef x)
89 {
90     GateRef tagged = ChangeTaggedPointerToInt64(x);
91     return Int64And(tagged, Int64(~JSTaggedValue::TAG_MARK));
92 }
93 
GetInt32OfTInt(GateRef x)94 GateRef CircuitBuilder::GetInt32OfTInt(GateRef x)
95 {
96     GateRef tagged = ChangeTaggedPointerToInt64(x);
97     return TruncInt64ToInt32(tagged);
98 }
99 
TaggedCastToIntPtr(GateRef x)100 GateRef CircuitBuilder::TaggedCastToIntPtr(GateRef x)
101 {
102     ASSERT(cmpCfg_ != nullptr);
103     return cmpCfg_->Is32Bit() ? GetInt32OfTInt(x) : GetInt64OfTInt(x);
104 }
105 
GetDoubleOfTDouble(GateRef x)106 GateRef CircuitBuilder::GetDoubleOfTDouble(GateRef x)
107 {
108     GateRef tagged = ChangeTaggedPointerToInt64(x);
109     GateRef val = Int64Sub(tagged, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
110     return CastInt64ToFloat64(val);
111 }
112 
GetBooleanOfTBoolean(GateRef x)113 GateRef CircuitBuilder::GetBooleanOfTBoolean(GateRef x)
114 {
115     GateRef tagged = ChangeTaggedPointerToInt64(x);
116     return TruncInt64ToInt1(tagged);
117 }
118 
GetDoubleOfTNumber(GateRef x)119 GateRef CircuitBuilder::GetDoubleOfTNumber(GateRef x)
120 {
121     Label subentry(env_);
122     SubCfgEntry(&subentry);
123     Label isInt(env_);
124     Label isDouble(env_);
125     Label exit(env_);
126     DEFVALUE(result, env_, VariableType::FLOAT64(), Double(0));
127     Branch(TaggedIsInt(x), &isInt, &isDouble);
128     Bind(&isInt);
129     {
130         result = ChangeInt32ToFloat64(GetInt32OfTInt(x));
131         Jump(&exit);
132     }
133     Bind(&isDouble);
134     {
135         result = GetDoubleOfTDouble(x);
136         Jump(&exit);
137     }
138     Bind(&exit);
139     GateRef ret = *result;
140     SubCfgExit();
141     return ret;
142 }
143 
DoubleToInt(GateRef x,Label * exit)144 GateRef CircuitBuilder::DoubleToInt(GateRef x, Label *exit)
145 {
146     Label overflow(env_);
147 
148     GateRef xInt = ChangeFloat64ToInt32(x);
149     DEFVALUE(result, env_, VariableType::INT32(), xInt);
150 
151     GateRef xInt64 = CastDoubleToInt64(x);
152     // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
153     GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
154     exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
155     exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
156     GateRef bits = Int32(base::INT32_BITS - 1);
157     // exp < 32 - 1
158     Branch(Int32LessThan(exp, bits), exit, &overflow);
159 
160     Bind(&overflow);
161     {
162         result = CallNGCRuntime(acc_.GetGlueFromArgList(), RTSTUB_ID(DoubleToInt),
163                                 Circuit::NullGate(), { x, IntPtr(base::INT32_BITS) }, Circuit::NullGate());
164         Jump(exit);
165     }
166     Bind(exit);
167     auto ret = *result;
168     return ret;
169 }
170 
DoubleToInt(GateRef glue,GateRef x,size_t typeBits)171 GateRef CircuitBuilder::DoubleToInt(GateRef glue, GateRef x, size_t typeBits)
172 {
173     Label entry(env_);
174     env_->SubCfgEntry(&entry);
175     Label exit(env_);
176     Label overflow(env_);
177 
178     GateRef xInt = ChangeFloat64ToInt32(x);
179     DEFVALUE(result, env_, VariableType::INT32(), xInt);
180 
181     if (env_->IsAmd64()) {
182         // 0x80000000: amd64 overflow return value
183         Branch(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit);
184     } else {
185         GateRef xInt64 = CastDoubleToInt64(x);
186         // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
187         GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
188         exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
189         exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
190         GateRef bits = Int32(typeBits - 1);
191         // exp < 32 - 1
192         Branch(Int32LessThan(exp, bits), &exit, &overflow);
193     }
194     Bind(&overflow);
195     {
196         result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), Circuit::NullGate(), { x, IntPtr(typeBits) },
197                                 Circuit::NullGate());
198         Jump(&exit);
199     }
200     Bind(&exit);
201     auto ret = *result;
202     env_->SubCfgExit();
203     return ret;
204 }
205 
Int32ToTaggedInt(GateRef x)206 GateRef CircuitBuilder::Int32ToTaggedInt(GateRef x)
207 {
208     GateRef val = SExtInt32ToInt64(x);
209     return Int64Or(val, Int64(JSTaggedValue::TAG_INT));
210 }
211 
Int32ToTaggedPtr(GateRef x)212 GateRef CircuitBuilder::Int32ToTaggedPtr(GateRef x)
213 {
214     GateRef val = SExtInt32ToInt64(x);
215     return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_INT)));
216 }
217 
Int64ToTaggedPtr(GateRef x)218 GateRef CircuitBuilder::Int64ToTaggedPtr(GateRef x)
219 {
220     return GetCircuit()->NewGate(circuit_->Int64ToTagged(),
221         MachineType::I64, { x }, GateType::TaggedValue());
222 }
223 
ToTaggedInt(GateRef x)224 GateRef CircuitBuilder::ToTaggedInt(GateRef x)
225 {
226     return Int64Or(x, Int64(JSTaggedValue::TAG_INT));
227 }
228 
ToTaggedIntPtr(GateRef x)229 GateRef CircuitBuilder::ToTaggedIntPtr(GateRef x)
230 {
231     return Int64ToTaggedPtr(Int64Or(x, Int64(JSTaggedValue::TAG_INT)));
232 }
233 
DoubleToTaggedDoublePtr(GateRef x)234 GateRef CircuitBuilder::DoubleToTaggedDoublePtr(GateRef x)
235 {
236     GateRef val = CastDoubleToInt64(x);
237     return Int64ToTaggedPtr(Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET)));
238 }
239 
BooleanToTaggedBooleanPtr(GateRef x)240 GateRef CircuitBuilder::BooleanToTaggedBooleanPtr(GateRef x)
241 {
242     auto val = ZExtInt1ToInt64(x);
243     return Int64ToTaggedPtr(Int64Or(val, Int64(JSTaggedValue::TAG_BOOLEAN_MASK)));
244 }
245 
BooleanToInt32(GateRef x)246 GateRef CircuitBuilder::BooleanToInt32(GateRef x)
247 {
248     return ZExtInt1ToInt32(x);
249 }
250 
BooleanToFloat64(GateRef x)251 GateRef CircuitBuilder::BooleanToFloat64(GateRef x)
252 {
253     return ChangeInt32ToFloat64(ZExtInt1ToInt32(x));
254 }
255 
Float32ToTaggedDoublePtr(GateRef x)256 GateRef CircuitBuilder::Float32ToTaggedDoublePtr(GateRef x)
257 {
258     GateRef val = ExtFloat32ToDouble(x);
259     return DoubleToTaggedDoublePtr(val);
260 }
261 
TaggedDoublePtrToFloat32(GateRef x)262 GateRef CircuitBuilder::TaggedDoublePtrToFloat32(GateRef x)
263 {
264     GateRef val = GetDoubleOfTDouble(x);
265     return TruncDoubleToFloat32(val);
266 }
267 
TaggedIntPtrToFloat32(GateRef x)268 GateRef CircuitBuilder::TaggedIntPtrToFloat32(GateRef x)
269 {
270     GateRef val = GetInt32OfTInt(x);
271     return ChangeInt32ToFloat32(val);
272 }
273 
DoubleToTaggedDouble(GateRef x)274 GateRef CircuitBuilder::DoubleToTaggedDouble(GateRef x)
275 {
276     GateRef val = CastDoubleToInt64(x);
277     return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
278 }
279 
DoubleIsNAN(GateRef x)280 GateRef CircuitBuilder::DoubleIsNAN(GateRef x)
281 {
282     GateRef diff = DoubleEqual(x, x);
283     return Equal(SExtInt1ToInt32(diff), Int32(0));
284 }
285 
DoubleToTagged(GateRef x)286 GateRef CircuitBuilder::DoubleToTagged(GateRef x)
287 {
288     GateRef val = CastDoubleToInt64(x);
289     acc_.SetGateType(val, GateType::TaggedValue());
290     return Int64Add(val, Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET));
291 }
292 
293 template<OpCode Op, MachineType Type>
BinaryOp(GateRef x,GateRef y)294 GateRef CircuitBuilder::BinaryOp(GateRef x, GateRef y)
295 {
296     if (Op == OpCode::ADD) {
297         return BinaryArithmetic(circuit_->Add(), Type, x, y);
298     } else if (Op == OpCode::SUB) {
299         return BinaryArithmetic(circuit_->Sub(), Type, x, y);
300     } else if (Op == OpCode::MUL) {
301         return BinaryArithmetic(circuit_->Mul(), Type, x, y);
302     }
303     UNREACHABLE();
304     return Circuit::NullGate();
305 }
306 
307 template<OpCode Op, MachineType Type>
BinaryOpWithOverflow(GateRef x,GateRef y)308 GateRef CircuitBuilder::BinaryOpWithOverflow(GateRef x, GateRef y)
309 {
310     if (Op == OpCode::ADD) {
311         return BinaryArithmetic(circuit_->AddWithOverflow(), Type, x, y);
312     } else if (Op == OpCode::SUB) {
313         return BinaryArithmetic(circuit_->SubWithOverflow(), Type, x, y);
314     } else if (Op == OpCode::MUL) {
315         return BinaryArithmetic(circuit_->MulWithOverflow(), Type, x, y);
316     }
317     UNREACHABLE();
318     return Circuit::NullGate();
319 }
320 
Equal(GateRef x,GateRef y,const char * comment)321 GateRef CircuitBuilder::Equal(GateRef x, GateRef y, const char* comment)
322 {
323     auto xType = acc_.GetMachineType(x);
324     switch (xType) {
325         case ARCH:
326         case FLEX:
327         case I1:
328         case I8:
329         case I16:
330         case I32:
331         case I64:
332             return BinaryCmp(circuit_->Icmp(static_cast<uint64_t>(ICmpCondition::EQ)), x, y, comment);
333         case F32:
334         case F64:
335             return BinaryCmp(circuit_->Fcmp(static_cast<uint64_t>(FCmpCondition::OEQ)), x, y, comment);
336         default:
337             LOG_ECMA(FATAL) << "this branch is unreachable";
338             UNREACHABLE();
339     }
340 }
341 
NotEqual(GateRef x,GateRef y,const char * comment)342 GateRef CircuitBuilder::NotEqual(GateRef x, GateRef y, const char* comment)
343 {
344     auto xType = acc_.GetMachineType(x);
345     switch (xType) {
346         case ARCH:
347         case FLEX:
348         case I1:
349         case I8:
350         case I16:
351         case I32:
352         case I64:
353             return BinaryCmp(circuit_->Icmp(static_cast<uint64_t>(ICmpCondition::NE)), x, y, comment);
354         case F32:
355         case F64:
356             return BinaryCmp(circuit_->Fcmp(static_cast<uint64_t>(FCmpCondition::ONE)), x, y, comment);
357         default:
358             LOG_ECMA(FATAL) << "this branch is unreachable";
359             UNREACHABLE();
360     }
361 }
362 
363 }
364 
365 #endif  // ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H