1/*
2 * Copyright (c) 2022 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/share_gate_meta_data.h"
17#include "ecmascript/compiler/number_gate_info.h"
18#include "ecmascript/compiler/type.h"
19#include "ecmascript/compiler/typed_hcr_lowering.h"
20#include "ecmascript/compiler/builtins_lowering.h"
21#include "ecmascript/compiler/new_object_stub_builder.h"
22#include "ecmascript/compiler/number_speculative_lowering.h"
23#include "ecmascript/deoptimizer/deoptimizer.h"
24#include "ecmascript/js_arraybuffer.h"
25#include "ecmascript/js_locale.h"
26#include "ecmascript/js_native_pointer.h"
27#include "ecmascript/js_object.h"
28
29namespace panda::ecmascript::kungfu {
30
31void NumberSpeculativeLowering::Run()
32{
33    std::vector<GateRef> gateList;
34    acc_.GetAllGates(gateList);
35    for (auto gate : gateList) {
36        auto op = acc_.GetOpCode(gate);
37        switch (op) {
38            case OpCode::RANGE_GUARD: {
39                rangeGuardGates_.push_back(gate);
40                break;
41            }
42            default: {
43                VisitGate(gate);
44            }
45        }
46    }
47    for (auto rangeGuard : rangeGuardGates_) {
48        VisitRangeGuard(rangeGuard);
49    }
50}
51
52void NumberSpeculativeLowering::VisitGate(GateRef gate)
53{
54    OpCode op = acc_.GetOpCode(gate);
55    switch (op) {
56        case OpCode::TYPED_BINARY_OP: {
57            VisitTypedBinaryOp(gate);
58            break;
59        }
60        case OpCode::TYPED_UNARY_OP: {
61            VisitTypedUnaryOp(gate);
62            break;
63        }
64        case OpCode::TYPED_CONDITION_JUMP: {
65            VisitTypedConditionJump(gate);
66            break;
67        }
68        case OpCode::VALUE_SELECTOR: {
69            VisitPhi(gate);
70            break;
71        }
72        case OpCode::CONSTANT: {
73            VisitConstant(gate);
74            break;
75        }
76        case OpCode::LOAD_ELEMENT: {
77            VisitLoadElement(gate);
78            break;
79        }
80        case OpCode::INDEX_CHECK: {
81            VisitIndexCheck(gate);
82            break;
83        }
84        case OpCode::RANGE_CHECK_PREDICATE: {
85            VisitRangeCheckPredicate(gate);
86            break;
87        }
88        case OpCode::LOAD_ARRAY_LENGTH:
89        case OpCode::LOAD_TYPED_ARRAY_LENGTH: {
90            VisitLoadArrayLength(gate);
91            break;
92        }
93        case OpCode::LOAD_STRING_LENGTH: {
94            VisitLoadStringLength(gate);
95            break;
96        }
97        case OpCode::LOAD_MAP_SIZE: {
98            VisitLoadMapSize(gate);
99            break;
100        }
101        case OpCode::LOAD_PROPERTY: {
102            VisitLoadProperty(gate);
103            break;
104        }
105        case OpCode::MONO_LOAD_PROPERTY_ON_PROTO: {
106            VisitLoadPropertyOnProto(gate);
107            break;
108        }
109        case OpCode::MATH_ROUND: {
110            VisitRound(gate);
111            break;
112        }
113        default:
114            break;
115    }
116}
117
118void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate)
119{
120    Environment env(gate, circuit_, &builder_);
121    if (acc_.HasStringType(gate)) {
122        VisitStringBinaryOp(gate);
123        return;
124    }
125    auto op = acc_.GetTypedBinaryOp(gate);
126    switch (op) {
127        case TypedBinOp::TYPED_STRICTEQ:
128        case TypedBinOp::TYPED_STRICTNOTEQ: {
129            VisitStrictEqualOrStrictNotEqual(gate);
130            break;
131        }
132        case TypedBinOp::TYPED_EQ:
133        case TypedBinOp::TYPED_NOTEQ: {
134            VisitEqualOrNotEqual(gate);
135            break;
136        }
137        default: {
138            if (acc_.HasNumberType(gate)) {
139                VisitNumberBinaryOp(gate);
140            }
141            break;
142        }
143    }
144}
145
146void NumberSpeculativeLowering::VisitEqualOrNotEqual(GateRef gate)
147{
148    if (acc_.HasNumberType(gate)) {
149        VisitNumberBinaryOp(gate);
150    } else {
151        VisitUndefinedEqOrUndefinedNotEq(gate);
152    }
153}
154
155void NumberSpeculativeLowering::VisitStrictEqualOrStrictNotEqual(GateRef gate)
156{
157    if (acc_.HasNumberType(gate)) {
158        VisitNumberBinaryOp(gate);
159    } else {
160        VisitUndefinedStrictEqOrUndefinedStrictNotEq(gate);
161    }
162}
163
164void NumberSpeculativeLowering::VisitNumberBinaryOp(GateRef gate)
165{
166    TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
167    switch (Op) {
168        case TypedBinOp::TYPED_ADD: {
169            VisitNumberCalculate<TypedBinOp::TYPED_ADD>(gate);
170            break;
171        }
172        case TypedBinOp::TYPED_SUB: {
173            VisitNumberCalculate<TypedBinOp::TYPED_SUB>(gate);
174            break;
175        }
176        case TypedBinOp::TYPED_MUL: {
177            VisitNumberCalculate<TypedBinOp::TYPED_MUL>(gate);
178            break;
179        }
180        case TypedBinOp::TYPED_LESS: {
181            VisitNumberCompare<TypedBinOp::TYPED_LESS>(gate);
182            break;
183        }
184        case TypedBinOp::TYPED_LESSEQ: {
185            VisitNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate);
186            break;
187        }
188        case TypedBinOp::TYPED_GREATER: {
189            VisitNumberCompare<TypedBinOp::TYPED_GREATER>(gate);
190            break;
191        }
192        case TypedBinOp::TYPED_GREATEREQ: {
193            VisitNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate);
194            break;
195        }
196        case TypedBinOp::TYPED_EQ: {
197            VisitNumberCompare<TypedBinOp::TYPED_EQ>(gate);
198            break;
199        }
200        case TypedBinOp::TYPED_NOTEQ: {
201            VisitNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate);
202            break;
203        }
204        case TypedBinOp::TYPED_STRICTEQ: {
205            VisitNumberCompare<TypedBinOp::TYPED_STRICTEQ>(gate);
206            break;
207        }
208        case TypedBinOp::TYPED_STRICTNOTEQ: {
209            VisitNumberCompare<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
210            break;
211        }
212        case TypedBinOp::TYPED_SHL: {
213            VisitNumberShift<TypedBinOp::TYPED_SHL>(gate);
214            break;
215        }
216        case TypedBinOp::TYPED_SHR: {
217            VisitNumberShift<TypedBinOp::TYPED_SHR>(gate);
218            break;
219        }
220        case TypedBinOp::TYPED_ASHR: {
221            VisitNumberShift<TypedBinOp::TYPED_ASHR>(gate);
222            break;
223        }
224        case TypedBinOp::TYPED_AND: {
225            VisitNumberLogical<TypedBinOp::TYPED_AND>(gate);
226            break;
227        }
228        case TypedBinOp::TYPED_OR: {
229            VisitNumberLogical<TypedBinOp::TYPED_OR>(gate);
230            break;
231        }
232        case TypedBinOp::TYPED_XOR: {
233            VisitNumberLogical<TypedBinOp::TYPED_XOR>(gate);
234            break;
235        }
236        case TypedBinOp::TYPED_DIV: {
237            VisitNumberDiv(gate);
238            break;
239        }
240        case TypedBinOp::TYPED_MOD: {
241            VisitNumberMod<TypedBinOp::TYPED_MOD>(gate);
242            break;
243        }
244        default:
245            break;
246    }
247}
248
249void NumberSpeculativeLowering::VisitTypedUnaryOp(GateRef gate)
250{
251    Environment env(gate, circuit_, &builder_);
252    TypedUnOp Op = acc_.GetTypedUnAccessor(gate).GetTypedUnOp();
253    switch (Op) {
254        case TypedUnOp::TYPED_INC: {
255            VisitNumberMonocular<TypedUnOp::TYPED_INC>(gate);
256            return;
257        }
258        case TypedUnOp::TYPED_DEC: {
259            VisitNumberMonocular<TypedUnOp::TYPED_DEC>(gate);
260            return;
261        }
262        case TypedUnOp::TYPED_NEG: {
263            VisitNumberMonocular<TypedUnOp::TYPED_NEG>(gate);
264            return;
265        }
266        case TypedUnOp::TYPED_ISFALSE: {
267            VisitIsTrueOrFalse(gate, false);
268            return;
269        }
270        case TypedUnOp::TYPED_ISTRUE: {
271            VisitIsTrueOrFalse(gate, true);
272            return;
273        }
274        case TypedUnOp::TYPED_NOT: {
275            VisitNumberNot(gate);
276            return;
277        }
278        default:
279            break;
280    }
281}
282
283void NumberSpeculativeLowering::VisitTypedConditionJump(GateRef gate)
284{
285    Environment env(gate, circuit_, &builder_);
286    ParamType type = acc_.GetTypedJumpAccessor(gate).GetParamType();
287    if (type.IsBooleanType()) {
288        VisitBooleanJump(gate);
289    } else {
290        UNREACHABLE();
291    }
292}
293
294template<TypedBinOp Op>
295void NumberSpeculativeLowering::VisitNumberCalculate(GateRef gate)
296{
297    GateRef left = acc_.GetValueIn(gate, 0);
298    GateRef right = acc_.GetValueIn(gate, 1);
299    TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
300    const ParamType paramType = accessor.GetParamType();
301    ASSERT(paramType.HasNumberType());
302    GateRef result = Circuit::NullGate();
303    if (paramType.IsIntType()) {
304        result = CalculateInts<Op>(left, right);    // int op int
305        UpdateRange(result, GetRange(gate));
306        acc_.SetMachineType(gate, MachineType::I32);
307    } else {
308        result = CalculateDoubles<Op>(left, right); // float op float
309        acc_.SetMachineType(gate, MachineType::F64);
310    }
311    acc_.SetGateType(gate, GateType::NJSValue());
312    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
313}
314
315template<TypedBinOp Op>
316void NumberSpeculativeLowering::VisitNumberCompare(GateRef gate)
317{
318    GateRef left = acc_.GetValueIn(gate, 0);
319    GateRef right = acc_.GetValueIn(gate, 1);
320    TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
321    const ParamType paramType = accessor.GetParamType();
322    ASSERT(paramType.HasNumberType());
323    GateRef result = Circuit::NullGate();
324    if (paramType.IsIntType()) {
325        result = CompareInts<Op>(left, right);  // int op int
326    } else {
327        result = CompareDoubles<Op>(left, right);   // float op float
328    }
329    acc_.SetMachineType(gate, MachineType::I1);
330    acc_.SetGateType(gate, GateType::NJSValue());
331    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
332}
333
334template<TypedBinOp Op>
335void NumberSpeculativeLowering::VisitNumberShift(GateRef gate)
336{
337    GateRef left = acc_.GetValueIn(gate, 0);
338    GateRef right = acc_.GetValueIn(gate, 1);
339    GateRef result = ShiftInts<Op>(left, right);  // int op int
340    UpdateRange(result, GetRange(gate));
341    acc_.SetMachineType(gate, MachineType::I32);
342    acc_.SetGateType(gate, GateType::NJSValue());
343    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
344}
345
346template<TypedBinOp Op>
347void NumberSpeculativeLowering::VisitNumberLogical(GateRef gate)
348{
349    GateRef left = acc_.GetValueIn(gate, 0);
350    GateRef right = acc_.GetValueIn(gate, 1);
351    GateRef result = LogicalInts<Op>(left, right);  // int op int
352    UpdateRange(result, GetRange(gate));
353    acc_.SetMachineType(gate, MachineType::I32);
354    acc_.SetGateType(gate, GateType::NJSValue());
355    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
356}
357
358void NumberSpeculativeLowering::VisitNumberDiv(GateRef gate)
359{
360    GateRef left = acc_.GetValueIn(gate, 0);
361    GateRef right = acc_.GetValueIn(gate, 1);
362    TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
363    const ParamType paramType = accessor.GetParamType();
364    ASSERT(paramType.HasNumberType());
365    GateRef result = Circuit::NullGate();
366    if (paramType.IsIntType()) {
367        result = builder_.Int32DivWithCheck(left, right);
368        acc_.SetMachineType(gate, MachineType::I32);
369    } else {
370        result = builder_.BinaryArithmetic(circuit_->Fdiv(),
371            MachineType::F64, left, right, GateType::NJSValue());
372        acc_.SetMachineType(gate, MachineType::F64);
373    }
374    acc_.SetGateType(gate, GateType::NJSValue());
375    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
376}
377
378template<TypedBinOp Op>
379void NumberSpeculativeLowering::VisitNumberMod(GateRef gate)
380{
381    GateRef left = acc_.GetValueIn(gate, 0);
382    GateRef right = acc_.GetValueIn(gate, 1);
383    TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
384    const ParamType paramType = accessor.GetParamType();
385    ASSERT(paramType.HasNumberType());
386    GateRef result = Circuit::NullGate();
387    if (paramType.IsIntType()) {
388        if (GetRange(right).MaybeZero()) {
389            builder_.Int32CheckRightIsZero(right);
390        }
391        bool isNegativeZero = (GetRange(left) % GetRange(right)).MaybeZero() && GetRange(left).MaybeNegative();
392        if (isNegativeZero) {
393            builder_.RemainderIsNegativeZero(left, right);
394        }
395        result = CalculateInts<Op>(left, right);
396        UpdateRange(result, GetRange(gate));
397        acc_.SetMachineType(gate, MachineType::I32);
398    } else {
399        GateRef glue = acc_.GetGlueFromArgList();
400        result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
401            Gate::InvalidGateRef, {left, right}, Circuit::NullGate());
402        acc_.SetMachineType(gate, MachineType::F64);
403    }
404    acc_.SetGateType(gate, GateType::NJSValue());
405    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
406}
407
408template<TypedUnOp Op>
409void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate)
410{
411    TypedUnaryAccessor accessor(acc_.TryGetValue(gate));
412    ParamType type = accessor.GetParamType();
413    ASSERT(type.HasNumberType());
414    GateRef value = acc_.GetValueIn(gate, 0);
415    GateRef result = Circuit::NullGate();
416    if (type.IsIntType()) {
417        if (Op == TypedUnOp::TYPED_NEG) {
418            builder_.ValueCheckNegOverflow(value);
419        }
420        result = MonocularInt<Op>(value);
421        UpdateRange(result, GetRange(gate));
422        acc_.SetMachineType(gate, MachineType::I32);
423    } else {
424        result = MonocularDouble<Op>(value);
425        acc_.SetMachineType(gate, MachineType::F64);
426    }
427    acc_.SetGateType(gate, GateType::NJSValue());
428    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
429}
430
431void NumberSpeculativeLowering::VisitNumberNot(GateRef gate)
432{
433    ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetParamType().HasNumberType());
434    GateRef value = acc_.GetValueIn(gate, 0);
435    GateRef result = builder_.Int32Not(value);
436    UpdateRange(result, GetRange(gate));
437    acc_.SetMachineType(gate, MachineType::I32);
438    acc_.SetGateType(gate, GateType::NJSValue());
439    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
440}
441
442void NumberSpeculativeLowering::VisitIsTrueOrFalse(GateRef gate, bool flag)
443{
444    GateRef value = acc_.GetValueIn(gate, 0);
445    GateRef result = Circuit::NullGate();
446    if (!flag) {
447        result = builder_.BoolNot(value);
448    } else {
449        result = value;
450    }
451    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
452}
453
454void NumberSpeculativeLowering::VisitBooleanJump(GateRef gate)
455{
456    TypedJumpAccessor jumpAcc = acc_.GetTypedJumpAccessor(gate);
457    TypedJumpOp jumpOp = jumpAcc.GetTypedJumpOp();
458    ASSERT((jumpOp == TypedJumpOp::TYPED_JEQZ) || (jumpOp == TypedJumpOp::TYPED_JNEZ));
459    GateRef condition = acc_.GetValueIn(gate, 0);
460    uint32_t trueWeight = jumpAcc.GetTrueWeight();
461    uint32_t falseWeight = jumpAcc.GetFalseWeight();
462    if (jumpOp == TypedJumpOp::TYPED_JEQZ) {
463        std::swap(trueWeight, falseWeight);
464        condition = builder_.BoolNot(condition);
465    }
466    GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition, trueWeight, falseWeight, "booleanJump");
467    acc_.ReplaceGate(gate, ifBranch, acc_.GetDep(gate), Circuit::NullGate());
468}
469
470void NumberSpeculativeLowering::VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)
471{
472    ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ ||
473           acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ);
474    GateRef left = acc_.GetValueIn(gate, 0);
475    GateRef right = acc_.GetValueIn(gate, 1);
476    ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
477    GateRef result = Circuit::NullGate();
478    if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) {
479        result = builder_.Equal(left, right);
480    } else {
481        result = builder_.NotEqual(left, right);
482    }
483    ASSERT(result != Circuit::NullGate());
484    acc_.SetMachineType(gate, MachineType::I1);
485    acc_.SetGateType(gate, GateType::NJSValue());
486    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
487}
488
489void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate)
490{
491    ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ ||
492           acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ);
493    GateRef left = acc_.GetValueIn(gate, 0);
494    GateRef right = acc_.GetValueIn(gate, 1);
495    ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
496    GateRef valueGate =  acc_.IsUndefinedOrNullOrHole(left) ? right : left;
497    GateRef result = Circuit::NullGate();
498    if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) {
499        result = builder_.TaggedIsUndefinedOrNullOrHole(valueGate);
500    } else {
501        result = builder_.TaggedIsNotUndefinedAndNullAndHole(valueGate);
502    }
503    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
504}
505
506void NumberSpeculativeLowering::VisitConstant(GateRef gate)
507{
508    TypeInfo output = GetOutputType(gate);
509    switch (output) {
510        case TypeInfo::INT32: {
511            int value = acc_.GetInt32FromConstant(gate);
512            GateRef constGate = GetConstInt32(value);
513            acc_.UpdateAllUses(gate, constGate);
514            break;
515        }
516        case TypeInfo::FLOAT64: {
517            double value = acc_.GetFloat64FromConstant(gate);
518            acc_.UpdateAllUses(gate, builder_.Double(value));
519            break;
520        }
521        default:
522            break;
523    }
524}
525
526void NumberSpeculativeLowering::VisitPhi(GateRef gate)
527{
528    TypeInfo output = GetOutputType(gate);
529    switch (output) {
530        case TypeInfo::INT1: {
531            acc_.SetGateType(gate, GateType::NJSValue());
532            acc_.SetMachineType(gate, MachineType::I1);
533            break;
534        }
535        case TypeInfo::INT32:
536        case TypeInfo::UINT32: {
537            acc_.SetGateType(gate, GateType::NJSValue());
538            acc_.SetMachineType(gate, MachineType::I32);
539            break;
540        }
541        case TypeInfo::FLOAT64: {
542            acc_.SetGateType(gate, GateType::NJSValue());
543            acc_.SetMachineType(gate, MachineType::F64);
544            break;
545        }
546        case TypeInfo::CHAR: {
547            acc_.SetGateType(gate, GateType::NJSValue());
548            acc_.SetMachineType(gate, MachineType::I32);
549            break;
550        }
551        default:
552            break;
553    }
554}
555
556void NumberSpeculativeLowering::VisitRangeCheckPredicate(GateRef gate)
557{
558    acc_.SetGateType(gate, GateType::NJSValue());
559    acc_.SetMachineType(gate, MachineType::I32);
560}
561
562void NumberSpeculativeLowering::VisitIndexCheck(GateRef gate)
563{
564    acc_.SetGateType(gate, GateType::NJSValue());
565    acc_.SetMachineType(gate, MachineType::I32);
566}
567
568void NumberSpeculativeLowering::VisitLoadArrayLength(GateRef gate)
569{
570    acc_.SetGateType(gate, GateType::NJSValue());
571    acc_.SetMachineType(gate, MachineType::I32);
572}
573
574void NumberSpeculativeLowering::VisitLoadStringLength(GateRef gate)
575{
576    acc_.SetGateType(gate, GateType::NJSValue());
577    acc_.SetMachineType(gate, MachineType::I32);
578}
579
580void NumberSpeculativeLowering::VisitLoadMapSize(GateRef gate)
581{
582    acc_.SetGateType(gate, GateType::NJSValue());
583    acc_.SetMachineType(gate, MachineType::I32);
584}
585
586void NumberSpeculativeLowering::VisitLoadElement(GateRef gate)
587{
588    auto op = acc_.GetTypedLoadOp(gate);
589    switch (op) {
590        case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT:
591        case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT:
592        case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT:
593        case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT:
594        case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT:
595        case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT:
596        case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT:
597            acc_.SetMachineType(gate, MachineType::I32);
598            acc_.SetGateType(gate, GateType::NJSValue());
599            break;
600        case TypedLoadOp::ARRAY_LOAD_HOLE_INT_ELEMENT:
601        case TypedLoadOp::ARRAY_LOAD_HOLE_DOUBLE_ELEMENT:
602            acc_.SetMachineType(gate, MachineType::I64);
603            acc_.SetGateType(gate, GateType::NJSValue());
604            break;
605        case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
606        case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT:
607            acc_.SetMachineType(gate, MachineType::F64);
608            acc_.SetGateType(gate, GateType::NJSValue());
609            break;
610        default:
611            break;
612    }
613}
614
615void NumberSpeculativeLowering::VisitLoadProperty(GateRef gate)
616{
617    TypeInfo output = GetOutputType(gate);
618    if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
619        Environment env(gate, circuit_, &builder_);
620        ASSERT(acc_.GetNumValueIn(gate) == 2);  // 2: receiver, plr
621        GateRef receiver = acc_.GetValueIn(gate, 0);
622        GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
623        PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
624        ASSERT(plr.IsLocal() || plr.IsFunction());
625
626        // Hole check?
627        GateRef result = Circuit::NullGate();
628        if (output == TypeInfo::FLOAT64) {
629            if (plr.IsInlinedProps()) {
630                result = builder_.LoadConstOffset(VariableType::FLOAT64(), receiver, plr.GetOffset());
631            } else {
632                auto properties =
633                    builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
634                result = builder_.GetValueFromTaggedArray(
635                    VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
636            }
637            acc_.SetMachineType(gate, MachineType::F64);
638        } else {
639            if (plr.IsInlinedProps()) {
640                result = builder_.LoadConstOffset(VariableType::INT32(), receiver, plr.GetOffset());
641            } else {
642                auto properties =
643                    builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
644                result = builder_.GetValueFromTaggedArray(
645                    VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
646            }
647            acc_.SetMachineType(gate, MachineType::I32);
648        }
649        acc_.SetGateType(gate, GateType::NJSValue());
650        acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
651    }
652}
653
654void NumberSpeculativeLowering::VisitRangeGuard(GateRef gate)
655{
656    Environment env(gate, circuit_, &builder_);
657    GateRef inputLength = acc_.GetValueIn(gate, 0);
658    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), inputLength);
659}
660
661template<TypedBinOp Op>
662GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right)
663{
664    GateRef res = Circuit::NullGate();
665    RangeInfo leftRange = GetRange(left);
666    RangeInfo rightRange = GetRange(right);
667    switch (Op) {
668        case TypedBinOp::TYPED_ADD: {
669            if (!leftRange.MaybeAddOverflowOrUnderflow(rightRange)) {
670                return builder_.Int32Add(left, right, GateType::NJSValue());
671            }
672            res = builder_.AddWithOverflow(left, right);
673            break;
674        }
675        case TypedBinOp::TYPED_SUB: {
676            if (!leftRange.MaybeSubOverflowOrUnderflow(rightRange)) {
677                return builder_.Int32Sub(left, right, GateType::NJSValue());
678            }
679            res = builder_.SubWithOverflow(left, right);
680            break;
681        }
682        case TypedBinOp::TYPED_MUL:
683            if (!leftRange.MaybeMulOverflowOrUnderflow(rightRange)) {
684                return builder_.Int32Mul(left, right);
685            }
686            res = builder_.MulWithOverflow(left, right);
687            break;
688        case TypedBinOp::TYPED_MOD: {
689            return builder_.BinaryArithmetic(circuit_->Smod(),
690                MachineType::I32, left, right, GateType::NJSValue());
691            break;
692        }
693        default:
694            break;
695    }
696    // DeoptCheckForOverFlow
697    builder_.OverflowCheck(res);
698    return builder_.ExtractValue(MachineType::I32, res, GetConstInt32(0));
699}
700
701template<TypedBinOp Op>
702GateRef NumberSpeculativeLowering::CalculateDoubles(GateRef left, GateRef right)
703{
704    GateRef res = Circuit::NullGate();
705    switch (Op) {
706        case TypedBinOp::TYPED_ADD:
707            res = builder_.DoubleAdd(left, right, GateType::NJSValue());
708            break;
709        case TypedBinOp::TYPED_SUB:
710            res = builder_.DoubleSub(left, right, GateType::NJSValue());
711            break;
712        case TypedBinOp::TYPED_MUL:
713            res = builder_.DoubleMul(left, right, GateType::NJSValue());
714            break;
715        default:
716            break;
717    }
718    return res;
719}
720
721template<TypedBinOp Op>
722GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right)
723{
724    GateRef condition = Circuit::NullGate();
725    switch (Op) {
726        case TypedBinOp::TYPED_LESS:
727            condition = builder_.Int32LessThan(left, right);
728            break;
729        case TypedBinOp::TYPED_LESSEQ:
730            condition = builder_.Int32LessThanOrEqual(left, right);
731            break;
732        case TypedBinOp::TYPED_GREATER:
733            condition = builder_.Int32GreaterThan(left, right);
734            break;
735        case TypedBinOp::TYPED_GREATEREQ:
736            condition = builder_.Int32GreaterThanOrEqual(left, right);
737            break;
738        case TypedBinOp::TYPED_EQ:
739        case TypedBinOp::TYPED_STRICTEQ:
740            condition = builder_.Int32Equal(left, right);
741            break;
742        case TypedBinOp::TYPED_NOTEQ:
743        case TypedBinOp::TYPED_STRICTNOTEQ:
744            condition = builder_.Int32NotEqual(left, right);
745            break;
746        default:
747            break;
748    }
749    return condition;
750}
751
752template<TypedBinOp Op>
753GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right)
754{
755    GateRef condition = Circuit::NullGate();
756    switch (Op) {
757        case TypedBinOp::TYPED_LESS:
758            condition = builder_.DoubleLessThan(left, right);
759            break;
760        case TypedBinOp::TYPED_LESSEQ:
761            condition = builder_.DoubleLessThanOrEqual(left, right);
762            break;
763        case TypedBinOp::TYPED_GREATER:
764            condition = builder_.DoubleGreaterThan(left, right);
765            break;
766        case TypedBinOp::TYPED_GREATEREQ:
767            condition = builder_.DoubleGreaterThanOrEqual(left, right);
768            break;
769        case TypedBinOp::TYPED_EQ:
770        case TypedBinOp::TYPED_STRICTEQ: {
771            condition = LogicAndBuilder(builder_.GetCurrentEnvironment())
772                .And(builder_.BoolNot(builder_.DoubleIsNAN(left)))
773                .And(builder_.BoolNot(builder_.DoubleIsNAN(right)))
774                .And(builder_.DoubleEqual(left, right))
775                .Done();
776            break;
777        }
778        case TypedBinOp::TYPED_NOTEQ:
779        case TypedBinOp::TYPED_STRICTNOTEQ: {
780            condition = LogicOrBuilder(builder_.GetCurrentEnvironment())
781                .Or(builder_.DoubleIsNAN(left))
782                .Or(builder_.DoubleIsNAN(right))
783                .Or(builder_.DoubleNotEqual(left, right))
784                .Done();
785            break;
786        }
787        default:
788            break;
789    }
790    return condition;
791}
792
793template<TypedBinOp Op>
794GateRef NumberSpeculativeLowering::ShiftInts(GateRef left, GateRef right)
795{
796    GateRef value = Circuit::NullGate();
797    GateRef bitmask = GetConstInt32(0x1f); // 0x1f: bit mask of shift value
798    GateRef shift = builder_.Int32And(right, bitmask, GateType::NJSValue());
799    switch (Op) {
800        case TypedBinOp::TYPED_SHL: {
801            value = builder_.Int32LSL(left, shift, GateType::NJSValue());
802            break;
803        }
804        case TypedBinOp::TYPED_SHR: {
805            value = builder_.Int32LSR(left, shift, GateType::NJSValue());
806            RangeInfo leftRange = GetRange(left);
807            RangeInfo rightRange = GetRange(right);
808            if (!leftRange.MaybeShrOverflow(rightRange)) {
809                return value;
810            }
811            builder_.Int32UnsignedUpperBoundCheck(value, builder_.Int32(INT32_MAX));
812            break;
813        }
814        case TypedBinOp::TYPED_ASHR: {
815            value = builder_.Int32ASR(left, shift, GateType::NJSValue());
816            break;
817        }
818        default:
819            LOG_ECMA(FATAL) << "this branch is unreachable";
820            UNREACHABLE();
821            break;
822    }
823    return value;
824}
825
826template<TypedBinOp Op>
827GateRef NumberSpeculativeLowering::LogicalInts(GateRef left, GateRef right)
828{
829    GateRef value = Circuit::NullGate();
830    switch (Op) {
831        case TypedBinOp::TYPED_AND: {
832            value = builder_.Int32And(left, right, GateType::NJSValue());
833            break;
834        }
835        case TypedBinOp::TYPED_OR: {
836            value = builder_.Int32Or(left, right, GateType::NJSValue());
837            break;
838        }
839        case TypedBinOp::TYPED_XOR: {
840            value = builder_.Int32Xor(left, right, GateType::NJSValue());
841            break;
842        }
843        default:
844            LOG_ECMA(FATAL) << "this branch is unreachable";
845            UNREACHABLE();
846            break;
847    }
848    return value;
849}
850
851template<TypedUnOp Op>
852GateRef NumberSpeculativeLowering::MonocularInt(GateRef value)
853{
854    GateRef res = Circuit::NullGate();
855    switch (Op) {
856        case TypedUnOp::TYPED_INC:
857            res = CalculateInts<TypedBinOp::TYPED_ADD>(value, GetConstInt32(1));
858            break;
859        case TypedUnOp::TYPED_DEC:
860            res = CalculateInts<TypedBinOp::TYPED_SUB>(value, GetConstInt32(1));
861            break;
862        case TypedUnOp::TYPED_NEG:
863            res = builder_.Int32Sub(GetConstInt32(0), value, GateType::NJSValue());
864            break;
865        default:
866            break;
867    }
868    return res;
869}
870
871template<TypedUnOp Op>
872GateRef NumberSpeculativeLowering::MonocularDouble(GateRef value)
873{
874    GateRef res = Circuit::NullGate();
875    switch (Op) {
876        case TypedUnOp::TYPED_INC:
877            res = CalculateDoubles<TypedBinOp::TYPED_ADD>(value, GetConstDouble(1));
878            break;
879        case TypedUnOp::TYPED_DEC:
880            res = CalculateDoubles<TypedBinOp::TYPED_SUB>(value, GetConstDouble(1));
881            break;
882        case TypedUnOp::TYPED_NEG:
883            res = CalculateDoubles<TypedBinOp::TYPED_MUL>(value, GetConstDouble(-1));
884            break;
885        default:
886            break;
887    }
888    return res;
889}
890
891void NumberSpeculativeLowering::UpdateRange(GateRef gate, const RangeInfo& range)
892{
893    auto id = acc_.GetId(gate);
894    if (id >= rangeInfos_.size()) {
895        rangeInfos_.resize(id + 1, RangeInfo::ANY());
896    }
897    rangeInfos_[id] = range;
898}
899
900RangeInfo NumberSpeculativeLowering::GetRange(GateRef gate) const
901{
902    auto id = acc_.GetId(gate);
903    if (id >= rangeInfos_.size()) {
904        rangeInfos_.resize(id + 1, RangeInfo::ANY());
905    }
906    ASSERT(!rangeInfos_[id].IsNone());
907    return rangeInfos_[id];
908}
909
910GateRef NumberSpeculativeLowering::GetConstInt32(int32_t v)
911{
912    auto val = builder_.Int32(v);
913    UpdateRange(val, RangeInfo(v, v));
914    return val;
915}
916
917GateRef NumberSpeculativeLowering::GetConstDouble(double v)
918{
919    auto val = builder_.Double(v);
920    UpdateRange(val, RangeInfo(v, v));
921    return val;
922}
923
924void NumberSpeculativeLowering::VisitStringBinaryOp(GateRef gate)
925{
926    TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
927    switch (Op) {
928        case TypedBinOp::TYPED_EQ: {
929            VisitStringCompare<TypedBinOp::TYPED_EQ>(gate);
930            break;
931        }
932        case TypedBinOp::TYPED_ADD: {
933            VisitStringAdd<TypedBinOp::TYPED_ADD>(gate);
934            break;
935        }
936        default:
937            LOG_COMPILER(FATAL) << "this branch is unreachable";
938            UNREACHABLE();
939    }
940}
941
942template<TypedBinOp Op>
943void NumberSpeculativeLowering::VisitStringCompare(GateRef gate)
944{
945    GateRef left = acc_.GetValueIn(gate, 0);
946    GateRef right = acc_.GetValueIn(gate, 1);
947
948    GateRef result;
949    ASSERT(Op == TypedBinOp::TYPED_EQ);
950    result = builder_.StringEqual(left, right);
951
952    acc_.SetMachineType(gate, MachineType::I1);
953    acc_.SetGateType(gate, GateType::NJSValue());
954    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
955}
956
957template<TypedBinOp Op>
958void NumberSpeculativeLowering::VisitStringAdd(GateRef gate)
959{
960    GateRef left = acc_.GetValueIn(gate, 0);
961    GateRef right = acc_.GetValueIn(gate, 1);
962
963    GateRef result;
964    ASSERT(Op == TypedBinOp::TYPED_ADD);
965    result = builder_.StringAdd(left, right);
966
967    acc_.SetMachineType(gate, MachineType::I64);
968    acc_.SetGateType(gate, GateType::NJSValue());
969    acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
970}
971
972void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate)
973{
974    TypeInfo output = GetOutputType(gate);
975    if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
976        Environment env(gate, circuit_, &builder_);
977        GateRef frameState = acc_.GetFrameState(gate);
978        GateRef receiver = acc_.GetValueIn(gate, 0);
979        GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
980        GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
981        GateRef unsharedConstPool = acc_.GetValueIn(gate, 3); // 3: constpool
982        PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
983        GateRef result = Circuit::NullGate();
984        ASSERT(plr.IsLocal() || plr.IsFunction());
985
986        auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
987        auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
988
989        auto holderHC = builder_.LoadHClassFromConstpool(unsharedConstPool, acc_.GetConstantValue(hclassIndex));
990        DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
991        Label exit(&builder_);
992        Label loopHead(&builder_);
993        Label loadHolder(&builder_);
994        Label lookUpProto(&builder_);
995        builder_.Jump(&loopHead);
996
997        builder_.LoopBegin(&loopHead);
998        builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS7);
999        auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
1000        BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
1001
1002        builder_.Bind(&lookUpProto);
1003        current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
1004        builder_.LoopEnd(&loopHead);
1005
1006        builder_.Bind(&loadHolder);
1007        if (output == TypeInfo::FLOAT64) {
1008            if (plr.IsInlinedProps()) {
1009                result = builder_.LoadConstOffset(VariableType::FLOAT64(), *current, plr.GetOffset());
1010            } else {
1011                auto properties =
1012                    builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1013                result = builder_.GetValueFromTaggedArray(
1014                    VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
1015            }
1016            acc_.SetMachineType(gate, MachineType::F64);
1017        } else {
1018            if (plr.IsInlinedProps()) {
1019                result = builder_.LoadConstOffset(VariableType::INT32(), *current, plr.GetOffset());
1020            } else {
1021                auto properties =
1022                    builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1023                result = builder_.GetValueFromTaggedArray(
1024                    VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
1025            }
1026            acc_.SetMachineType(gate, MachineType::I32);
1027        }
1028        builder_.Jump(&exit);
1029        builder_.Bind(&exit);
1030        acc_.SetGateType(gate, GateType::NJSValue());
1031        acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1032    }
1033}
1034
1035void NumberSpeculativeLowering::VisitRound(GateRef gate)
1036{
1037    TypeInfo output = GetOutputType(gate);
1038    GateRef in = acc_.GetValueIn(gate, 0);
1039    if (output == TypeInfo::INT32) {
1040        acc_.ReplaceGate(gate, in);
1041    }
1042}
1043
1044}  // namespace panda::ecmascript
1045