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