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