/*
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H
#define ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H

#include "ecmascript/base/number_helper.h"
#include "ecmascript/compiler/assembler/assembler.h"
#include "ecmascript/compiler/builtins/builtins_call_signature.h"
#include "ecmascript/compiler/call_signature.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/compilation_env.h"
#include "ecmascript/compiler/gate.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/compiler/lcr_gate_meta_data.h"
#include "ecmascript/compiler/share_gate_meta_data.h"
#include "ecmascript/compiler/variable_type.h"
#include "ecmascript/global_env_constants.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/jspandafile/constpool_value.h"

namespace panda::ecmascript::kungfu {
using namespace panda::ecmascript;
#define DEFVALUE(varname, cirBuilder, type, val) \
        Variable varname(cirBuilder, type, cirBuilder->NextVariableId(), val)

class BuiltinsTypedArrayStubBuilder;
class BuiltinsStringStubBuilder;
class CompilationConfig;
class Environment;
class Label;
class NTypeBytecodeLowering;
class SlowPathLowering;
class StubBuilder;
class TypedBytecodeLowering;
class PGOHCRLowering;
class NTypeHCRLowering;
class TSHCRLowering;
class Variable;
class NativeInlineLowering;
class TypedHCRLowering;
class TypedNativeInlineLowering;
class StringBuilderOptimizer;
class PostSchedule;
class TSHCROptPass;
class BuiltinLowering;

#define BINARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH(V)                    \
    V(Int16Add, Add, MachineType::I16)                                    \
    V(Int32Add, Add, MachineType::I32)                                    \
    V(Int64Add, Add, MachineType::I64)                                    \
    V(DoubleAdd, Add, MachineType::F64)                                   \
    V(PtrAdd, Add, MachineType::ARCH)                                     \
    V(DoubleExp, Exp, MachineType::F64)                                   \
    V(Int16Sub, Sub, MachineType::I16)                                    \
    V(Int32Sub, Sub, MachineType::I32)                                    \
    V(Int64Sub, Sub, MachineType::I64)                                    \
    V(DoubleSub, Sub, MachineType::F64)                                   \
    V(PtrSub, Sub, MachineType::ARCH)                                     \
    V(Int32Mul, Mul, MachineType::I32)                                    \
    V(Int64Mul, Mul, MachineType::I64)                                    \
    V(DoubleMul, Mul, MachineType::F64)                                   \
    V(PtrMul, Mul, MachineType::ARCH)                                     \
    V(Int32Div, Sdiv, MachineType::I32)                                   \
    V(Int64Div, Sdiv, MachineType::I64)                                   \
    V(DoubleDiv, Fdiv, MachineType::F64)                                  \
    V(Int32Mod, Smod, MachineType::I32)                                   \
    V(IntPtrMod, Smod, MachineType::I64)                                  \
    V(DoubleMod, Smod, MachineType::F64)                                  \
    V(BitAnd, And, MachineType::I1)                                       \
    V(Int8And, And, MachineType::I8)                                      \
    V(Int8Xor, Xor, MachineType::I8)                                      \
    V(Int16And, And, MachineType::I16)                                    \
    V(Int32And, And, MachineType::I32)                                    \
    V(Int64And, And, MachineType::I64)                                    \
    V(BitOr, Or, MachineType::I1)                                         \
    V(Int16Or, Or, MachineType::I16)                                      \
    V(Int32Or, Or, MachineType::I32)                                      \
    V(Int64Or, Or, MachineType::I64)                                      \
    V(Int32Xor, Xor, MachineType::I32)                                    \
    V(Int64Xor, Xor, MachineType::I64)                                    \
    V(Int16LSL, Lsl, MachineType::I16)                                    \
    V(Int32LSL, Lsl, MachineType::I32)                                    \
    V(Int64LSL, Lsl, MachineType::I64)                                    \
    V(Int8LSR, Lsr, MachineType::I8)                                      \
    V(Int16LSR, Lsr, MachineType::I16)                                      \
    V(Int32LSR, Lsr, MachineType::I32)                                    \
    V(Int64LSR, Lsr, MachineType::I64)                                    \
    V(Int32ASR, Asr, MachineType::I32)                                    \
    V(Int64ASR, Asr, MachineType::I64)                                    \
    V(Int32Min, Min, MachineType::I32)                                    \
    V(DoubleMin, Min, MachineType::F64)                                   \
    V(Int32Max, Max, MachineType::I32)                                    \
    V(DoubleMax, Max, MachineType::F64)

#define UNARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH(V)                  \
    V(BoolNot, Rev, MachineType::I1)                                   \
    V(Int32Not, Rev, MachineType::I32)                                 \
    V(Int64Not, Rev, MachineType::I64)                                 \
    V(CastDoubleToInt64, Bitcast, MachineType::I64)                    \
    V(CastInt64ToFloat64, Bitcast, MachineType::F64)                   \
    V(CastInt32ToFloat32, Bitcast, MachineType::F32)                   \
    V(CastFloat32ToInt32, Bitcast, MachineType::I32)                   \
    V(SExtInt32ToInt64, Sext, MachineType::I64)                        \
    V(SExtInt1ToInt64, Sext, MachineType::I64)                         \
    V(SExtInt1ToInt32, Sext, MachineType::I32)                         \
    V(ZExtInt8ToInt16, Zext, MachineType::I16)                         \
    V(ZExtInt32ToInt64, Zext, MachineType::I64)                        \
    V(ZExtInt1ToInt64, Zext, MachineType::I64)                         \
    V(ZExtInt1ToInt32, Zext, MachineType::I32)                         \
    V(ZExtInt8ToInt32, Zext, MachineType::I32)                         \
    V(ZExtInt8ToInt64, Zext, MachineType::I64)                         \
    V(ZExtInt8ToPtr, Zext, MachineType::ARCH)                          \
    V(ZExtInt16ToPtr, Zext, MachineType::ARCH)                         \
    V(ZExtInt32ToPtr, Zext, MachineType::ARCH)                         \
    V(SExtInt32ToPtr, Sext, MachineType::ARCH)                         \
    V(ZExtInt16ToInt32, Zext, MachineType::I32)                        \
    V(ZExtInt16ToInt64, Zext, MachineType::I64)                        \
    V(DoubleTrunc, DoubleTrunc, MachineType::F64)                      \
    V(TruncInt16ToInt8, Trunc, MachineType::I8)                        \
    V(TruncInt64ToInt32, Trunc, MachineType::I32)                      \
    V(TruncPtrToInt32, Trunc, MachineType::I32)                        \
    V(TruncInt64ToInt1, Trunc, MachineType::I1)                        \
    V(TruncInt64ToInt16, Trunc, MachineType::I16)                      \
    V(TruncInt32ToInt1, Trunc, MachineType::I1)                        \
    V(TruncInt32ToInt8, Trunc, MachineType::I8)                        \
    V(TruncInt32ToInt16, Trunc, MachineType::I16)                      \
    V(TruncFloatToInt64, TruncFloatToInt64, MachineType::I64)          \
    V(TruncFloatToInt32, TruncFloatToInt32, MachineType::I32)          \
    V(ExtFloat32ToDouble, Fext, MachineType::F64)                      \
    V(TruncDoubleToFloat32, Ftrunc, MachineType::F32)                  \
    V(ChangeInt32ToFloat64, SignedIntToFloat, MachineType::F64)        \
    V(ChangeInt32ToFloat32, SignedIntToFloat, MachineType::F32)        \
    V(ChangeUInt32ToFloat64, UnsignedIntToFloat, MachineType::F64)     \
    V(ChangeFloat64ToInt32, FloatToSignedInt, MachineType::I32)        \
    V(ChangeTaggedPointerToInt64, TaggedToInt64, MachineType::I64)     \
    V(SExtInt16ToInt64, Sext, MachineType::I64)                        \
    V(SExtInt16ToInt32, Sext, MachineType::I32)                        \
    V(SExtInt8ToInt32, Sext, MachineType::I32)                         \
    V(SExtInt8ToInt64, Sext, MachineType::I64)                         \
    V(Abs, Abs, MachineType::I32)                                      \
    V(FAbs, Abs, MachineType::F64)                                     \
    V(CountLeadingZeroes32, Clz32, MachineType::I32)                   \
    V(DoubleCeil, Ceil, MachineType::F64)                              \
    V(DoubleFloor, Floor, MachineType::F64)                            \
    V(Int64Rev, BitRev, MachineType::I64)                              \
    V(Int32Rev, BitRev, MachineType::I32)                              \
    V(Int16Rev, BitRev, MachineType::I16)                              \
    V(Int8Rev, BitRev, MachineType::I8)

#define DOUBLE_CMP_METHOD_LIST(V)                                                    \
    V(DoubleLessThan,                       Fcmp,         FCmpCondition::OLT)        \
    V(DoubleLessThanOrEqual,                Fcmp,         FCmpCondition::OLE)        \
    V(DoubleGreaterThan,                    Fcmp,         FCmpCondition::OGT)        \
    V(DoubleGreaterThanOrEqual,             Fcmp,         FCmpCondition::OGE)        \
    V(DoubleEqual,                          Fcmp,         FCmpCondition::OEQ)        \
    V(DoubleNotEqual,                       Fcmp,         FCmpCondition::ONE)

#define INT8_CMP_METHOD_LIST(V)                                                      \
    V(Int8GreaterThanOrEqual,               Icmp,         ICmpCondition::SGE)

#define INT32_CMP_METHOD_LIST(V)                                                     \
    V(Int32LessThan,                        Icmp,         ICmpCondition::SLT)        \
    V(Int32LessThanOrEqual,                 Icmp,         ICmpCondition::SLE)        \
    V(Int32GreaterThan,                     Icmp,         ICmpCondition::SGT)        \
    V(Int32GreaterThanOrEqual,              Icmp,         ICmpCondition::SGE)        \
    V(Int32UnsignedLessThan,                Icmp,         ICmpCondition::ULT)        \
    V(Int32UnsignedLessThanOrEqual,         Icmp,         ICmpCondition::ULE)        \
    V(Int32UnsignedGreaterThan,             Icmp,         ICmpCondition::UGT)        \
    V(Int32UnsignedGreaterThanOrEqual,      Icmp,         ICmpCondition::UGE)

#define INT64_CMP_METHOD_LIST(V)                                                     \
    V(Int64LessThan,                        Icmp,         ICmpCondition::SLT)        \
    V(Int64LessThanOrEqual,                 Icmp,         ICmpCondition::SLE)        \
    V(Int64GreaterThan,                     Icmp,         ICmpCondition::SGT)        \
    V(Int64GreaterThanOrEqual,              Icmp,         ICmpCondition::SGE)        \
    V(Int64UnsignedLessThanOrEqual,         Icmp,         ICmpCondition::ULE)        \
    V(Int64UnsignedGreaterThan,             Icmp,         ICmpCondition::UGT)        \
    V(Int64UnsignedGreaterThanOrEqual,      Icmp,         ICmpCondition::UGE)

#define BINARY_CMP_METHOD_LIST_WITHOUT_BITWIDTH(V)                                   \
    DOUBLE_CMP_METHOD_LIST(V)                                                        \
    INT8_CMP_METHOD_LIST(V)                                                          \
    INT32_CMP_METHOD_LIST(V)                                                         \
    INT64_CMP_METHOD_LIST(V)

class CircuitBuilder {
public:
    explicit CircuitBuilder(Circuit *circuit) : circuit_(circuit), acc_(circuit) {}
    CircuitBuilder(Circuit *circuit, CompilationConfig *cmpCfg)
        : circuit_(circuit), acc_(circuit), cmpCfg_(cmpCfg)
    {
    }
    ~CircuitBuilder() = default;
    NO_MOVE_SEMANTIC(CircuitBuilder);
    NO_COPY_SEMANTIC(CircuitBuilder);

    enum JudgeMethodType {
        HAS_AOT,
        HAS_AOT_FASTCALL,
        HAS_AOT_NOTFASTCALL,
    };

    // **************************** Share IR *****************************
    GateRef Arguments(size_t index);
    GateRef DefaultCase(GateRef switchBranch);
    GateRef DependRelay(GateRef state, GateRef depend);
    void DeoptCheck(GateRef condition, GateRef frameState, DeoptType type);
    GateRef GetElementsArray(GateRef glue, GateRef object);
    GateRef GetLengthOfTaggedArray(GateRef array);
    GateRef GetLengthOfJSTypedArray(GateRef array);
    GateRef GetDataOfTaggedArray(GateRef array);
    GateRef GetLengthOfJSArray(GateRef array);
    GateRef IsTypedArray(GateRef glue, GateRef array);
    GateRef IsSharedTypedArray(GateRef glue, GateRef array);
    GateRef GetSuperConstructor(GateRef ctor);
    GateRef Merge(const std::vector<GateRef> &inList);
    GateRef Selector(OpCode opcode, MachineType machineType, GateRef control, const std::vector<GateRef> &values,
        int valueCounts, VariableType type = VariableType::VOID());
    GateRef Selector(OpCode opcode, GateRef control, const std::vector<GateRef> &values,
        int valueCounts, VariableType type = VariableType::VOID());
    GateRef Nop();
    GateRef Return(GateRef state, GateRef depend, GateRef value);
    GateRef ReturnVoid(GateRef state, GateRef depend);
    GateRef Goto(GateRef state);
    GateRef LoopBegin(GateRef state);
    GateRef LoopEnd(GateRef state);
    GateRef LoopExit(GateRef state);
    GateRef LoopExitDepend(GateRef state, GateRef depend);
    GateRef LoopExitValue(GateRef state, GateRef value);
    GateRef IfTrue(GateRef ifBranch);
    GateRef IfFalse(GateRef ifBranch);
    GateRef IsJsCOWArray(GateRef glue, GateRef obj);
    GateRef IsJsCOWArray(GateRef glue, GateRef obj, const CompilationEnv *compilationEnv);
    GateRef IsCOWArray(GateRef objectType);
    GateRef IsTaggedArray(GateRef glue, GateRef object);
    GateRef CheckJSType(GateRef glue, GateRef object, JSType jsType);
    GateRef IsMutantTaggedArray(GateRef objectType);
    GateRef SwitchCase(GateRef switchBranch, int64_t value);
    GateRef Int8(int8_t val);
    GateRef Int16(int16_t val);
    GateRef Int32(int32_t value);
    GateRef Int64(int64_t value);
    GateRef IntPtr(int64_t val);
    GateRef HeapConstant(uint32_t val);
    GateRef StringPtr(std::string_view str);
    GateRef StringPtr(const std::string &str);
    GateRef Boolean(bool value);
    GateRef Double(double value);
    GateRef UndefineConstant();
    GateRef HoleConstant();
    GateRef SpecialHoleConstant();
    GateRef NullPtrConstant();
    GateRef NullConstant();
    GateRef TaggedValueConstant(JSTaggedValue taggedValue);
    GateRef ExceptionConstant();
    void ClearConstantCache(GateRef gate);
    GateRef NanValue();
    GateRef RelocatableData(uint64_t val);

#define BRANCH(condition, trueLabel, falseLabel)                                         \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "- " << #falseLabel;                     \
        Branch(condition, trueLabel, falseLabel, 1, 1, os.str().c_str());                \
    }

#define BRANCH_CIR(condition, trueLabel, falseLabel)                                     \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "- " << #falseLabel;                     \
        builder_.Branch(condition, trueLabel, falseLabel, 1, 1, os.str().c_str());       \
    }

#define BRANCH_LIKELY(condition, trueLabel, falseLabel)                                  \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "(likely)- " << #falseLabel;             \
        Branch(condition, trueLabel, falseLabel,                                         \
            BranchWeight::DEOPT_WEIGHT, BranchWeight::ONE_WEIGHT, os.str().c_str());     \
    }

#define BRANCH_CIR_LIKELY(condition, trueLabel, falseLabel)                              \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "(likely)- " << #falseLabel;             \
        builder_.Branch(condition, trueLabel, falseLabel,                                \
            BranchWeight::DEOPT_WEIGHT, BranchWeight::ONE_WEIGHT, os.str().c_str());     \
    }

#define BRANCH_UNLIKELY(condition, trueLabel, falseLabel)                                \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "(unlikely)- " << #falseLabel;           \
        Branch(condition, trueLabel, falseLabel,                                         \
            BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, os.str().c_str());     \
    }

#define BRANCH_CIR_UNLIKELY(condition, trueLabel, falseLabel)                            \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "(unlikely)- " << #falseLabel;           \
        builder_.Branch(condition, trueLabel, falseLabel,                                \
            BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, os.str().c_str());     \
    }

#define BRANCH_NO_WEIGHT(condition, trueLabel, falseLabel)                               \
    {                                                                                    \
        std::ostringstream os;                                                           \
        os << __func__ << ": " << #trueLabel << "(no weight)- " << #falseLabel;          \
        Branch(condition, trueLabel, falseLabel,                                         \
            BranchWeight::ZERO_WEIGHT, BranchWeight::ZERO_WEIGHT, os.str().c_str());     \
    }

    GateRef Branch(GateRef state, GateRef condition, uint32_t leftWeight = 1, uint32_t rightWeight = 1,
                   const char* comment = nullptr);  // 1: default branch weight
    GateRef SwitchBranch(GateRef state, GateRef index, int caseCounts);
    void AppendFrameState(std::vector<GateRef> &args, GateRef hirGate);
    inline GateRef True();
    inline GateRef False();
    inline GateRef Undefined();
    inline GateRef Hole();

    GateRef ElementsKindIsInt(GateRef kind);
    GateRef ElementsKindIsIntOrHoleInt(GateRef kind);
    GateRef ElementsKindIsNumber(GateRef kind);
    GateRef ElementsKindIsNumOrHoleNum(GateRef kind);
    GateRef ElementsKindIsString(GateRef kind);
    GateRef ElementsKindIsStringOrHoleString(GateRef kind);
    GateRef ElementsKindIsHeapKind(GateRef kind);
    GateRef ElementsKindHasHole(GateRef kind);

    GateRef LoadBuiltinObject(size_t offset);

    // Get
    GateRef GetConstPoolFromFunction(GateRef glue, GateRef jsFunc);
    GateRef GetSharedConstpoolFromMethod(GateRef glue, GateRef method);
    GateRef GetUnsharedConstpoolFromGlue(GateRef glue, GateRef constpool);
    GateRef GetUnsharedConstpoolIndex(GateRef glue, GateRef constpool);
    GateRef GetUnsharedConstpool(GateRef glue, GateRef arrayAddr, GateRef index);
    GateRef GetUnsharedConstpoolArrayLen(GateRef glue);
    GateRef GetCodeAddr(GateRef jsFunc);
    GateRef GetBaselineCodeAddr(GateRef baselineCode);
    GateRef GetObjectByIndexFromConstPool(GateRef glue, GateRef hirGate, GateRef frameState, GateRef index,
                                   ConstPoolType type);
    GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef shardConstPool, GateRef unsharedConstPool,
                                   GateRef module, GateRef index, ConstPoolType type);
    GateRef GetFunctionLexicalEnv(GateRef glue, GateRef function);
    GateRef GetGlobalEnv();
    GateRef GetGlobalEnvObj(GateRef env, size_t index);
    GateRef GetGlobalEnvObjHClass(GateRef env, size_t index);
    GateRef GetGlobalConstantValue(ConstantIndex index);
    GateRef GetGlobalEnvValue(VariableType type, GateRef glue, GateRef env, size_t index);
    GateRef GetGlobalEnv(GateRef glue);
    GateRef GetGlobalObject(GateRef glue, GateRef globalEnv);
    GateRef GetMethodFromFunction(GateRef glue, GateRef function);
    GateRef GetModuleFromFunction(GateRef glue, GateRef function);
    GateRef GetSendableEnvFromModule(GateRef glue, GateRef module);
    GateRef GetHomeObjectFromFunction(GateRef glue, GateRef function);
    GateRef GetHClassGateFromIndex(GateRef gate, int32_t index);
    GateRef GetProfileTypeInfo(GateRef glue, GateRef function);
    inline GateRef GetExpectedNumOfArgs(GateRef method);
    inline GateRef GetGlobalConstantOffset(ConstantIndex index); // shareir
    GateRef GetEmptyArray(GateRef glue);
    GateRef IsCompositeHClass(GateRef hClass);
    void CheckHClassFieldInvalidAccess(GateRef glue, GateRef hClass);
    void CheckHClassAddrInvalid(GateRef glue, GateRef hClass);
    GateRef GetPrototypeFromHClass(GateRef glue, GateRef hClass);
    GateRef GetEnumCacheFromHClass(GateRef glue, GateRef hClass);
    GateRef GetProtoChangeMarkerFromHClass(GateRef glue, GateRef hClass);
    GateRef GetCacheKindFromForInIterator(GateRef iter);
    GateRef GetLengthFromForInIterator(GateRef iter);
    GateRef GetIndexFromForInIterator(GateRef iter);
    GateRef GetKeysFromForInIterator(GateRef glue, GateRef iter);
    GateRef GetObjectFromForInIterator(GateRef glue, GateRef iter);
    GateRef GetCachedHClassFromForInIterator(GateRef glue, GateRef iter);
    void SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length);
    void SetCacheKindForInIterator(GateRef glue, GateRef iter, GateRef cacheKind);
    void SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index);
    void SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys);
    void SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object);
    void SetCachedHClassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass);
    void IncreaseIteratorIndex(GateRef glue, GateRef iter, GateRef index);
    void IncreaseArrayIteratorIndex(GateRef glue, GateRef iter, GateRef index);
    void SetNextIndexOfArrayIterator(GateRef glue, GateRef iter, GateRef nextIndex);
    void SetIteratedArrayOfArrayIterator(GateRef glue, GateRef iter, GateRef iteratedArray);
    void SetBitFieldOfArrayIterator(GateRef glue, GateRef iter, GateRef kind);
    GateRef GetArrayIterationKind(GateRef iter);
    GateRef GetHasChanged(GateRef object);
    GateRef GetAccessorHasChanged(GateRef object);
    GateRef GetNotFoundHasChanged(GateRef object);
    GateRef HasDeleteProperty(GateRef hClass);
    GateRef IsOnHeap(GateRef hClass);
    GateRef IsEcmaObject(GateRef glue, GateRef obj);
    GateRef GetStageOfHotReload(GateRef glue);
    GateRef IsNotLdEndExecPatchMain(GateRef glue);
    GateRef FloatArrayElementConvert(GateRef value, bool isFloat32);

    // Set
    void SetLengthToFunction(GateRef glue, GateRef function, GateRef value);
    void SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value);
    void SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value);
    void SetModuleToFunction(GateRef glue, GateRef function, GateRef value);
    void SetSendableEnvToModule(GateRef glue, GateRef module, GateRef value);
    void SetRawProfileTypeInfoToFunction(GateRef glue, GateRef function, GateRef value);
    void UpdateProfileTypeInfoCellToFunction(GateRef glue, GateRef function,
                                             GateRef profileTypeInfo, GateRef slotId);
    void UpdateProfileTypeInfoCellType(GateRef glue, GateRef profileTypeInfoCell);

    GateRef FunctionIsResolved(GateRef function);
    GateRef HasPendingException(GateRef glue); // shareir
    GateRef HasPendingException(GateRef glue, const CompilationEnv *compilationEnv);
    GateRef IsUtf8String(GateRef string);
    GateRef IsUtf16String(GateRef string);
    GateRef IsInternString(GateRef string);
    GateRef LoadObjectFromConstPool(GateRef glue, GateRef constPool, GateRef index);
    GateRef IsAccessorInternal(GateRef glue, GateRef accessor);

    // label related
    void NewEnvironment(GateRef hir);
    void DeleteCurrentEnvironment();
    inline int NextVariableId();
    inline void HandleException(GateRef result, Label *success, Label *exception, Label *exit);
    inline void HandleException(GateRef result, Label *success, Label *fail, Label *exit, GateRef exceptionVal);
    inline void SubCfgEntry(Label *entry);
    inline void SubCfgExit();
    inline GateRef Return(GateRef value);
    inline GateRef Return();
    inline void Bind(Label *label);
    inline void Bind(Label *label, bool justSlowPath);
    void Jump(Label *label);
    void Branch(GateRef condition, Label *trueLabel, Label *falseLabel,
                uint32_t trueWeight = 1, uint32_t falseWeight = 1, const char* comment = nullptr);
    void Switch(GateRef index, Label *defaultLabel,
                const int64_t *keysValue, Label *keysLabel, int numberOfKeys);
    void Switch(GateRef index, Label *defaultLabel,
                const int64_t *keysValue, Label * const *keysLabel, int numberOfKeys);
    void LoopBegin(Label *loopHead);
    void LoopEnd(Label *loopHead);
    void LoopExit(const std::vector<Variable*> &vars, size_t diff = 1);
    inline Label *GetCurrentLabel() const;
    inline GateRef GetState() const;
    inline GateRef GetDepend() const;
    inline StateDepend GetStateDepend() const;

    Circuit *GetCircuit() const
    {
        return circuit_;
    }

    void SetEnvironment(Environment *env)
    {
        env_ = env;
    }
    Environment *GetCurrentEnvironment() const
    {
        return env_;
    }
    void SetCompilationConfig(CompilationConfig *cmpCfg)
    {
        cmpCfg_ = cmpCfg;
    }
    CompilationConfig *GetCompilationConfig() const
    {
        return cmpCfg_;
    }

    // **************************** High IR ******************************
    GateRef CreateArray(ElementsKind kind, uint32_t arraySize, GateRef elementsLength, RegionSpaceFlag flag);
    GateRef CreateArrayWithBuffer(ElementsKind kind, ArrayMetaDataAccessor::Mode mode, GateRef cpId,
                                  GateRef constPoolIndex, RegionSpaceFlag flag);
    GateRef CreateArguments(ElementsKind kind, CreateArgumentsAccessor::Mode mode, GateRef restIdx);
    GateRef Construct(GateRef hirGate, std::vector<GateRef> args);
    GateRef CallNew(GateRef hirGate, std::vector<GateRef> args, bool needPushArgv = false, bool isFastCall = false);
    GateRef CallInternal(GateRef hirGate, std::vector<GateRef> args, uint64_t pcOffset);
    GateRef TypedCallNative(GateRef hirGate, GateRef thisObj, GateRef funcId);
    GateRef IsBase(GateRef glue, GateRef ctor);
    GateRef IsDerived(GateRef glue, GateRef ctor);
    GateRef ToLength(GateRef receiver);
    GateRef StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value);
    GateRef LdLocalModuleVar(GateRef jsFunc, GateRef index);
    GateRef LdExternalModuleVar(GateRef jsFunc, GateRef index);
    GateRef BuiltinConstructor(BuiltinsStubCSigns::ID id, GateRef gate);

    inline GateRef GetMethodId(GateRef glue, GateRef func);
    inline GateRef GetBuiltinsId(GateRef glue, GateRef func);
    inline GateRef IsAOTLiteralInfo(GateRef glue, GateRef x);
    GateRef GetKeyFromLexivalEnv(GateRef glue, GateRef lexicalEnv, GateRef levelIndex, GateRef slotIndex);
    GateRef GetParentEnv(GateRef glue, GateRef object);
    GateRef GetSendableParentEnv(GateRef glue, GateRef object);
    GateRef GetPropertiesFromLexicalEnv(GateRef glue, GateRef object, GateRef index);
    GateRef GetPropertiesFromSendableEnv(GateRef glue, GateRef object, GateRef index);
    GateRef Float32ArrayConstructor(GateRef hirGate, std::vector<GateRef> args);

    // call operation
    GateRef CallPrivateGetter(GateRef hirGate, GateRef receiver, GateRef accessor, const char* comment = nullptr);
    GateRef CallPrivateSetter(
        GateRef hirGate, GateRef receiver, GateRef accessor, GateRef value, const char* comment = nullptr);
    GateRef CallGetter(GateRef hirGate, GateRef receiver, GateRef holder,
        GateRef propertyLookupResult, const char* comment = nullptr);
    GateRef CallSetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult,
                       GateRef value, const char* comment = nullptr);
    GateRef CallBCHandler(GateRef glue, GateRef target, const std::vector<GateRef> &args,
                          const char* comment = nullptr);
    GateRef CallBCDebugger(GateRef glue, GateRef target, const std::vector<GateRef> &args,
                           const char* comment = nullptr);
    GateRef CallBuiltin(GateRef glue, GateRef target, const std::vector<GateRef> &args,
                        GateRef hir = Circuit::NullGate(),
                        const char* comment = nullptr);
    GateRef CallBuiltinWithArgv(GateRef glue, GateRef target, const std::vector<GateRef> &args,
                                const char* comment = nullptr);
    GateRef CallRuntimeVarargs(GateRef glue, int index, GateRef argc, GateRef argv, const char* comment = nullptr);
    GateRef CallRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args, GateRef hirGate,
                        const char* comment = nullptr);
    GateRef CallNGCRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args, bool useLabel);

    GateRef CallNGCRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args,
                           GateRef hirGate, const char* comment = nullptr);
    GateRef FastCallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args,
                              GateRef hirGate);
    GateRef CallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args,
                          GateRef hirGate);
    GateRef CallStub(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
                     const char* comment = nullptr);
    GateRef CallCommonStub(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
                           const char *comment = nullptr);
    GateRef CallBuiltinRuntime(GateRef glue, GateRef depend, const std::vector<GateRef> &args, bool isNew = false);
    GateRef CallBuiltinRuntimeWithNewTarget(GateRef glue, GateRef depend, const std::vector<GateRef> &args);
    GateRef Call(const CallSignature* cs, GateRef glue, GateRef target, GateRef depend,
                 const std::vector<GateRef> &args, GateRef hirGate, const char* comment = nullptr);
    GateRef NoLabelCallRuntime(GateRef glue, GateRef depend, size_t index, std::vector<GateRef> &args, GateRef hirGate);

    void StartCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel);
    void EndCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel);
    GateRef GetCallBuiltinId(GateRef method);

    // FastCall
    inline GateRef CanFastCall(GateRef jsFunc);

    // Js world
    inline GateRef GetObjectType(GateRef hClass);
    inline GateRef HasConstructor(GateRef glue, GateRef object);
    inline GateRef IsSpecial(GateRef x, JSTaggedType type);
    inline GateRef IsJSFunction(GateRef glue, GateRef obj);
    inline GateRef IsDictionaryMode(GateRef glue, GateRef object);
    inline GateRef IsJsType(GateRef glue, GateRef object, JSType type);
    inline GateRef IsStableElements(GateRef hClass);
    inline GateRef IsStableElements(GateRef hClass, CompilationEnv *compilationEnv);
    inline GateRef IsStableArguments(GateRef hClass);
    inline GateRef IsStableArray(GateRef hClass);
    inline GateRef IsDictionaryElement(GateRef hClass);
    inline GateRef IsJSArrayPrototypeModified(GateRef hClass);
    inline GateRef IsClassConstructor(GateRef glue, GateRef object);
    inline GateRef IsClassConstructorWithBitField(GateRef bitfield);
    inline GateRef IsConstructor(GateRef glue, GateRef object);
    inline GateRef IsClassPrototype(GateRef glue, GateRef object);
    inline GateRef IsClassPrototypeWithBitField(GateRef object);
    inline GateRef IsExtensible(GateRef glue, GateRef object);
    inline GateRef IsJSObject(GateRef glue, GateRef obj);
    inline GateRef IsCallable(GateRef glue, GateRef obj);
    inline GateRef IsCallableFromBitField(GateRef bitfield);
    inline GateRef AlreadyDeopt(GateRef method);
    inline GateRef AlreadyDeoptFromExtraLiteralInfo(GateRef callfield);
    inline GateRef IsPrototypeHClass(GateRef hclass);
    inline GateRef IsJsProxy(GateRef glue, GateRef obj);
    GateRef IsJSHClass(GateRef glue, GateRef obj);
    // It must sets zero for high 32 bits field when store hclass to object header.
    inline void StoreHClass(GateRef glue, GateRef object, GateRef hClass, RegionSpaceFlag spaceType,
                            MemoryAttribute mAttr = MemoryAttribute::NeedBarrier());
    // It must keeps high 32 bits field when store hclass to object header.
    inline void TransitionHClass(GateRef glue, GateRef object, GateRef hClass,
                             MemoryAttribute mAttr = MemoryAttribute::NeedBarrier());
    inline void TransitionHClassByConstOffset(GateRef glue, GateRef object, GateRef hClass,
                                              MemoryAttribute mAttr = MemoryAttribute::NeedBarrier());
    inline void StorePrototype(GateRef glue, GateRef hclass, GateRef prototype);
    void SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible);

    // WeakRef
    inline GateRef CreateWeakRef(GateRef x);
    inline GateRef LoadObjectFromWeakRef(GateRef x);

    // hClass
    inline GateRef GetElementsKindByHClass(GateRef hClass);
    inline GateRef GetObjectSizeFromHClass(GateRef hClass);
    inline GateRef HasConstructorByHClass(GateRef hClass);
    inline GateRef IsDictionaryModeByHClass(GateRef hClass);
    inline GateRef LoadHclassImpl(GateRef glue, GateRef object, int line);
    // notice: if jump here by stub_builder please see stub_builder-inl.h/stub_builder.h LoadHclassImpl
#define LoadHClass(glue, object) LoadHclassImpl(glue, object, __LINE__)
    inline GateRef LoadHClassByConstOffset(GateRef glue, GateRef object);
    inline GateRef LoadPrototype(GateRef glue, GateRef hclass);
    inline GateRef LoadProtoChangeMarker(GateRef glue, GateRef hclass);
    inline GateRef LoadPrototypeHClass(GateRef glue, GateRef object);
    inline GateRef LoadPrototypeOfPrototypeHClass(GateRef glue, GateRef object);
    void SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass,
                                 GateRef value, GateRef attrOffset, VariableType type);

    // Others
    GateRef OrdinaryHasInstance(GateRef obj, GateRef target);
    GateRef MigrateArrayWithKind(GateRef receiver, GateRef oldElementsKind, GateRef newElementsKind);

    // **************************** Middle IR ****************************
    GateRef EcmaObjectCheck(GateRef gate);
    GateRef HeapObjectCheck(GateRef gate, GateRef frameState);
    GateRef BuiltinHClassConsistencyCheck(GateRef receiver, GateRef classIndexGate);
    GateRef HeapObjectIsEcmaObjectCheck(GateRef gate, GateRef frameState);
    GateRef ProtoChangeMarkerCheck(GateRef gate, GateRef frameState = Gate::InvalidGateRef);
    GateRef PrimitiveTypeProtoChangeMarkerCheck(GateRef gate, GateRef frameState);
    GateRef StableArrayCheck(GateRef gate, ElementsKind kind, ArrayMetaDataAccessor::Mode mode);
    GateRef ElementsKindCheck(GateRef receiver, ElementsKind kind, ArrayMetaDataAccessor::Mode mode);
    GateRef COWArrayCheck(GateRef gate);
    GateRef EcmaStringCheck(GateRef gate);
    GateRef StringKeyCheck(GateRef key, GateRef value);
    GateRef InternStringKeyCheck(GateRef key, GateRef value);
    GateRef InternStringCheck(GateRef gate);
    GateRef EcmaMapCheck(GateRef gate);
    GateRef FlattenTreeStringCheck(GateRef gate);
    GateRef HClassStableArrayCheck(GateRef gate, GateRef frameState, ArrayMetaDataAccessor accessor);
    GateRef ArrayGuardianCheck(GateRef frameState);
    GateRef TypedArrayCheck(GateRef gate, ParamType paramType, TypedArrayMetaDataAccessor::Mode mode,
                            OnHeapMode onHeap = OnHeapMode::NONE);
    GateRef LoadTypedArrayLength(GateRef gate, ParamType paramType, OnHeapMode onHeap = OnHeapMode::NONE);
    GateRef RangeGuard(GateRef gate, uint32_t left, uint32_t right);
    GateRef BuiltinInstanceHClassCheck(GateRef gate, BuiltinTypeId type, ElementsKind kind,
                                       bool isPrototypeOfPrototype);
    GateRef BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type, ElementsKind kind,
                                        bool isPrototypeOfPrototype);
    GateRef OrdinaryHasInstanceCheck(GateRef target, GateRef jsFunc, std::vector<GateRef> &expectedHCIndexes);
    GateRef IndexCheck(GateRef gate, GateRef index);
    GateRef ObjectTypeCheck(bool isHeapObject, GateRef gate, GateRef hclassIndex,
                            GateRef frameState = Gate::InvalidGateRef);
    GateRef ObjectTypeCheck(bool isHeapObject, GateRef gate, const std::vector<int>& hclassIndexList,
                            GateRef frameState = Gate::InvalidGateRef);
    GateRef TryPrimitiveTypeCheck(GateType type, GateRef gate);
    GateRef CallTargetCheck(GateRef gate, GateRef function, GateRef id, const char* comment = nullptr);
    GateRef CallTargetCheck(GateRef gate, GateRef function, GateRef id, std::vector<GateRef> params,
                            const char* comment = nullptr);
    GateRef InlineSuperCtorCheck(GateRef gate, GateRef function, GateRef newTarget, GateRef methodOffset,
                                 const char* comment = nullptr);
    template<TypedCallTargetCheckOp Op>
    GateRef JSCallTargetTypeCheck(GateRef func, GateRef methodIndex, GateRef gate);
    template<TypedCallTargetCheckOp Op>
    inline GateRef JSNoGCCallThisTargetTypeCheck(GateRef func, GateRef methodId, GateRef gate);
    GateRef CallTargetIsCompiledCheck(GateRef func, GateRef gate);
    GateRef TypeOfCheck(GateRef gate, ParamType paramType);
    GateRef TypedTypeOf(ParamType paramType);
    GateRef TypedCallOperator(GateRef hirGate, MachineType type, const std::vector<GateRef>& inList, bool isSideEffect);
    inline GateRef CallNewBuiltin(GateRef hirGate, std::vector<GateRef> &args);
    inline GateRef TypedCallBuiltin(GateRef hirGate, const std::vector<GateRef> &args,
                                    BuiltinsStubCSigns::ID id, bool isSideEffect);
    GateRef TypeConvert(MachineType type, ParamType typeFrom, GateType typeTo, const std::vector<GateRef>& inList);
    GateRef ProductIsNegativeZero(GateRef result, GateRef left, GateRef right);
    GateRef Int32CheckRightIsZero(GateRef right);
    GateRef RemainderIsNegativeZero(GateRef left, GateRef right);
    GateRef Float64CheckRightIsZero(GateRef right);
    GateRef ValueCheckNegOverflow(GateRef value);
    GateRef OverflowCheck(GateRef value);
    GateRef LexVarIsHoleCheck(GateRef value);
    GateRef IsUndefinedOrHoleCheck(GateRef value);
    GateRef IsNotUndefinedOrHoleCheck(GateRef value);
    GateRef IsDataViewCheck(GateRef obj);
    GateRef IsCallableCheck(GateRef func, GateRef frameState = Circuit::NullGate());
    GateRef Int32UnsignedUpperBoundCheck(GateRef value, GateRef upperBound);
    GateRef Int32DivWithCheck(GateRef left, GateRef right);
    GateType GetGateTypeOfValueType(ValueType type);
    GateRef InsertStableArrayCheck(GateRef array, ArrayMetaDataAccessor accessor);
    GateRef InsertLoadArrayLength(GateRef array, GateRef length, bool isTypedArray);
    GateRef InsertTypedArrayCheck(GateRef array, TypedArrayMetaDataAccessor accessor);
    GateRef TypedConstructorCheck(GateRef gate, size_t type);
    GateRef ArrayConstructorCheck(GateRef gate);
    GateRef Float32ArrayConstructorCheck(GateRef gate);
    GateRef ObjectConstructorCheck(GateRef gate);
    GateRef BooleanConstructorCheck(GateRef gate);
    GateRef InsertTypedBinaryop(GateRef left, GateRef right, TypedBinOp op);
    GateRef InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right);
    GateRef TypedConditionJump(MachineType type, TypedJumpOp jumpOp, uint32_t weight, ParamType paramType,
                               const std::vector<GateRef>& inList);
    GateRef TypedNewAllocateThis(GateRef ctor, GateRef hclass, GateRef size, GateRef frameState);
    GateRef TypedSuperAllocateThis(GateRef superCtor, GateRef newTarget);
    template<TypedBinOp Op>
    inline GateRef TypedBinaryOp(GateRef x, GateRef y, ParamType paramType);
    template<TypedUnOp Op>
    inline GateRef TypedUnaryOp(GateRef x, ParamType paramType);
    template<TypedJumpOp Op>
    inline GateRef TypedConditionJump(GateRef x, ParamType paramType, uint32_t weight);
    GateRef Convert(GateRef gate, ValueType src, ValueType dst);
    GateRef ConvertBoolToTaggedBoolean(GateRef gate);
    GateRef ConvertTaggedBooleanToBool(GateRef gate);
    GateRef ConvertInt32ToBool(GateRef gate);
    GateRef ConvertFloat64ToBool(GateRef gate);
    GateRef ConvertInt32ToTaggedInt(GateRef gate);
    GateRef ConvertFloat64ToTaggedDouble(GateRef gate);
    GateRef ConvertFloat64ToInt32(GateRef gate);
    GateRef ConvertInt32ToFloat64(GateRef gate);
    GateRef ConvertBoolToInt32(GateRef gate, ConvertSupport support);
    GateRef ConvertBoolToFloat64(GateRef gate, ConvertSupport support);
    GateRef ConvertUInt32ToBool(GateRef gate);
    GateRef ConvertUInt32ToTaggedNumber(GateRef gate);
    GateRef ConvertUInt32ToFloat64(GateRef gate);
    GateRef ConvertCharToEcmaString(GateRef gate);
    GateRef ConvertCharToInt32(GateRef gate);
    GateRef ConvertCharToDouble(GateRef gate);
    GateRef CheckAndConvert(
        GateRef gate, ValueType src, ValueType dst, ConvertSupport support = ConvertSupport::ENABLE);
    GateRef ConvertHoleAsUndefined(GateRef receiver);
    GateRef ConvertSpecialHoleIntToTagged(GateRef gate);
    GateRef ConvertSpecialHoleDoubleToTagged(GateRef gate);
    GateRef CheckSpecialHoleAndConvertToTaggedInt(GateRef receiver);
    GateRef CheckSpecialHoleAndConvertToTaggedDouble(GateRef receiver);
    GateRef CheckUInt32AndConvertToInt32(GateRef gate);
    GateRef CheckTaggedIntAndConvertToInt32(GateRef gate);
    GateRef CheckTaggedDoubleAndConvertToInt32(GateRef gate);
    GateRef CheckTaggedNumberAndConvertToInt32(GateRef gate);
    GateRef CheckTaggedIntAndConvertToFloat64(GateRef gate);
    GateRef CheckTaggedDoubleAndConvertToFloat64(GateRef gate);
    GateRef CheckTaggedNumberAndConvertToFloat64(GateRef gate);
    GateRef CheckTaggedNumberAndConvertToBool(GateRef gate);
    GateRef CheckTaggedBooleanAndConvertToBool(GateRef gate);
    GateRef CheckNullAndConvertToInt32(GateRef gate);
    GateRef CheckTaggedBooleanAndConvertToInt32(GateRef gate);
    GateRef CheckHoleIntAndConvertToTaggedInt(GateRef gate);
    GateRef CheckHoleDoubleAndConvertToTaggedDouble(GateRef gate);
    GateRef CheckNullAndConvertToFloat64(GateRef gate);
    GateRef CheckTaggedBooleanAndConvertToFloat64(GateRef gate);
    GateRef CheckUndefinedAndConvertToFloat64(GateRef gate);
    GateRef CheckUndefinedAndConvertToBool(GateRef gate);
    GateRef CheckNullAndConvertToBool(GateRef gate);
    GateRef CheckUndefinedAndConvertToInt32(GateRef gate);
    GateRef CheckHoleIntAndConvertToInt32(GateRef gate);
    GateRef CheckHoleDoubleAndConvertToInt32(GateRef gate);
    GateRef CheckHoleIntAndConvertToFloat64(GateRef gate);
    GateRef CheckHoleDoubleAndConvertToFloat64(GateRef gate);
    GateRef CheckFloat64ConvertToInt32Legally(GateRef gate);
    GateRef StartAllocate();
    GateRef FinishAllocate(GateRef value);

    inline GateRef PrimitiveToNumber(GateRef x, ParamType paramType);
    inline GateRef GetValueFromTaggedArray(GateRef glue, GateRef array, GateRef index);
    inline GateRef GetValueFromTaggedArray(GateRef glue, GateRef array, GateRef index, GateRef depend);
    inline GateRef GetValueFromTaggedArray(VariableType valType, GateRef array, GateRef index);
    inline GateRef GetValueFromJSArrayWithElementsKind(VariableType type, GateRef array, GateRef index);
    inline GateRef GetArrayElementsGuardians(GateRef env);
    inline GateRef GetMapIteratorDetector(GateRef env);
    inline GateRef GetSetIteratorDetector(GateRef env);
    inline GateRef GetStringIteratorDetector(GateRef env);
    inline GateRef GetStringWrapperToPrimitiveDetector(GateRef env);
    inline GateRef GetArrayIteratorDetector(GateRef env);
    inline GateRef GetTypedArrayIteratorDetector(GateRef env);
    inline GateRef GetTypedArraySpeciesProtectDetector(GateRef env);
    template<TypedLoadOp Op>
    GateRef LoadElement(GateRef receiver, GateRef index, OnHeapMode onHeap = OnHeapMode::NONE);
    GateRef LoadProperty(GateRef receiver, GateRef propertyLookupResult, bool isFunction);
    GateRef LoadArrayLength(GateRef gate, ElementsKind kind, ArrayMetaDataAccessor::Mode mode);
    inline GateRef LoadFromTaggedArray(GateRef array, size_t index);
    GateRef LoadStringLength(GateRef string);
    GateRef LoadMapSize(GateRef string);
    GateRef LoadConstOffset(VariableType type, GateRef receiver, size_t offset,
                            MemoryAttribute mAttr = MemoryAttribute::Default());
    GateRef LoadHClassByConstOffset(VariableType type, GateRef receiver);
    GateRef LoadHClassFromConstpool(GateRef constpool, size_t index);
    GateRef TypedCall(GateRef hirGate, std::vector<GateRef> args, bool isNoGC);
    GateRef TypedFastCall(GateRef hirGate, std::vector<GateRef> args, bool isNoGC);
    inline void SetValueToTaggedArray(VariableType valType, GateRef glue, GateRef array, GateRef index, GateRef val);
    GateRef StoreConstOffset(VariableType type, GateRef receiver, size_t offset, GateRef value,
                             MemoryAttribute mAttr = MemoryAttribute::Default());
    GateRef StoreHClassConstOffset(VariableType type, GateRef receiver, GateRef value, GateRef compValue,
                                   MemoryAttribute mAttr = MemoryAttribute::Default());
    inline GateRef StoreToTaggedArray(GateRef array, size_t index, GateRef value);
    GateRef StringEqual(GateRef x, GateRef y);
    GateRef StringAdd(GateRef x, GateRef y, uint32_t stringStatus = 0);
    template<TypedStoreOp Op>
    GateRef StoreElement(GateRef receiver, GateRef index, GateRef value, OnHeapMode onHeap = OnHeapMode::NONE);
    GateRef StoreMemory(MemoryType Op, VariableType type, GateRef receiver, GateRef index, GateRef value);
    GateRef StoreProperty(GateRef receiver, GateRef propertyLookupResult, GateRef value, uint32_t receiverHClassIndex);
    inline GateRef JudgeAotAndFastCall(GateRef jsFunc, JudgeMethodType type);
    GateRef ComputeTaggedArraySize(GateRef length);
    GateRef HeapAlloc(GateRef glue, GateRef size, GateType type, RegionSpaceFlag flag);
    GateRef TaggedIsHeapObjectOp(GateRef value);
    GateRef IsSpecificObjectType(GateRef obj, JSType type);
    GateRef IsMarkerCellValid(GateRef cell);
    GateRef IsMarkerCellValidOp(GateRef cell);
    GateRef MonoLoadPropertyOnProto(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex);
    GateRef MonoCallGetterOnProto(GateRef gate, GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex);
    GateRef MonoStorePropertyLookUpProto(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex,
                                         GateRef value);
    GateRef MonoStoreProperty(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex,
                              GateRef value, GateRef keyIndex, GateRef isProto, GateRef frameState);
    GateRef TypedCreateObjWithBuffer(std::vector<GateRef> &valueIn);
    template<TypedLoadOp Op>
    GateRef ConvertJSArrayHoleAsUndefined(GateRef receiver);
    GateRef BuildBigIntAsIntN(const GateMetaData* op, std::vector<GateRef> &&args);
    GateRef NewJSPrimitiveRef(GateRef glue, GateRef globalEnv, size_t index, GateRef obj);
    GateRef ToObject(GateRef glue, GateRef globalEnv, GateRef obj);
    GateRef GetPrototype(GateRef glue, GateRef object);

    GateRef GetGlobalConstantValue(VariableType type, GateRef glue, ConstantIndex index);
    GateRef TransProtoWithoutLayout(GateRef glue, GateRef hClass, GateRef proto);
    GateRef OrdinaryNewJSObjectCreate(GateRef glue, GateRef proto);

    // bit operation
    inline GateRef TaggedIsInt(GateRef x);
    inline GateRef TaggedIsDouble(GateRef x);
    inline GateRef TaggedIsObject(GateRef x);
    inline GateRef TaggedIsNumber(GateRef x);
    inline GateRef TaggedIsNumeric(GateRef glue, GateRef x);
    inline GateRef TaggedIsNotHole(GateRef x);
    inline GateRef TaggedIsHole(GateRef x);
    inline GateRef TaggedIsNullPtr(GateRef x);
    inline GateRef TaggedIsUndefined(GateRef x);
    inline GateRef TaggedIsException(GateRef x);
    inline GateRef TaggedIsSpecial(GateRef x);
    inline GateRef TaggedIsHeapObject(GateRef x);
    inline GateRef TaggedIsHeapObject(GateRef x, const CompilationEnv *compilationEnv);
    inline GateRef TaggedIsJSFunction(GateRef glue, GateRef x);
    inline GateRef TaggedIsArrayIterator(GateRef glue, GateRef obj);
    inline GateRef TaggedIsAsyncGeneratorObject(GateRef glue, GateRef x);
    inline GateRef TaggedIsJSGlobalObject(GateRef glue, GateRef x);
    inline GateRef TaggedIsGeneratorObject(GateRef glue, GateRef x);
    inline GateRef TaggedIsJSArray(GateRef glue, GateRef x);
    inline GateRef TaggedIsJSProxy(GateRef glue, GateRef x);
    inline GateRef TaggedIsPropertyBox(GateRef glue, GateRef x);
    inline GateRef TaggedIsWeak(GateRef x);
    inline GateRef TaggedIsPrototypeHandler(GateRef glue, GateRef x);
    inline GateRef TaggedIsTransitionHandler(GateRef glue, GateRef x);
    inline GateRef TaggedIsStoreAOTHandler(GateRef glue, GateRef x);
    inline GateRef TaggedIsTransWithProtoHandler(GateRef glue, GateRef x);
    inline GateRef TaggedIsUndefinedOrNull(GateRef x);
    inline GateRef TaggedIsUndefinedOrNullOrHole(GateRef x);
    inline GateRef TaggedIsNotUndefinedAndNullAndHole(GateRef x);
    inline GateRef TaggedIsNotUndefinedAndNull(GateRef x);
    inline GateRef TaggedIsUndefinedOrHole(GateRef x);
    inline GateRef TaggedIsTrue(GateRef x);
    inline GateRef TaggedIsFalse(GateRef x);
    inline GateRef TaggedIsNull(GateRef x);
    inline GateRef TaggedIsNotNull(GateRef x);
    inline GateRef TaggedIsBoolean(GateRef x);
    inline GateRef TaggedIsNativePointer(GateRef glue, GateRef x);
    inline GateRef TaggedIsBigInt(GateRef glue, GateRef obj);
    inline GateRef TaggedIsString(GateRef glue, GateRef obj);
    inline GateRef TaggedIsLineUtf8String(GateRef glue, GateRef obj);
    inline GateRef TaggedIsStringIterator(GateRef glue, GateRef obj);
    inline GateRef TaggedIsSharedObj(GateRef glue, GateRef obj);
    inline GateRef TaggedIsStableArray(GateRef glue, GateRef obj);
    inline GateRef TaggedIsStringOrSymbol(GateRef glue, GateRef obj);
    inline GateRef TaggedIsSymbol(GateRef glue, GateRef obj);
    inline GateRef TaggedIsEnumCache(GateRef glue, GateRef obj);
    inline GateRef TaggedIsProtoChangeMarker(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsJSMap(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsJSSet(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsJSDate(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsTypedArray(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsJSArray(GateRef glue, GateRef obj);
    inline GateRef TaggedIsBoundFunction(GateRef glue, GateRef obj);
    inline GateRef TaggedGetInt(GateRef x);
    inline GateRef TaggedObjectIsString(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsString(GateRef glue, GateRef obj, const CompilationEnv *compilationEnv);
    inline GateRef TaggedObjectIsShared(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsEcmaObject(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsByteArray(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsMap(GateRef glue, GateRef obj);
    inline GateRef TaggedObjectIsDataView(GateRef glue, GateRef obj);
    inline GateRef IsSpecialHole(GateRef x);
    inline GateRef IsNotSpecialHole(GateRef x);
    inline GateRef TaggedTrue();
    inline GateRef TaggedFalse();

    // String
    inline GateRef BothAreString(GateRef glue, GateRef x, GateRef y);
    inline GateRef IsTreeString(GateRef glue, GateRef obj);
    inline GateRef IsSlicedString(GateRef glue, GateRef obj);
    inline GateRef IsCachedExternalString(GateRef glue, GateRef obj);
    inline GateRef IsSpecialSlicedString(GateRef glue, GateRef obj);
    inline GateRef IsLineString(GateRef glue, GateRef obj);
    inline GateRef TreeStringIsFlat(GateRef glue, GateRef string);
    inline GateRef GetFirstFromTreeString(GateRef glue, GateRef string);
    inline GateRef GetSecondFromTreeString(GateRef glue, GateRef string);
    inline GateRef ComputeSizeUtf8(GateRef length);
    inline GateRef ComputeSizeUtf16(GateRef length);
    inline GateRef AlignUp(GateRef x, GateRef alignment);
    GateRef NumberToString(GateRef number);
    GateRef TaggedPointerToInt64(GateRef x);
    GateRef GetLengthFromString(GateRef value);
    GateRef Rotl(GateRef word, uint32_t shift);
    GateRef CalcHashcodeForInt(GateRef value);
    GateRef GetHashcodeFromString(GateRef glue, GateRef value, GateRef hir = Circuit::NullGate());
    GateRef TryGetHashcodeFromString(GateRef string);
    GateRef CanBeConcat(GateRef glue, GateRef leftString, GateRef rightString, GateRef isValidOpt);
    GateRef CanBackStore(GateRef glue, GateRef rightString, GateRef isValidOpt);
    void CopyUtf8AsUtf16(GateRef glue, GateRef dst, GateRef src, GateRef sourceLength);
    void CopyChars(GateRef glue, GateRef dst, GateRef source, GateRef sourceLength,
        GateRef charSize, VariableType type);
    void SetMixHashcode(GateRef glue, GateRef str, GateRef rawHashcode);
    GateRef StringFromSingleCharCode(GateRef gate);
    GateRef StringCharCodeAt(GateRef thisValue, GateRef posTag);
    GateRef StringSubstring(GateRef thisValue, GateRef startTag, GateRef endTag);
    GateRef StringSubStr(GateRef thisValue, GateRef intStart, GateRef lengthTag);
    GateRef StringSlice(GateRef thisValue, GateRef startTag, GateRef endTag);
    GateRef NumberIsNaN(GateRef gate);
    GateRef NumberParseFloat(GateRef gate, GateRef frameState);
    GateRef NumberParseInt(GateRef gate, GateRef radix);
    GateRef NumberIsFinite(GateRef gate);
    GateRef NumberIsInteger(GateRef gate);
    GateRef NumberIsSafeInteger(GateRef gate);
    GateRef ArrayBufferIsView(GateRef gate);
    GateRef DataViewGet(GateRef thisobj, GateRef index, GateRef dataViewCallID,
                        MachineType type, GateRef isLittleEndian, GateRef frameState);
    GateRef DataViewSet(GateRef thisobj,
                        GateRef index,
                        GateRef value,
                        GateRef dataViewCallID,
                        GateRef isLittleEndian,
                        GateRef frameState);
    GateRef ArrayIncludesIndexOf(
        GateRef elements, GateRef target, GateRef fromIndex, GateRef len, GateRef CallID, GateRef ArrayKind);
    GateRef ArrayIteratorBuiltin(GateRef thisArray, GateRef callID);
    GateRef ArrayForEach(GateRef thisValue, GateRef callBackFn, GateRef usingThis,
        GateRef frameState, uint32_t pcOffset);
    GateRef ArraySort(GateRef thisValue, GateRef callBackFn);
    GateRef ArrayFilter(
        GateRef thisValue, GateRef callBackFn, GateRef usingThis, GateRef frameState, uint32_t pcOffset);
    GateRef ArrayMap(GateRef thisValue, GateRef callBackFn, GateRef usingThis, GateRef frameState, uint32_t pcOffset);
    GateRef ArraySome(GateRef thisValue, GateRef callBackFn, GateRef usingThis, GateRef frameState, uint32_t pcOffset);
    GateRef ArrayFindOrFindIndex(GateRef thisValue, GateRef callBackFn,
        GateRef usingThis, GateRef callIDRef, GateRef frameState, uint32_t pcOffset);
    GateRef ArrayEvery(GateRef thisValue, GateRef callBackFn, GateRef usingThis, GateRef frameState, uint32_t pcOffset);
    GateRef ArrayPop(GateRef thisValue, GateRef frameState);
    GateRef ArrayPush(GateRef thisValue, GateRef value);
    GateRef ArraySlice(GateRef thisValue, GateRef startIndex, GateRef endIndex, GateRef frameState);
    GateRef ToNumber(GateRef gate, GateRef value, GateRef glue);
    GateRef StringToNumber(GateRef gate, GateRef value, GateRef radix, GateRef glue);
    GateRef IsASCIICharacter(GateRef gate);

    // for in
    inline GateRef GetEnumCacheKindFromEnumCache(GateRef enumCache);
    inline GateRef GetEnumCacheOwnFromEnumCache(GateRef glue, GateRef enumCache);
    inline GateRef GetEnumCacheAllFromEnumCache(GateRef glue, GateRef enumCache);
    inline GateRef GetProtoChainInfoEnumCacheFromEnumCache(GateRef glue, GateRef enumCache);

    GateRef IsEnumCacheValid(GateRef glue, GateRef receiver, GateRef cachedHclass, GateRef kind);
    GateRef NeedCheckProperty(GateRef glue, GateRef receiver);

    // ElementsKind Array
    GateRef MigrateFromRawValueToHeapValues(GateRef object, GateRef needCOW, GateRef isIntKind);
    GateRef MigrateFromHeapValueToRawValue(GateRef object, GateRef needCOW, GateRef isIntKind);
    GateRef MigrateFromHoleIntToHoleNumber(GateRef object);
    GateRef MigrateFromHoleNumberToHoleInt(GateRef object);

    // **************************** Low IR *******************************
    inline GateRef Equal(GateRef x, GateRef y, const char* comment = nullptr);
    inline GateRef NotEqual(GateRef x, GateRef y, const char* comment = nullptr);
    inline GateRef IntPtrAdd(GateRef x, GateRef y);
    inline GateRef IntPtrSub(GateRef x, GateRef y);
    inline GateRef IntPtrMul(GateRef x, GateRef y);
    inline GateRef IntPtrDiv(GateRef x, GateRef y);
    inline GateRef IntPtrOr(GateRef x, GateRef y);
    inline GateRef IntPtrLSL(GateRef x, GateRef y);
    inline GateRef IntPtrLSR(GateRef x, GateRef y);
    inline GateRef Int64NotEqual(GateRef x, GateRef y);
    inline GateRef Int32NotEqual(GateRef x, GateRef y);
    inline GateRef Int64Equal(GateRef x, GateRef y);
    inline GateRef Int8Equal(GateRef x, GateRef y);
    inline GateRef Int32Equal(GateRef x, GateRef y);
    inline GateRef IntPtrLessThan(GateRef x, GateRef y);
    inline GateRef IntPtrLessThanOrEqual(GateRef x, GateRef y);
    inline GateRef IntPtrGreaterThan(GateRef x, GateRef y);
    inline GateRef IntPtrGreaterThanOrEqual(GateRef x, GateRef y);
    inline GateRef IntPtrAnd(GateRef x, GateRef y);
    inline GateRef IntPtrNot(GateRef x);
    inline GateRef IntPtrEqual(GateRef x, GateRef y);
    GateRef DoubleTrunc(GateRef glue, GateRef gate, GateRef value, const char* comment = nullptr);
    GateRef AddWithOverflow(GateRef left, GateRef right);
    GateRef SubWithOverflow(GateRef left, GateRef right);
    GateRef MulWithOverflow(GateRef left, GateRef right);
    GateRef ExtractValue(MachineType mt, GateRef pointer, GateRef index);
    GateRef Sqrt(GateRef param);
    MachineType GetMachineTypeOfValueType(ValueType type);
    GateRef Alloca(size_t size);
    GateRef ReadSp();
    GateRef ReadReserveRegister();
    GateRef BinaryArithmetic(const GateMetaData* meta, MachineType machineType, GateRef left,
                             GateRef right, GateType gateType = GateType::Empty(), const char* comment = nullptr);
    GateRef BinaryCmp(const GateMetaData* meta, GateRef left, GateRef right, const char* comment = nullptr);

    GateRef NeedSkipReadBarrier(GateRef glue);

    GateRef NotSwitchToStwStub(GateRef glue);
    // Load
    GateRef Load(VariableType type, GateRef glue, GateRef base, GateRef offset,
        MemoryAttribute mAttr = MemoryAttribute::NeedBarrier());
    GateRef Load(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef depend,
        MemoryAttribute mAttr = MemoryAttribute::NeedBarrier());

    // LoadWithoutBarrier
    GateRef LoadWithoutBarrier(VariableType type, GateRef base, GateRef offset,
        MemoryAttribute mAttr = MemoryAttribute::Default());
    GateRef LoadWithoutBarrier(VariableType type, GateRef base, GateRef offset, GateRef depend,
        MemoryAttribute mAttr = MemoryAttribute::Default());
    GateRef LoadFromAddressWithoutBarrier(VariableType type, GateRef addr,
        MemoryAttribute mAttr = MemoryAttribute::Default());

    void Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value,
               MemoryAttribute mAttr = MemoryAttribute::Default());
    GateRef FetchOr(GateRef ptr, GateRef value, MemoryAttribute mAttr);
    GateRef AtomicCmpXchg(VariableType type, GateRef address, GateRef expected, GateRef desired);
    GateRef AtomicLoadAcquire(VariableType type, GateRef address);
    void StoreHClass(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value, GateRef compValue,
                     MemoryAttribute mAttr = MemoryAttribute::Default());
    void StoreWithoutBarrier(VariableType type, GateRef addr, GateRef value,
                             MemoryAttribute mAttr = MemoryAttribute::Default());
    GateRef ThreeInt64Min(GateRef first, GateRef second, GateRef third);

    // cast operation
    inline GateRef Int16ToBigEndianInt16(GateRef x);
    inline GateRef Int32ToBigEndianInt32(GateRef x);
    inline GateRef Int64ToBigEndianInt64(GateRef x);
    inline GateRef GetInt64OfTInt(GateRef x);
    inline GateRef GetInt32OfTInt(GateRef x);
    inline GateRef GetInt32OfTNumber(GateRef x);
    inline GateRef TaggedCastToIntPtr(GateRef x);
    inline GateRef GetDoubleOfTInt(GateRef x);
    inline GateRef GetDoubleOfTDouble(GateRef x);
    inline GateRef GetBooleanOfTBoolean(GateRef x);
    GateRef GetDoubleOfTNumber(GateRef x);
    GateRef TruncDoubleToInt(GateRef glue, GateRef x, size_t typeBits);
    GateRef DoubleToIntOverflowCheck(GateRef x, size_t typeBits);
    GateRef SaturateTruncDoubleToInt32(GateRef glue, GateRef x);
    GateRef DoubleCheckINFInRangeInt32(GateRef x);
    GateRef DoubleInRangeInt32(GateRef x);
    inline GateRef Int32ToTaggedPtr(GateRef x);
    inline GateRef Int64ToTaggedPtr(GateRef x);
    inline GateRef Int32ToTaggedInt(GateRef x);
    inline GateRef ToTaggedInt(GateRef x);
    inline GateRef ToTaggedIntPtr(GateRef x);
    inline GateRef DoubleToTaggedDoublePtr(GateRef x);
    inline GateRef DoubleIsImpureNaN(GateRef x);
    inline GateRef BooleanToTaggedBooleanPtr(GateRef x);
    inline GateRef BooleanToInt32(GateRef x);
    inline GateRef BooleanToFloat64(GateRef x);
    inline GateRef Float32ToTaggedDoublePtr(GateRef x);
    inline GateRef TaggedDoublePtrToFloat32(GateRef x);
    inline GateRef TaggedIntPtrToFloat32(GateRef x);
    inline GateRef DoubleToTaggedDouble(GateRef x);
    inline GateRef DoubleToTagged(GateRef x);
    inline GateRef DoubleIsNAN(GateRef x);
    inline GateRef DoubleIsINF(GateRef x);
    inline GateRef DoubleIsNanOrInf(GateRef x);
    GateRef DoubleIsWithinInt32(GateRef x);
    static MachineType GetMachineTypeFromVariableType(VariableType type);
    GateRef FastToBoolean(GateRef glue, GateRef value);

    // Opcode with control and depend inputs from label and value inputs args
    GateRef BuildControlDependOp(const GateMetaData* op, std::vector<GateRef> args,
                                 std::vector<GateRef> frameStates = {});
    template<OpCode Op, MachineType Type>
    inline GateRef BinaryOp(GateRef x, GateRef y);
    template<OpCode Op, MachineType Type>
    inline GateRef BinaryOpWithOverflow(GateRef x, GateRef y);

    GateRef BuildTypedArrayIterator(GateRef gate, const GateMetaData* op);
    GateRef IsStableArrayLengthWriteable(GateRef glue, GateRef array);

#define ARITHMETIC_BINARY_OP_WITH_BITWIDTH(NAME, OPCODEID, MACHINETYPEID)                                        \
    inline GateRef NAME(GateRef x, GateRef y, GateType type = GateType::Empty(), const char* comment = nullptr)  \
    {                                                                                                            \
        return BinaryArithmetic(circuit_->OPCODEID(), MACHINETYPEID, x, y, type, comment);                       \
    }

    BINARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH(ARITHMETIC_BINARY_OP_WITH_BITWIDTH)
#undef ARITHMETIC_BINARY_OP_WITH_BITWIDTH

#define ARITHMETIC_UNARY_OP_WITH_BITWIDTH(NAME, OPCODEID, MACHINETYPEID)                                     \
    inline GateRef NAME(GateRef x, const char* comment = nullptr)                                            \
    {                                                                                                        \
        return circuit_->NewGate(circuit_->OPCODEID(), MACHINETYPEID, { x }, GateType::NJSValue(), comment); \
    }

    UNARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH(ARITHMETIC_UNARY_OP_WITH_BITWIDTH)
#undef ARITHMETIC_UNARY_OP_WITH_BITWIDTH

#define DOUBLE_CMP_BINARY_OP(NAME, OPCODEID, CONDITION)                                          \
    inline GateRef NAME(GateRef x, GateRef y, const char* comment = nullptr)                     \
    {                                                                                            \
        return BinaryCmp(circuit_->OPCODEID(static_cast<uint64_t>(CONDITION)), x, y, comment);   \
    }

    DOUBLE_CMP_METHOD_LIST(DOUBLE_CMP_BINARY_OP)
#undef DOUBLE_CMP_BINARY_OP

#define INT8_CMP_BINARY_OP(NAME, OPCODEID, CONDITION)                                            \
    inline GateRef NAME(GateRef x, GateRef y, const char* comment = nullptr)                     \
    {                                                                                            \
        ASSERT(acc_.GetMachineType(x) == MachineType::I8);                                       \
        ASSERT(acc_.GetMachineType(y) == MachineType::I8);                                       \
        return BinaryCmp(circuit_->OPCODEID(static_cast<uint64_t>(CONDITION)), x, y, comment);   \
    }

    INT8_CMP_METHOD_LIST(INT8_CMP_BINARY_OP)
#undef INT8_CMP_BINARY_OP

// fixme: There are bugs in the AOT type conversion, INT32 CMP check temporarily no added
#define INT32_CMP_BINARY_OP(NAME, OPCODEID, CONDITION)                                           \
    inline GateRef NAME(GateRef x, GateRef y, const char* comment = nullptr)                     \
    {                                                                                            \
        return BinaryCmp(circuit_->OPCODEID(static_cast<uint64_t>(CONDITION)), x, y, comment);   \
    }

    INT32_CMP_METHOD_LIST(INT32_CMP_BINARY_OP)
#undef INT32_CMP_BINARY_OP

#define INT64_CMP_BINARY_OP(NAME, OPCODEID, CONDITION)                                           \
    inline GateRef NAME(GateRef x, GateRef y, const char* comment = nullptr)                     \
    {                                                                                            \
        ASSERT(acc_.GetMachineType(x) == MachineType::I64 ||                                     \
               acc_.GetMachineType(x) == MachineType::ARCH);                                     \
        ASSERT(acc_.GetMachineType(y) == MachineType::I64 ||                                     \
               acc_.GetMachineType(y) == MachineType::ARCH);                                     \
        return BinaryCmp(circuit_->OPCODEID(static_cast<uint64_t>(CONDITION)), x, y, comment);   \
    }

    INT64_CMP_METHOD_LIST(INT64_CMP_BINARY_OP)
#undef INT64_CMP_BINARY_OP

private:

    std::vector<GateRef> ConcatParams(const std::vector<std::vector<GateRef>>& params);
    static constexpr uint32_t GATE_TWO_VALUESIN = 2;

    inline void SetDepend(GateRef depend);
    inline void SetState(GateRef state);

    template <class LabelPtrGetter>
    void SwitchGeneric(GateRef index, Label *defaultLabel, Span<const int64_t> keysValue,
                       LabelPtrGetter getIthLabelFn);

#define ARITHMETIC_UNARY_OP_WITH_BITWIDTH(NAME, OPCODEID, MACHINETYPEID)                                     \
    inline GateRef NAME(GateRef x, const char* comment = nullptr)                                            \
    {                                                                                                        \
        return circuit_->NewGate(circuit_->OPCODEID(), MACHINETYPEID, { x }, GateType::NJSValue(), comment); \
    }

#undef ARITHMETIC_UNARY_OP_WITH_BITWIDTH

    Circuit *circuit_ {nullptr};
    GateAccessor acc_;
    Environment *env_ {nullptr};
    CompilationConfig *cmpCfg_ {nullptr};
    friend StubBuilder;
    friend BuiltinsStringStubBuilder;
    friend BuiltinsTypedArrayStubBuilder;
    friend TypedBytecodeLowering;
    friend NTypeBytecodeLowering;
    friend PGOHCRLowering;
    friend TSHCRLowering;
    friend NTypeHCRLowering;
    friend SlowPathLowering;
    friend NativeInlineLowering;
    friend TypedHCRLowering;
    friend TypedNativeInlineLowering;
    friend PostSchedule;
    friend TSHCROptPass;
    friend BuiltinLowering;
};

class LogicAndBuilder {
public:
    inline LogicAndBuilder(Environment *env);
    inline ~LogicAndBuilder();
    NO_MOVE_SEMANTIC(LogicAndBuilder);
    NO_COPY_SEMANTIC(LogicAndBuilder);

    inline LogicAndBuilder &And(GateRef check);

    inline GateRef Done();
private:
    Environment *env_ {nullptr};
    CircuitBuilder *builder_ {nullptr};
    Label *subentry_ {nullptr};
    Variable *result_ {nullptr};
    Label *exit_ {nullptr};
    std::vector<Label*> labels_;
};

class LogicOrBuilder {
public:
    inline LogicOrBuilder(Environment *env);
    inline ~LogicOrBuilder();
    NO_MOVE_SEMANTIC(LogicOrBuilder);
    NO_COPY_SEMANTIC(LogicOrBuilder);

    inline LogicOrBuilder &Or(GateRef check);

    inline GateRef Done();
private:
    Environment *env_ {nullptr};
    CircuitBuilder *builder_ {nullptr};
    Label *subentry_ {nullptr};
    Variable *result_ {nullptr};
    Label *exit_ {nullptr};
    std::vector<Label*> labels_;
};
}  // namespace panda::ecmascript::kungfu

#endif  // ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H