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