• 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 }, 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