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 #include "ecmascript/compiler/lcr_circuit_builder.h"
17 #include "ecmascript/compiler/circuit_builder-inl.h"
18
19 namespace panda::ecmascript::kungfu {
20
BinaryCmp(const GateMetaData * meta,GateRef left,GateRef right,const char * comment)21 GateRef CircuitBuilder::BinaryCmp(const GateMetaData* meta, GateRef left, GateRef right, const char* comment)
22 {
23 return GetCircuit()->NewGate(meta, MachineType::I1, { left, right }, GateType::NJSValue(), comment);
24 }
25
GetMachineTypeFromVariableType(VariableType type)26 MachineType CircuitBuilder::GetMachineTypeFromVariableType(VariableType type)
27 {
28 return type.GetMachineType();
29 }
30
Sqrt(GateRef param)31 GateRef CircuitBuilder::Sqrt(GateRef param)
32 {
33 return GetCircuit()->NewGate(circuit_->Sqrt(), MachineType::F64, {param}, GateType::DoubleType());
34 }
35
AddWithOverflow(GateRef left,GateRef right)36 GateRef CircuitBuilder::AddWithOverflow(GateRef left, GateRef right)
37 {
38 return GetCircuit()->NewGate(circuit_->AddWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType());
39 }
40
SubWithOverflow(GateRef left,GateRef right)41 GateRef CircuitBuilder::SubWithOverflow(GateRef left, GateRef right)
42 {
43 return GetCircuit()->NewGate(circuit_->SubWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType());
44 }
45
MulWithOverflow(GateRef left,GateRef right)46 GateRef CircuitBuilder::MulWithOverflow(GateRef left, GateRef right)
47 {
48 return GetCircuit()->NewGate(circuit_->MulWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType());
49 }
50
ExtractValue(MachineType mt,GateRef pointer,GateRef index)51 GateRef CircuitBuilder::ExtractValue(MachineType mt, GateRef pointer, GateRef index)
52 {
53 ASSERT(acc_.GetOpCode(index) == OpCode::CONSTANT);
54 ASSERT(acc_.GetMachineType(index) == MachineType::I32);
55 return GetCircuit()->NewGate(circuit_->ExtractValue(), mt, {pointer, index}, GateType::NJSValue());
56 }
57
ReadSp()58 GateRef CircuitBuilder::ReadSp()
59 {
60 return circuit_->NewGate(circuit_->ReadSp(), MachineType::I64, GateType::NJSValue());
61 }
62
GetMachineTypeOfValueType(ValueType type)63 MachineType CircuitBuilder::GetMachineTypeOfValueType(ValueType type)
64 {
65 switch (type) {
66 case ValueType::BOOL:
67 return MachineType::I1;
68 case ValueType::INT32:
69 case ValueType::UINT32:
70 return MachineType::I32;
71 case ValueType::FLOAT64:
72 return MachineType::F64;
73 case ValueType::TAGGED_BOOLEAN:
74 case ValueType::TAGGED_INT:
75 case ValueType::TAGGED_DOUBLE:
76 case ValueType::TAGGED_NUMBER:
77 case ValueType::TAGGED_NULL:
78 case ValueType::CHAR:
79 case ValueType::ECMA_STRING:
80 case ValueType::UNDEFINED:
81 case ValueType::HOLE_INT:
82 case ValueType::HOLE_DOUBLE:
83 return MachineType::I64;
84 default:
85 UNREACHABLE();
86 break;
87 }
88 return MachineType::NOVALUE;
89 }
90
BinaryArithmetic(const GateMetaData * meta,MachineType machineType,GateRef left,GateRef right,GateType gateType,const char * comment)91 GateRef CircuitBuilder::BinaryArithmetic(const GateMetaData* meta, MachineType machineType,
92 GateRef left, GateRef right, GateType gateType, const char* comment)
93 {
94 auto circuit = GetCircuit();
95 if (gateType == GateType::Empty()) {
96 gateType = acc_.GetGateType(left);
97 }
98 return circuit->NewGate(meta, machineType, { left, right }, gateType, comment);
99 }
100
Alloca(size_t size)101 GateRef CircuitBuilder::Alloca(size_t size)
102 {
103 return GetCircuit()->NewGate(circuit_->Alloca(size), MachineType::ARCH, GateType::NJSValue());
104 }
105
106 // memory
Store(VariableType type,GateRef glue,GateRef base,GateRef offset,GateRef value,MemoryAttribute mAttr)107 void CircuitBuilder::Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value,
108 MemoryAttribute mAttr)
109 {
110 auto label = GetCurrentLabel();
111 auto depend = label->GetDepend();
112 if (mAttr.GetBarrier() == MemoryAttribute::Barrier::UNKNOWN_BARRIER && acc_.IsConstant(value)) {
113 mAttr.SetBarrier(MemoryAttribute::Barrier::NO_BARRIER);
114 }
115 auto bit = LoadStoreAccessor::ToValue(mAttr);
116 GateRef result = GetCircuit()->NewGate(circuit_->Store(bit),
117 MachineType::NOVALUE, { depend, glue, base, offset, value }, type.GetGateType());
118 label->SetDepend(result);
119 }
120
StoreWithoutBarrier(VariableType type,GateRef addr,GateRef value,MemoryAttribute mAttr)121 void CircuitBuilder::StoreWithoutBarrier(VariableType type, GateRef addr, GateRef value, MemoryAttribute mAttr)
122 {
123 auto label = GetCurrentLabel();
124 auto depend = label->GetDepend();
125 auto bit = LoadStoreAccessor::ToValue(mAttr);
126 GateRef result = GetCircuit()->NewGate(circuit_->StoreWithoutBarrier(bit),
127 MachineType::NOVALUE, { depend, addr, value }, type.GetGateType());
128 label->SetDepend(result);
129 }
130
131 // memory
Load(VariableType type,GateRef base,GateRef offset,MemoryAttribute mAttr)132 GateRef CircuitBuilder::Load(VariableType type, GateRef base, GateRef offset, MemoryAttribute mAttr)
133 {
134 auto label = GetCurrentLabel();
135 auto depend = label->GetDepend();
136 GateRef val = PtrAdd(base, offset);
137 auto bits = LoadStoreAccessor::ToValue(mAttr);
138 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(),
139 { depend, val }, type.GetGateType());
140 label->SetDepend(result);
141 return result;
142 }
143
Load(VariableType type,GateRef base,GateRef offset,GateRef depend,MemoryAttribute mAttr)144 GateRef CircuitBuilder::Load(VariableType type, GateRef base, GateRef offset, GateRef depend,
145 MemoryAttribute mAttr)
146 {
147 GateRef val = PtrAdd(base, offset);
148 auto bits = LoadStoreAccessor::ToValue(mAttr);
149 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(),
150 { depend, val }, type.GetGateType());
151 return result;
152 }
153
Load(VariableType type,GateRef addr,MemoryAttribute mAttr)154 GateRef CircuitBuilder::Load(VariableType type, GateRef addr, MemoryAttribute mAttr)
155 {
156 auto label = GetCurrentLabel();
157 auto depend = label->GetDepend();
158 auto bits = LoadStoreAccessor::ToValue(mAttr);
159 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(),
160 { depend, addr }, type.GetGateType());
161 label->SetDepend(result);
162 return result;
163 }
164
DoubleTrunc(GateRef gate,GateRef value,const char * comment)165 GateRef CircuitBuilder::DoubleTrunc(GateRef gate, GateRef value, const char* comment)
166 {
167 if (GetCompilationConfig()->IsAArch64()) {
168 return DoubleTrunc(value, comment);
169 }
170
171 GateRef glue = acc_.GetGlueFromArgList();
172 return CallNGCRuntime(glue, RTSTUB_ID(FloatTrunc), Gate::InvalidGateRef, {value}, gate, comment);
173 }
174
GetDoubleOfTNumber(GateRef x)175 GateRef CircuitBuilder::GetDoubleOfTNumber(GateRef x)
176 {
177 Label subentry(env_);
178 SubCfgEntry(&subentry);
179 Label isInt(env_);
180 Label isDouble(env_);
181 Label exit(env_);
182 DEFVALUE(result, env_, VariableType::FLOAT64(), Double(0));
183 BRANCH(TaggedIsInt(x), &isInt, &isDouble);
184 Bind(&isInt);
185 {
186 result = ChangeInt32ToFloat64(GetInt32OfTInt(x));
187 Jump(&exit);
188 }
189 Bind(&isDouble);
190 {
191 result = GetDoubleOfTDouble(x);
192 Jump(&exit);
193 }
194 Bind(&exit);
195 GateRef ret = *result;
196 SubCfgExit();
197 return ret;
198 }
199
DoubleToIntOverflowCheck(GateRef x,size_t typeBits)200 GateRef CircuitBuilder::DoubleToIntOverflowCheck(GateRef x, size_t typeBits)
201 {
202 GateRef xInt64 = CastDoubleToInt64(x);
203 // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
204 GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
205 exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
206 exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
207 GateRef bits = Int32(typeBits - 1);
208 // exp < 32 - 1
209 return Int32LessThan(exp, bits);
210 }
211
TruncDoubleToInt(GateRef glue,GateRef x,size_t typeBits)212 GateRef CircuitBuilder::TruncDoubleToInt(GateRef glue, GateRef x, size_t typeBits)
213 {
214 Label entry(env_);
215 env_->SubCfgEntry(&entry);
216 Label exit(env_);
217 Label overflow(env_);
218
219 GateRef xInt = ChangeFloat64ToInt32(x);
220 DEFVALUE(result, env_, VariableType::INT32(), xInt);
221 BRANCH(DoubleToIntOverflowCheck(x, typeBits), &exit, &overflow);
222
223 Bind(&overflow);
224 {
225 result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), Circuit::NullGate(), { x, IntPtr(typeBits) },
226 Circuit::NullGate());
227 Jump(&exit);
228 }
229 Bind(&exit);
230 auto ret = *result;
231 env_->SubCfgExit();
232 return ret;
233 }
234
SaturateTruncDoubleToInt32(GateRef glue,GateRef x)235 GateRef CircuitBuilder::SaturateTruncDoubleToInt32(GateRef glue, GateRef x)
236 {
237 Label entry(env_);
238 env_->SubCfgEntry(&entry);
239 Label exit(env_);
240 Label overflow(env_);
241
242 GateRef xInt = ChangeFloat64ToInt32(x);
243 DEFVALUE(result, env_, VariableType::INT32(), xInt);
244 BRANCH(DoubleToIntOverflowCheck(x, base::INT32_BITS), &exit, &overflow);
245
246 Bind(&overflow);
247 {
248 result = CallNGCRuntime(glue, RTSTUB_ID(SaturateTruncDoubleToInt32), Circuit::NullGate(), { x },
249 Circuit::NullGate());
250 Jump(&exit);
251 }
252 Bind(&exit);
253 auto ret = *result;
254 env_->SubCfgExit();
255 return ret;
256 }
257
DoubleCheckINFInRangeInt32(GateRef x)258 GateRef CircuitBuilder::DoubleCheckINFInRangeInt32(GateRef x)
259 {
260 Label entry(env_);
261 env_->SubCfgEntry(&entry);
262 Label exit(env_);
263 Label isInfinity(env_);
264 Label positiveInf(env_);
265 Label negativeInf(env_);
266
267 DEFVALUE(result, env_, VariableType::INT32(), DoubleInRangeInt32(x));
268 GateRef Max = Double(INT32_MAX);
269 GateRef Min = Double(INT32_MIN);
270 GateRef pInfinity = Double(base::POSITIVE_INFINITY);
271 Branch(DoubleIsINF(x), &isInfinity, &exit);
272 Bind(&isInfinity);
273 {
274 Branch(DoubleEqual(x, pInfinity), &positiveInf, &negativeInf);
275 Bind(&positiveInf);
276 {
277 result = ChangeFloat64ToInt32(Max);
278 Jump(&exit);
279 }
280 Bind(&negativeInf);
281 {
282 result = ChangeFloat64ToInt32(Min);
283 Jump(&exit);
284 }
285 }
286 Bind(&exit);
287 auto ret = *result;
288 env_->SubCfgExit();
289 return ret;
290 }
291
DoubleInRangeInt32(GateRef x)292 GateRef CircuitBuilder::DoubleInRangeInt32(GateRef x)
293 {
294 Label entry(env_);
295 env_->SubCfgEntry(&entry);
296 Label exit(env_);
297 Label overflow(env_);
298 Label checkUnderflow(env_);
299 Label underflow(env_);
300
301 DEFVALUE(result, env_, VariableType::INT32(), ChangeFloat64ToInt32(x));
302 GateRef Max = Double(INT32_MAX);
303 GateRef Min = Double(INT32_MIN);
304 Branch(DoubleGreaterThan(x, Max), &overflow, &checkUnderflow);
305 Bind(&overflow);
306 {
307 result = ChangeFloat64ToInt32(Max);
308 Jump(&exit);
309 }
310 Bind(&checkUnderflow);
311 {
312 Branch(DoubleLessThan(x, Min), &underflow, &exit);
313 Bind(&underflow);
314 {
315 result = ChangeFloat64ToInt32(Min);
316 Jump(&exit);
317 }
318 }
319 Bind(&exit);
320 auto ret = *result;
321 env_->SubCfgExit();
322 return ret;
323 }
324
325 // According to C++ standard: "If the truncated value cannot fit into the destination type, the behavior is undefined"
326 // Thus it's necessary to do bound checking before converting back and forth.
DoubleIsWithinInt32(GateRef x)327 GateRef CircuitBuilder::DoubleIsWithinInt32(GateRef x)
328 {
329 Label entry(env_);
330 env_->SubCfgEntry(&entry);
331 Label noOverflow(env_);
332 Label noUnderflow(env_);
333 Label isWithinInt32(env_);
334 Label exit(env_);
335 DEFVALUE(result, env_, VariableType::BOOL(), False());
336
337 GateRef limitMax = Double(INT32_MAX);
338 GateRef limitMin = Double(INT32_MIN);
339 Branch(DoubleLessThanOrEqual(x, limitMax), &noOverflow, &exit); // NaN, +inf -> exit
340 Bind(&noOverflow);
341 Branch(DoubleGreaterThanOrEqual(x, limitMin), &noUnderflow, &exit); // NaN, -inf -> exit
342 Bind(&noUnderflow);
343 GateRef xToInt32 = ChangeFloat64ToInt32(x);
344 Branch(DoubleEqual(ChangeInt32ToFloat64(xToInt32), x), &isWithinInt32, &exit);
345 Bind(&isWithinInt32);
346 result.WriteVariable(True());
347 Jump(&exit);
348
349 Bind(&exit);
350 auto ret = *result;
351 env_->SubCfgExit();
352 return ret;
353 }
354
ThreeInt64Min(GateRef first,GateRef second,GateRef third)355 GateRef CircuitBuilder::ThreeInt64Min(GateRef first, GateRef second, GateRef third)
356 {
357 Label entry(env_);
358 env_->SubCfgEntry(&entry);
359 Label exit(env_);
360 DEFVALUE(min, env_, VariableType::INT64(), first);
361 Label useSecond(env_);
362 Label next(env_);
363 Branch(Int64GreaterThan(*min, second), &useSecond, &next);
364 Bind(&useSecond);
365 {
366 min = second;
367 Jump(&next);
368 }
369 Bind(&next);
370 Label useThird(env_);
371 Branch(Int64GreaterThan(*min, third), &useThird, &exit);
372 Bind(&useThird);
373 {
374 min = third;
375 Jump(&exit);
376 }
377 Bind(&exit);
378 auto ret = *min;
379 env_->SubCfgExit();
380 return ret;
381 }
382 }
383