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 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_CIR2(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
DoubleToInt(GateRef x,Label * exit)200 GateRef CircuitBuilder::DoubleToInt(GateRef x, Label *exit)
201 {
202 Label overflow(env_);
203
204 GateRef xInt = ChangeFloat64ToInt32(x);
205 DEFVALUE(result, env_, VariableType::INT32(), xInt);
206
207 GateRef xInt64 = CastDoubleToInt64(x);
208 // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
209 GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
210 exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
211 exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
212 GateRef bits = Int32(base::INT32_BITS - 1);
213 // exp < 32 - 1
214 BRANCH_CIR2(Int32LessThan(exp, bits), exit, &overflow);
215
216 Bind(&overflow);
217 {
218 result = CallNGCRuntime(acc_.GetGlueFromArgList(), RTSTUB_ID(DoubleToInt),
219 Circuit::NullGate(), { x, IntPtr(base::INT32_BITS) }, Circuit::NullGate());
220 Jump(exit);
221 }
222 Bind(exit);
223 auto ret = *result;
224 return ret;
225 }
226
DoubleToInt(GateRef glue,GateRef x,size_t typeBits)227 GateRef CircuitBuilder::DoubleToInt(GateRef glue, GateRef x, size_t typeBits)
228 {
229 Label entry(env_);
230 env_->SubCfgEntry(&entry);
231 Label exit(env_);
232 Label overflow(env_);
233
234 GateRef xInt = ChangeFloat64ToInt32(x);
235 DEFVALUE(result, env_, VariableType::INT32(), xInt);
236
237 if (env_->IsAmd64()) {
238 // 0x80000000: amd64 overflow return value
239 BRANCH_CIR2(Int32Equal(xInt, Int32(0x80000000)), &overflow, &exit);
240 } else {
241 GateRef xInt64 = CastDoubleToInt64(x);
242 // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS
243 GateRef exp = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK));
244 exp = TruncInt64ToInt32(Int64LSR(exp, Int64(base::DOUBLE_SIGNIFICAND_SIZE)));
245 exp = Int32Sub(exp, Int32(base::DOUBLE_EXPONENT_BIAS));
246 GateRef bits = Int32(typeBits - 1);
247 // exp < 32 - 1
248 BRANCH_CIR2(Int32LessThan(exp, bits), &exit, &overflow);
249 }
250 Bind(&overflow);
251 {
252 result = CallNGCRuntime(glue, RTSTUB_ID(DoubleToInt), Circuit::NullGate(), { x, IntPtr(typeBits) },
253 Circuit::NullGate());
254 Jump(&exit);
255 }
256 Bind(&exit);
257 auto ret = *result;
258 env_->SubCfgExit();
259 return ret;
260 }
261
DoubleCheckINFInRangeInt32(GateRef x)262 GateRef CircuitBuilder::DoubleCheckINFInRangeInt32(GateRef x)
263 {
264 Label entry(env_);
265 env_->SubCfgEntry(&entry);
266 Label exit(env_);
267 Label isInfinity(env_);
268 Label positiveInf(env_);
269 Label negativeInf(env_);
270
271 DEFVALUE(result, env_, VariableType::INT32(), DoubleInRangeInt32(x));
272 GateRef Max = Double(INT32_MAX);
273 GateRef Min = Double(INT32_MIN);
274 GateRef pInfinity = Double(base::POSITIVE_INFINITY);
275 Branch(DoubleIsINF(x), &isInfinity, &exit);
276 Bind(&isInfinity);
277 {
278 Branch(DoubleEqual(x, pInfinity), &positiveInf, &negativeInf);
279 Bind(&positiveInf);
280 {
281 result = ChangeFloat64ToInt32(Max);
282 Jump(&exit);
283 }
284 Bind(&negativeInf);
285 {
286 result = ChangeFloat64ToInt32(Min);
287 Jump(&exit);
288 }
289 }
290 Bind(&exit);
291 auto ret = *result;
292 env_->SubCfgExit();
293 return ret;
294 }
295
DoubleInRangeInt32(GateRef x)296 GateRef CircuitBuilder::DoubleInRangeInt32(GateRef x)
297 {
298 Label entry(env_);
299 env_->SubCfgEntry(&entry);
300 Label exit(env_);
301 Label overflow(env_);
302 Label checkUnderflow(env_);
303 Label underflow(env_);
304
305 DEFVALUE(result, env_, VariableType::INT32(), ChangeFloat64ToInt32(x));
306 GateRef Max = Double(INT32_MAX);
307 GateRef Min = Double(INT32_MIN);
308 Branch(DoubleGreaterThan(x, Max), &overflow, &checkUnderflow);
309 Bind(&overflow);
310 {
311 result = ChangeFloat64ToInt32(Max);
312 Jump(&exit);
313 }
314 Bind(&checkUnderflow);
315 {
316 Branch(DoubleLessThan(x, Min), &underflow, &exit);
317 Bind(&underflow);
318 {
319 result = ChangeFloat64ToInt32(Min);
320 Jump(&exit);
321 }
322 }
323 Bind(&exit);
324 auto ret = *result;
325 env_->SubCfgExit();
326 return ret;
327 }
328 }
329