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
22namespace panda::ecmascript::kungfu {
23
24GateRef 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
29MachineType CircuitBuilder::GetMachineTypeFromVariableType(VariableType type)
30{
31    return type.GetMachineType();
32}
33
34GateRef CircuitBuilder::Sqrt(GateRef param)
35{
36    return GetCircuit()->NewGate(circuit_->Sqrt(), MachineType::F64, {param}, GateType::DoubleType());
37}
38
39GateRef CircuitBuilder::AddWithOverflow(GateRef left, GateRef right)
40{
41    return GetCircuit()->NewGate(circuit_->AddWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType());
42}
43
44GateRef CircuitBuilder::SubWithOverflow(GateRef left, GateRef right)
45{
46    return GetCircuit()->NewGate(circuit_->SubWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType());
47}
48
49GateRef CircuitBuilder::MulWithOverflow(GateRef left, GateRef right)
50{
51    return GetCircuit()->NewGate(circuit_->MulWithOverflow(), MachineType::I64, {left, right}, GateType::AnyType());
52}
53
54GateRef 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
61GateRef CircuitBuilder::ReadSp()
62{
63    return circuit_->NewGate(circuit_->ReadSp(), MachineType::I64, GateType::NJSValue());
64}
65
66MachineType 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
94GateRef 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
104GateRef CircuitBuilder::Alloca(size_t size)
105{
106    return GetCircuit()->NewGate(circuit_->Alloca(size), MachineType::ARCH, GateType::NJSValue());
107}
108
109// memory
110void 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
124void 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
135GateRef 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
147GateRef 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
157GateRef 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
168GateRef 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
178GateRef 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
203GateRef 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
230GateRef 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
265GateRef 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
299GateRef 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