• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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