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, value }, type.GetGateType());
118 label->SetDepend(result);
119 }
120
FetchOr(GateRef ptr,GateRef value,MemoryAttribute mAttr)121 GateRef CircuitBuilder::FetchOr(GateRef ptr, GateRef value, MemoryAttribute mAttr)
122 {
123 auto label = GetCurrentLabel();
124 auto depend = label->GetDepend();
125 auto bits = LoadStoreAccessor::ToValue(mAttr);
126 GateRef result = GetCircuit()->NewGate(circuit_->FetchOr(bits),
127 MachineType::I64, { depend, ptr, value }, acc_.GetGateType(value));
128 label->SetDepend(result);
129 return result;
130 }
131
StoreHClass(VariableType type,GateRef glue,GateRef base,GateRef offset,GateRef value,GateRef compValue,MemoryAttribute mAttr)132 void CircuitBuilder::StoreHClass(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value,
133 GateRef compValue, MemoryAttribute mAttr)
134 {
135 auto label = GetCurrentLabel();
136 auto depend = label->GetDepend();
137 if (mAttr.GetBarrier() == MemoryAttribute::Barrier::UNKNOWN_BARRIER && acc_.IsConstant(value)) {
138 mAttr.SetBarrier(MemoryAttribute::Barrier::NO_BARRIER);
139 }
140 auto bit = LoadStoreAccessor::ToValue(mAttr);
141 GateRef result = GetCircuit()->NewGate(circuit_->Store(bit),
142 MachineType::NOVALUE, { depend, glue, base, offset, value, compValue }, type.GetGateType());
143 label->SetDepend(result);
144 }
145
StoreWithoutBarrier(VariableType type,GateRef addr,GateRef value,MemoryAttribute mAttr)146 void CircuitBuilder::StoreWithoutBarrier(VariableType type, GateRef addr, GateRef value, MemoryAttribute mAttr)
147 {
148 auto label = GetCurrentLabel();
149 auto depend = label->GetDepend();
150 auto bit = LoadStoreAccessor::ToValue(mAttr);
151 GateRef result = GetCircuit()->NewGate(circuit_->StoreWithoutBarrier(bit),
152 MachineType::NOVALUE, { depend, addr, value }, type.GetGateType());
153 label->SetDepend(result);
154 }
155
156 // memory
Load(VariableType type,GateRef glue,GateRef base,GateRef offset,MemoryAttribute mAttr)157 GateRef CircuitBuilder::Load(VariableType type, GateRef glue, GateRef base, GateRef offset, MemoryAttribute mAttr)
158 {
159 auto label = GetCurrentLabel();
160 auto depend = label->GetDepend();
161 GateRef val = PtrAdd(base, offset);
162 auto bits = LoadStoreAccessor::ToValue(mAttr);
163 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(),
164 { depend, glue, val }, type.GetGateType());
165 label->SetDepend(result);
166 return result;
167 }
168
Load(VariableType type,GateRef glue,GateRef base,GateRef offset,GateRef depend,MemoryAttribute mAttr)169 GateRef CircuitBuilder::Load(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef depend,
170 MemoryAttribute mAttr)
171 {
172 GateRef val = PtrAdd(base, offset);
173 auto bits = LoadStoreAccessor::ToValue(mAttr);
174 GateRef result = GetCircuit()->NewGate(GetCircuit()->Load(bits), type.GetMachineType(),
175 { depend, glue, val }, type.GetGateType());
176 return result;
177 }
178
LoadWithoutBarrier(VariableType type,GateRef base,GateRef offset,MemoryAttribute mAttr)179 GateRef CircuitBuilder::LoadWithoutBarrier(VariableType type, GateRef base, GateRef offset, MemoryAttribute mAttr)
180 {
181 auto label = GetCurrentLabel();
182 auto depend = label->GetDepend();
183 GateRef val = PtrAdd(base, offset);
184 auto bits = LoadStoreAccessor::ToValue(mAttr);
185 GateRef result = GetCircuit()->NewGate(GetCircuit()->LoadWithoutBarrier(bits), type.GetMachineType(),
186 { depend, val }, type.GetGateType());
187 label->SetDepend(result);
188 return result;
189 }
190
LoadWithoutBarrier(VariableType type,GateRef base,GateRef offset,GateRef depend,MemoryAttribute mAttr)191 GateRef CircuitBuilder::LoadWithoutBarrier(VariableType type, GateRef base, GateRef offset, GateRef depend,
192 MemoryAttribute mAttr)
193 {
194 GateRef val = PtrAdd(base, offset);
195 auto bits = LoadStoreAccessor::ToValue(mAttr);
196 GateRef result = GetCircuit()->NewGate(GetCircuit()->LoadWithoutBarrier(bits), type.GetMachineType(),
197 { depend, val }, type.GetGateType());
198 return result;
199 }
200
LoadFromAddressWithoutBarrier(VariableType type,GateRef addr,MemoryAttribute mAttr)201 GateRef CircuitBuilder::LoadFromAddressWithoutBarrier(VariableType type, GateRef addr, MemoryAttribute mAttr)
202 {
203 auto label = GetCurrentLabel();
204 auto depend = label->GetDepend();
205 auto bits = LoadStoreAccessor::ToValue(mAttr);
206 GateRef result = GetCircuit()->NewGate(GetCircuit()->LoadWithoutBarrier(bits), type.GetMachineType(),
207 { depend, addr }, type.GetGateType());
208 label->SetDepend(result);
209 return result;
210 }
211
NeedSkipReadBarrier(GateRef glue)212 GateRef CircuitBuilder::NeedSkipReadBarrier(GateRef glue)
213 {
214 GateRef gcStateBitField = LoadWithoutBarrier(VariableType::INT64(), glue,
215 IntPtr(JSThread::GlueData::GetSharedGCStateBitFieldOffset(false)));
216 GateRef readBarrierStateBit = Int64And(gcStateBitField, Int64(JSThread::READ_BARRIER_STATE_BITFIELD_MASK));
217 GateRef ret = Int64Equal(readBarrierStateBit, Int64(0));
218 return ret;
219 }
220
DoubleTrunc(GateRef glue,GateRef gate,GateRef value,const char * comment)221 GateRef CircuitBuilder::DoubleTrunc(GateRef glue, GateRef gate, GateRef value, const char* comment)
222 {
223 if (GetCompilationConfig()->IsAArch64()) {
224 return DoubleTrunc(value, comment);
225 }
226
227 return CallNGCRuntime(glue, RTSTUB_ID(FloatTrunc), Gate::InvalidGateRef, {value}, gate, comment);
228 }
229
GetDoubleOfTNumber(GateRef x)230 GateRef CircuitBuilder::GetDoubleOfTNumber(GateRef x)
231 {
232 Label subentry(env_);
233 SubCfgEntry(&subentry);
234 Label isInt(env_);
235 Label isDouble(env_);
236 Label exit(env_);
237 DEFVALUE(result, env_, VariableType::FLOAT64(), Double(0));
238 BRANCH(TaggedIsInt(x), &isInt, &isDouble);
239 Bind(&isInt);
240 {
241 result = ChangeInt32ToFloat64(GetInt32OfTInt(x));
242 Jump(&exit);
243 }
244 Bind(&isDouble);
245 {
246 result = GetDoubleOfTDouble(x);
247 Jump(&exit);
248 }
249 Bind(&exit);
250 GateRef ret = *result;
251 SubCfgExit();
252 return ret;
253 }
254
DoubleToIntOverflowCheck(GateRef x,size_t typeBits)255 GateRef CircuitBuilder::DoubleToIntOverflowCheck(GateRef x, size_t typeBits)
256 {
257 GateRef xInt64 = CastDoubleToInt64(x);
258 // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
259 GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
260 exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
261 exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
262 GateRef bits = Int32(typeBits - 1);
263 // exp < 32 - 1
264 return Int32LessThan(exp, bits);
265 }
266
TruncDoubleToInt(GateRef glue,GateRef x,size_t typeBits)267 GateRef CircuitBuilder::TruncDoubleToInt(GateRef glue, GateRef x, size_t typeBits)
268 {
269 Label entry(env_);
270 env_->SubCfgEntry(&entry);
271 Label exit(env_);
272 Label overflow(env_);
273
274 GateRef xInt = ChangeFloat64ToInt32(x);
275 DEFVALUE(result, env_, VariableType::INT32(), xInt);
276 BRANCH(DoubleToIntOverflowCheck(x, typeBits), &exit, &overflow);
277
278 Bind(&overflow);
279 {
280 result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), Circuit::NullGate(), { x, IntPtr(typeBits) },
281 Circuit::NullGate());
282 Jump(&exit);
283 }
284 Bind(&exit);
285 auto ret = *result;
286 env_->SubCfgExit();
287 return ret;
288 }
289
SaturateTruncDoubleToInt32(GateRef glue,GateRef x)290 GateRef CircuitBuilder::SaturateTruncDoubleToInt32(GateRef glue, GateRef x)
291 {
292 Label entry(env_);
293 env_->SubCfgEntry(&entry);
294 Label exit(env_);
295 Label overflow(env_);
296
297 GateRef xInt = ChangeFloat64ToInt32(x);
298 DEFVALUE(result, env_, VariableType::INT32(), xInt);
299 BRANCH(DoubleToIntOverflowCheck(x, base::INT32_BITS), &exit, &overflow);
300
301 Bind(&overflow);
302 {
303 result = CallNGCRuntime(glue, RTSTUB_ID(SaturateTruncDoubleToInt32), Circuit::NullGate(), { x },
304 Circuit::NullGate());
305 Jump(&exit);
306 }
307 Bind(&exit);
308 auto ret = *result;
309 env_->SubCfgExit();
310 return ret;
311 }
312
DoubleCheckINFInRangeInt32(GateRef x)313 GateRef CircuitBuilder::DoubleCheckINFInRangeInt32(GateRef x)
314 {
315 Label entry(env_);
316 env_->SubCfgEntry(&entry);
317 Label exit(env_);
318 Label isInfinity(env_);
319 Label positiveInf(env_);
320 Label negativeInf(env_);
321
322 DEFVALUE(result, env_, VariableType::INT32(), DoubleInRangeInt32(x));
323 GateRef Max = Double(INT32_MAX);
324 GateRef Min = Double(INT32_MIN);
325 GateRef pInfinity = Double(base::POSITIVE_INFINITY);
326 Branch(DoubleIsINF(x), &isInfinity, &exit);
327 Bind(&isInfinity);
328 {
329 Branch(DoubleEqual(x, pInfinity), &positiveInf, &negativeInf);
330 Bind(&positiveInf);
331 {
332 result = ChangeFloat64ToInt32(Max);
333 Jump(&exit);
334 }
335 Bind(&negativeInf);
336 {
337 result = ChangeFloat64ToInt32(Min);
338 Jump(&exit);
339 }
340 }
341 Bind(&exit);
342 auto ret = *result;
343 env_->SubCfgExit();
344 return ret;
345 }
346
DoubleInRangeInt32(GateRef x)347 GateRef CircuitBuilder::DoubleInRangeInt32(GateRef x)
348 {
349 Label entry(env_);
350 env_->SubCfgEntry(&entry);
351 Label exit(env_);
352 Label overflow(env_);
353 Label checkUnderflow(env_);
354 Label underflow(env_);
355
356 DEFVALUE(result, env_, VariableType::INT32(), ChangeFloat64ToInt32(x));
357 GateRef Max = Double(INT32_MAX);
358 GateRef Min = Double(INT32_MIN);
359 Branch(DoubleGreaterThan(x, Max), &overflow, &checkUnderflow);
360 Bind(&overflow);
361 {
362 result = ChangeFloat64ToInt32(Max);
363 Jump(&exit);
364 }
365 Bind(&checkUnderflow);
366 {
367 Branch(DoubleLessThan(x, Min), &underflow, &exit);
368 Bind(&underflow);
369 {
370 result = ChangeFloat64ToInt32(Min);
371 Jump(&exit);
372 }
373 }
374 Bind(&exit);
375 auto ret = *result;
376 env_->SubCfgExit();
377 return ret;
378 }
379
380 // According to C++ standard: "If the truncated value cannot fit into the destination type, the behavior is undefined"
381 // Thus it's necessary to do bound checking before converting back and forth.
DoubleIsWithinInt32(GateRef x)382 GateRef CircuitBuilder::DoubleIsWithinInt32(GateRef x)
383 {
384 Label entry(env_);
385 env_->SubCfgEntry(&entry);
386 Label noOverflow(env_);
387 Label noUnderflow(env_);
388 Label isWithinInt32(env_);
389 Label exit(env_);
390 DEFVALUE(result, env_, VariableType::BOOL(), False());
391
392 GateRef limitMax = Double(INT32_MAX);
393 GateRef limitMin = Double(INT32_MIN);
394 Branch(DoubleLessThanOrEqual(x, limitMax), &noOverflow, &exit); // NaN, +inf -> exit
395 Bind(&noOverflow);
396 Branch(DoubleGreaterThanOrEqual(x, limitMin), &noUnderflow, &exit); // NaN, -inf -> exit
397 Bind(&noUnderflow);
398 GateRef xToInt32 = ChangeFloat64ToInt32(x);
399 Branch(DoubleEqual(ChangeInt32ToFloat64(xToInt32), x), &isWithinInt32, &exit);
400 Bind(&isWithinInt32);
401 result.WriteVariable(True());
402 Jump(&exit);
403
404 Bind(&exit);
405 auto ret = *result;
406 env_->SubCfgExit();
407 return ret;
408 }
409
ThreeInt64Min(GateRef first,GateRef second,GateRef third)410 GateRef CircuitBuilder::ThreeInt64Min(GateRef first, GateRef second, GateRef third)
411 {
412 Label entry(env_);
413 env_->SubCfgEntry(&entry);
414 Label exit(env_);
415 DEFVALUE(min, env_, VariableType::INT64(), first);
416 Label useSecond(env_);
417 Label next(env_);
418 Branch(Int64GreaterThan(*min, second), &useSecond, &next);
419 Bind(&useSecond);
420 {
421 min = second;
422 Jump(&next);
423 }
424 Bind(&next);
425 Label useThird(env_);
426 Branch(Int64GreaterThan(*min, third), &useThird, &exit);
427 Bind(&useThird);
428 {
429 min = third;
430 Jump(&exit);
431 }
432 Bind(&exit);
433 auto ret = *min;
434 env_->SubCfgExit();
435 return ret;
436 }
437 }
438