1/*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/compiler/codegen/llvm/llvm_ir_builder.h"
17
18#include <cmath>
19
20#include "ecmascript/compiler/argument_accessor.h"
21#include "ecmascript/compiler/bc_call_signature.h"
22#include "ecmascript/compiler/baseline/baseline_call_signature.h"
23#include "ecmascript/compiler/circuit.h"
24#include "ecmascript/compiler/call_signature.h"
25#include "ecmascript/compiler/debug_info.h"
26#include "ecmascript/compiler/gate.h"
27#include "ecmascript/compiler/share_gate_meta_data.h"
28#include "ecmascript/compiler/rt_call_signature.h"
29#include "ecmascript/compiler/baseline/baseline_stub_csigns.h"
30#include "ecmascript/deoptimizer/deoptimizer.h"
31#include "ecmascript/frames.h"
32#include "ecmascript/js_thread.h"
33#include "ecmascript/method.h"
34#include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h"
35
36#if defined(__clang__)
37#pragma clang diagnostic push
38#pragma clang diagnostic ignored "-Wshadow"
39#pragma clang diagnostic ignored "-Wunused-parameter"
40#pragma clang diagnostic ignored "-Wdeprecated-declarations"
41#elif defined(__GNUC__)
42#pragma GCC diagnostic push
43#pragma GCC diagnostic ignored "-Wshadow"
44#pragma GCC diagnostic ignored "-Wunused-parameter"
45#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
46#endif
47
48#include "llvm/IR/Instructions.h"
49#include "llvm/IR/Intrinsics.h"
50#include "llvm/IR/IRBuilder.h"
51
52#if defined(__clang__)
53#pragma clang diagnostic pop
54#elif defined(__GNUC__)
55#pragma GCC diagnostic pop
56#endif
57
58#include "llvm/Support/Host.h"
59#include "securec.h"
60
61namespace panda::ecmascript::kungfu {
62LLVMIRBuilder::LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit,
63                             LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg,
64                             CallSignature::CallConv callConv, bool enableLog, bool isFastCallAot,
65                             const std::string &funcName, bool enableOptInlining, bool enableBranchProfiling)
66    : compCfg_(cfg), scheduledGates_(schedule), circuit_(circuit), acc_(circuit), module_(module->GetModule()),
67      function_(function), llvmModule_(module), callConv_(callConv), enableLog_(enableLog),
68      isFastCallAot_(isFastCallAot), enableOptInlining_(enableOptInlining),
69      enableOptBranchProfiling_(enableBranchProfiling)
70{
71    ASSERT(compCfg_->Is64Bit());
72    context_ = module->GetContext();
73    builder_ = LLVMCreateBuilderInContext(context_);
74    bbID2BB_.clear();
75    SetFunctionCallConv();
76    InitializeHandlers();
77
78    LLVMSetGC(function_, "statepoint-example");
79    slotSize_ = sizeof(uint64_t);
80    slotType_ = GetInt64T();
81
82    LLVMMetadataRef dFile = llvmModule_->GetDFileMD();
83    LLVMMetadataRef funcTyMD = GetFunctionTypeMD(dFile);
84    size_t funcOffset = 0;
85    dFuncMD_ = LLVMDIBuilderCreateFunction(GetDIBuilder(), dFile, funcName.c_str(), funcName.size(),
86                                           funcName.c_str(), funcName.size(), dFile, funcOffset,
87                                           funcTyMD, true, true, 0, LLVMDIFlags::LLVMDIFlagZero, false);
88    LLVMSetSubprogram(function_, dFuncMD_);
89    std::string triple = LLVMGetTarget(module->GetModule());
90    ASSERT(GlobalTargetBuilders().count(triple) && "unsupported target");
91    targetBuilder_ = GlobalTargetBuilders()[triple]();
92    ASMBarrierCall_ = targetBuilder_->GetASMBarrierCall(module);
93}
94
95LLVMMetadataRef LLVMIRBuilder::GetFunctionTypeMD(LLVMMetadataRef dFile)
96{
97    LLVMDIBuilderRef builder = GetDIBuilder();
98    LLVMMetadataRef Int64Ty = LLVMDIBuilderCreateBasicType(builder, "Int64", 5, 64, 0, LLVMDIFlags::LLVMDIFlagZero);
99    LLVMMetadataRef paramT[] = { nullptr, Int64Ty }; // need to compute the real types for parameters in the future.
100    LLVMMetadataRef funcTy = LLVMDIBuilderCreateSubroutineType(builder, dFile, paramT, 2, LLVMDIFlags::LLVMDIFlagZero);
101    return funcTy;
102}
103
104LLVMIRBuilder::~LLVMIRBuilder()
105{
106    if (builder_ != nullptr) {
107        LLVMDisposeBuilder(builder_);
108        builder_ = nullptr;
109    }
110    delete targetBuilder_;
111}
112
113void LLVMIRBuilder::SetFunctionCallConv()
114{
115    switch (callConv_) {
116        case CallSignature::CallConv::GHCCallConv:
117            LLVMSetFunctionCallConv(function_, LLVMGHCCallConv);
118            break;
119        case CallSignature::CallConv::WebKitJSCallConv: {
120            LLVMSetFunctionCallConv(function_, LLVMWebKitJSCallConv);
121            break;
122        }
123        default: {
124            LLVMSetFunctionCallConv(function_, LLVMCCallConv);
125            callConv_ = CallSignature::CallConv::CCallConv;
126            break;
127        }
128    }
129}
130
131int LLVMIRBuilder::FindBasicBlock(GateRef gate) const
132{
133    for (size_t bbIdx = 0; bbIdx < scheduledGates_->size(); bbIdx++) {
134        const std::vector<GateRef>& bb = scheduledGates_->at(bbIdx);
135        for (size_t instIdx = bb.size(); instIdx > 0; instIdx--) {
136            GateRef tmp = bb[instIdx - 1];
137            if (tmp == gate) {
138                return bbIdx;
139            }
140        }
141    }
142    return -1;
143}
144
145void LLVMIRBuilder::InitializeHandlers()
146{
147    opHandlers_ = {
148        {OpCode::STATE_ENTRY, &LLVMIRBuilder::HandleGoto},
149        {OpCode::RETURN, &LLVMIRBuilder::HandleReturn},
150        {OpCode::RETURN_VOID, &LLVMIRBuilder::HandleReturnVoid},
151        {OpCode::IF_BRANCH, &LLVMIRBuilder::HandleBranch},
152        {OpCode::SWITCH_BRANCH, &LLVMIRBuilder::HandleSwitch},
153        {OpCode::ORDINARY_BLOCK, &LLVMIRBuilder::HandleGoto},
154        {OpCode::IF_TRUE, &LLVMIRBuilder::HandleGoto},
155        {OpCode::IF_FALSE, &LLVMIRBuilder::HandleGoto},
156        {OpCode::SWITCH_CASE, &LLVMIRBuilder::HandleGoto},
157        {OpCode::MERGE, &LLVMIRBuilder::HandleGoto},
158        {OpCode::DEFAULT_CASE, &LLVMIRBuilder::HandleGoto},
159        {OpCode::LOOP_BEGIN, &LLVMIRBuilder::HandleGoto},
160        {OpCode::LOOP_BACK, &LLVMIRBuilder::HandleGoto},
161        {OpCode::VALUE_SELECTOR, &LLVMIRBuilder::HandlePhi},
162        {OpCode::ASM_CALL_BARRIER, &LLVMIRBuilder::HandleCall},
163        {OpCode::RUNTIME_CALL, &LLVMIRBuilder::HandleRuntimeCall},
164        {OpCode::RUNTIME_CALL_WITH_ARGV, &LLVMIRBuilder::HandleRuntimeCallWithArgv},
165        {OpCode::NOGC_RUNTIME_CALL, &LLVMIRBuilder::HandleCall},
166        {OpCode::CALL_OPTIMIZED, &LLVMIRBuilder::HandleCall},
167        {OpCode::FAST_CALL_OPTIMIZED, &LLVMIRBuilder::HandleCall},
168        {OpCode::CALL, &LLVMIRBuilder::HandleCall},
169        {OpCode::BASELINE_CALL, &LLVMIRBuilder::HandleCall},
170        {OpCode::BYTECODE_CALL, &LLVMIRBuilder::HandleBytecodeCall},
171        {OpCode::DEBUGGER_BYTECODE_CALL, &LLVMIRBuilder::HandleBytecodeCall},
172        {OpCode::BUILTINS_CALL, &LLVMIRBuilder::HandleCall},
173        {OpCode::BUILTINS_CALL_WITH_ARGV, &LLVMIRBuilder::HandleCall},
174        {OpCode::ALLOCA, &LLVMIRBuilder::HandleAlloca},
175        {OpCode::ARG, &LLVMIRBuilder::HandleParameter},
176        {OpCode::CONSTANT, &LLVMIRBuilder::HandleConstant},
177        {OpCode::CONSTSTRING, &LLVMIRBuilder::HandleConstString},
178        {OpCode::RELOCATABLE_DATA, &LLVMIRBuilder::HandleRelocatableData},
179        {OpCode::ZEXT, &LLVMIRBuilder::HandleZExtInt},
180        {OpCode::SEXT, &LLVMIRBuilder::HandleSExtInt},
181        {OpCode::TRUNC, &LLVMIRBuilder::HandleCastIntXToIntY},
182        {OpCode::FEXT, &LLVMIRBuilder::HandleFPExt},
183        {OpCode::FTRUNC, &LLVMIRBuilder::HandleFPTrunc},
184        {OpCode::REV, &LLVMIRBuilder::HandleIntRev},
185        {OpCode::ADD, &LLVMIRBuilder::HandleAdd},
186        {OpCode::SUB, &LLVMIRBuilder::HandleSub},
187        {OpCode::MUL, &LLVMIRBuilder::HandleMul},
188        {OpCode::FDIV, &LLVMIRBuilder::HandleFloatDiv},
189        {OpCode::SDIV, &LLVMIRBuilder::HandleIntDiv},
190        {OpCode::UDIV, &LLVMIRBuilder::HandleUDiv},
191        {OpCode::AND, &LLVMIRBuilder::HandleIntAnd},
192        {OpCode::OR, &LLVMIRBuilder::HandleIntOr},
193        {OpCode::XOR, &LLVMIRBuilder::HandleIntXor},
194        {OpCode::LSR, &LLVMIRBuilder::HandleIntLsr},
195        {OpCode::ASR, &LLVMIRBuilder::HandleIntAsr},
196        {OpCode::ICMP, &LLVMIRBuilder::HandleCmp},
197        {OpCode::FCMP, &LLVMIRBuilder::HandleCmp},
198        {OpCode::LOAD, &LLVMIRBuilder::HandleLoad},
199        {OpCode::STORE_WITHOUT_BARRIER, &LLVMIRBuilder::HandleStore},
200        {OpCode::SIGNED_INT_TO_FLOAT, &LLVMIRBuilder::HandleChangeInt32ToDouble},
201        {OpCode::UNSIGNED_INT_TO_FLOAT, &LLVMIRBuilder::HandleChangeUInt32ToDouble},
202        {OpCode::FLOAT_TO_SIGNED_INT, &LLVMIRBuilder::HandleChangeDoubleToInt32},
203        {OpCode::TAGGED_TO_INT64, &LLVMIRBuilder::HandleChangeTaggedPointerToInt64},
204        {OpCode::INT64_TO_TAGGED, &LLVMIRBuilder::HandleChangeInt64ToTagged},
205        {OpCode::BITCAST, &LLVMIRBuilder::HandleBitCast},
206        {OpCode::LSL, &LLVMIRBuilder::HandleIntLsl},
207        {OpCode::SMOD, &LLVMIRBuilder::HandleMod},
208        {OpCode::FMOD, &LLVMIRBuilder::HandleMod},
209        {OpCode::DEOPT_CHECK, &LLVMIRBuilder::HandleDeoptCheck},
210        {OpCode::TRUNC_FLOAT_TO_INT64, &LLVMIRBuilder::HandleTruncFloatToInt},
211        {OpCode::TRUNC_FLOAT_TO_INT32, &LLVMIRBuilder::HandleTruncFloatToInt},
212        {OpCode::ADD_WITH_OVERFLOW, &LLVMIRBuilder::HandleAddWithOverflow},
213        {OpCode::SUB_WITH_OVERFLOW, &LLVMIRBuilder::HandleSubWithOverflow},
214        {OpCode::MUL_WITH_OVERFLOW, &LLVMIRBuilder::HandleMulWithOverflow},
215        {OpCode::EXTRACT_VALUE, &LLVMIRBuilder::HandleExtractValue},
216        {OpCode::SQRT, &LLVMIRBuilder::HandleSqrt},
217        {OpCode::EXP, &LLVMIRBuilder::HandleExp},
218        {OpCode::ABS, &LLVMIRBuilder::HandleAbs},
219        {OpCode::MIN, &LLVMIRBuilder::HandleMin},
220        {OpCode::MAX, &LLVMIRBuilder::HandleMax},
221        {OpCode::CLZ32, &LLVMIRBuilder::HandleClz32},
222        {OpCode::DOUBLE_TRUNC, &LLVMIRBuilder::HandleDoubleTrunc},
223        {OpCode::CEIL, &LLVMIRBuilder::HandleCeil},
224        {OpCode::FLOOR, &LLVMIRBuilder::HandleFloor},
225        {OpCode::READSP, &LLVMIRBuilder::HandleReadSp},
226        {OpCode::FINISH_ALLOCATE, &LLVMIRBuilder::HandleFinishAllocate},
227    };
228    illegalOpHandlers_ = {
229        OpCode::NOP, OpCode::CIRCUIT_ROOT, OpCode::DEPEND_ENTRY,
230        OpCode::DEAD, OpCode::RETURN_LIST,
231        OpCode::ARG_LIST, OpCode::THROW,
232        OpCode::DEPEND_SELECTOR, OpCode::DEPEND_RELAY,
233        OpCode::FRAME_STATE, OpCode::STATE_SPLIT, OpCode::FRAME_ARGS,
234        OpCode::LOOP_EXIT_DEPEND, OpCode::LOOP_EXIT,
235        OpCode::START_ALLOCATE, OpCode::FRAME_VALUES
236    };
237}
238
239std::string LLVMIRBuilder::LLVMValueToString(LLVMValueRef val) const
240{
241    char* msg = LLVMPrintValueToString(val);
242    std::string str(msg);
243    LLVMDisposeMessage(msg);
244    return str;
245}
246
247void LLVMIRBuilder::Build()
248{
249    for (size_t bbIdx = 0; bbIdx < scheduledGates_->size(); bbIdx++) {
250        const std::vector<GateRef>& bb = scheduledGates_->at(bbIdx);
251        for (size_t instIdx = bb.size(); instIdx > 0; instIdx--) {
252            GateId gateId = acc_.GetId(bb[instIdx - 1]);
253            instID2bbID_[gateId] = static_cast<int>(bbIdx);
254        }
255    }
256
257    for (size_t bbIdx = 0; bbIdx < scheduledGates_->size(); bbIdx++) {
258        const std::vector<GateRef>& bb = scheduledGates_->at(bbIdx);
259        OperandsVector predecessors;
260        auto ins = acc_.Ins(bb[0]);
261        for (auto i = ins.begin(); i != ins.end(); i++) {
262            GateRef r = *i;
263            if (!acc_.IsState(r)) {
264                continue;
265            }
266            predecessors.insert(instID2bbID_[acc_.GetId(r)]);
267        }
268        LinkToLLVMCfg(bbIdx, predecessors);
269
270        for (size_t instIdx = bb.size(); instIdx > 0; instIdx--) {
271            GateRef gate = bb[instIdx - 1];
272            auto found = opHandlers_.find(acc_.GetOpCode(gate));
273            if (found != opHandlers_.end()) {
274                (this->*(found->second))(gate);
275                continue;
276            }
277            if (illegalOpHandlers_.find(acc_.GetOpCode(gate)) == illegalOpHandlers_.end()) {
278                acc_.Print(gate);
279                LOG_COMPILER(FATAL) << "The gate below need to be translated ";
280                UNREACHABLE();
281            }
282        }
283    }
284    Finish();
285}
286
287BasicBlock *LLVMIRBuilder::EnsureBB(int id)
288{
289    BasicBlock *bb = nullptr;
290    if (bbID2BB_.count(id) == 0) {
291        auto newBB = std::make_unique<BasicBlock>(id);
292        bb = newBB.get();
293        bbID2BB_[id] = std::move(newBB);
294    } else {
295        bb = bbID2BB_[id].get();
296    }
297    return bb;
298}
299
300void LLVMIRBuilder::SetToCfg(BasicBlock *bb) const
301{
302    EnsureLBB(bb);
303    BasicBlockImpl *impl = bb->GetImpl<BasicBlockImpl>();
304    if ((impl == nullptr) || (impl->lBB_ == nullptr)) {
305        LOG_COMPILER(ERROR) << "SetToCfg failed ";
306        return;
307    }
308    impl->started = true;
309    bb->SetImpl(impl);
310    LLVMPositionBuilderAtEnd(builder_, impl->lBB_);
311}
312
313void LLVMIRBuilder::ProcessPhiWorkList()
314{
315    for (BasicBlock *bb : phiRebuildWorklist_) {
316        auto impl = bb->GetImpl<BasicBlockImpl>();
317        for (auto &e : impl->unmergedPhis_) {
318            ASSERT(bbID2BB_.count(e.predBBId) > 0);
319            BasicBlock *pred = bbID2BB_[e.predBBId].get();
320            if (!impl->started) {
321                OPTIONAL_LOG_COMPILER(ERROR) << " ProcessPhiWorkList error hav't start ";
322                return;
323            }
324            LLVMValueRef value = GetLValue(e.operand);
325            if (LLVMTypeOf(value) != LLVMTypeOf(e.phi)) {
326                OPTIONAL_LOG_COMPILER(ERROR) << " ProcessPhiWorkList LLVMTypeOf don't match error ";
327            }
328            LLVMBasicBlockRef llvmBB = EnsureLBB(pred);
329            LLVMAddIncoming(e.phi, &value, &llvmBB, 1);
330        }
331        impl->unmergedPhis_.clear();
332    }
333    phiRebuildWorklist_.clear();
334}
335
336void LLVMIRBuilder::EndCurrentBlock() const
337{
338    BasicBlockImpl *impl = currentBb_->GetImpl<BasicBlockImpl>();
339    impl->ended = true;
340}
341
342void LLVMIRBuilder::Finish()
343{
344    ASSERT(!!currentBb_);
345    EndCurrentBlock();
346    ProcessPhiWorkList();
347    for (auto &it : bbID2BB_) {
348        it.second->ResetImpl<BasicBlockImpl>();
349    }
350    LLVMDIBuilderFinalize(GetDIBuilder());
351}
352
353BasicBlockImpl *LLVMIRBuilder::EnsureBBImpl(BasicBlock *bb) const
354{
355    if (bb->GetImpl<BasicBlockImpl>()) {
356        return bb->GetImpl<BasicBlockImpl>();
357    }
358    auto impl = std::make_unique<BasicBlockImpl>();
359    bb->SetImpl(impl.release());
360    return bb->GetImpl<BasicBlockImpl>();
361}
362
363void LLVMIRBuilder::AssistGenPrologue(const size_t reservedSlotsSize, FrameType frameType)
364{
365    LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
366                                       std::to_string(reservedSlotsSize).c_str());
367    auto ArgList = circuit_->GetArgRoot();
368    auto uses = acc_.Uses(ArgList);
369    for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) {
370        int argth = static_cast<int>(acc_.TryGetValue(*useIt));
371        LLVMValueRef value = LLVMGetParam(function_, argth);
372        int funcIndex = 0;
373        if (isFastCallAot_) {
374            frameType = FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
375            funcIndex = static_cast<int>(FastCallArgIdx::FUNC);
376        } else {
377            funcIndex = static_cast<int>(CommonArgIdx::FUNC);
378        }
379        if (argth == funcIndex) {
380            SaveByteCodePcOnOptJSFuncFrame(value);
381            SaveJSFuncOnOptJSFuncFrame(value);
382            SaveFrameTypeOnFrame(frameType, builder_);
383        }
384    }
385}
386
387void LLVMIRBuilder::GenPrologue()
388{
389    auto frameType = circuit_->GetFrameType();
390    if (IsInterpreted()) {
391        return;
392    }
393    LLVMAddTargetDependentFunctionAttr(function_, "frame-pointer", "all");
394
395    size_t reservedSlotsSize = 0;
396    if (frameType == FrameType::OPTIMIZED_FRAME) {
397        reservedSlotsSize = OptimizedFrame::ComputeReservedSize(slotSize_);
398        LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
399                                           std::to_string(reservedSlotsSize).c_str());
400        SaveFrameTypeOnFrame(frameType, builder_);
401    } else if (frameType == FrameType::BASELINE_BUILTIN_FRAME) {
402        reservedSlotsSize = BaselineBuiltinFrame::ComputeReservedSize(slotSize_);
403        LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
404                                           std::to_string(reservedSlotsSize).c_str());
405        SaveFrameTypeOnFrame(frameType, builder_);
406    } else if (frameType == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
407        reservedSlotsSize = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
408        LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
409                                           std::to_string(reservedSlotsSize).c_str());
410        auto ArgList = circuit_->GetArgRoot();
411        auto uses = acc_.Uses(ArgList);
412        for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) {
413            int argth = static_cast<int>(acc_.TryGetValue(*useIt));
414            LLVMValueRef value = LLVMGetParam(function_, argth);
415            int funcIndex = 0;
416            if (isFastCallAot_) {
417                frameType = FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME;
418                funcIndex = static_cast<int>(FastCallArgIdx::FUNC);
419            } else {
420                funcIndex = static_cast<int>(CommonArgIdx::FUNC);
421            }
422            if (argth == funcIndex) {
423                SaveJSFuncOnOptJSFuncFrame(value);
424                SaveFrameTypeOnFrame(frameType, builder_);
425            }
426        }
427    } else if (frameType == FrameType::FASTJIT_FUNCTION_FRAME) {
428        reservedSlotsSize = FASTJITFunctionFrame::ComputeReservedPcOffset(slotSize_);
429        AssistGenPrologue(reservedSlotsSize, frameType);
430    } else {
431        LOG_COMPILER(FATAL) << "frameType interpret type error !";
432        ASSERT_PRINT(static_cast<uintptr_t>(frameType), "is not support !");
433    }
434}
435
436void LLVMIRBuilder::SaveByteCodePcOnOptJSFuncFrame(LLVMValueRef value)
437{
438    ASSERT(circuit_->GetFrameType() == FrameType::FASTJIT_FUNCTION_FRAME);
439    // load method
440    LLVMValueRef func = LLVMBuildPtrToInt(builder_, value, slotType_, "cast_to_i64");
441    LLVMValueRef offsetMethod = LLVMConstInt(GetInt64T(), JSFunctionBase::METHOD_OFFSET, false);
442    LLVMValueRef addrMethod = LLVMBuildAdd(builder_, func, offsetMethod, "");
443    LLVMValueRef methodPtr = LLVMBuildIntToPtr(builder_, addrMethod, GetTaggedPtrT(), "");
444    LLVMValueRef method = LLVMBuildLoad(builder_, methodPtr, "");
445    // load byteCodePc
446    LLVMValueRef offsetByteCodePc = LLVMConstInt(GetInt64T(), Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET, false);
447    LLVMValueRef addrByteCodePc = LLVMBuildAdd(builder_, method, offsetByteCodePc, "");
448    LLVMValueRef byteCodePcPtr = LLVMBuildIntToPtr(builder_, addrByteCodePc, GetTaggedPtrT(), "");
449    LLVMValueRef byteCodePc = LLVMBuildLoad(builder_, byteCodePcPtr, "");
450    // push byteCodePc
451    LLVMValueRef llvmFpAddr = CallingFp(module_, builder_, false);
452    LLVMValueRef frameAddr = LLVMBuildPtrToInt(builder_, llvmFpAddr, slotType_, "cast_int_t");
453    size_t reservedOffset = FASTJITFunctionFrame::ComputeReservedPcOffset(slotSize_);
454    LLVMValueRef byteCodePcSlotAddr = LLVMBuildSub(builder_, frameAddr, LLVMConstInt(slotType_,
455        reservedOffset, false), "");
456    LLVMValueRef byteCodePcAddr = LLVMBuildIntToPtr(builder_, byteCodePcSlotAddr,
457        LLVMPointerType(slotType_, 0), "byteCodePc.Addr");
458    LLVMBuildStore(builder_, byteCodePc, byteCodePcAddr);
459}
460
461void LLVMIRBuilder::SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder)
462{
463    LLVMValueRef llvmFpAddr = CallingFp(module_, builder, false);
464
465    LLVMValueRef frameAddr = LLVMBuildPtrToInt(builder, llvmFpAddr, slotType_, "cast_int_t");
466    LLVMValueRef frameTypeSlotAddr = LLVMBuildSub(builder, frameAddr, LLVMConstInt(slotType_, slotSize_, false), "");
467    LLVMValueRef addr = LLVMBuildIntToPtr(builder, frameTypeSlotAddr, LLVMPointerType(slotType_, 0), "frameType.Addr");
468    LLVMValueRef llvmFrameType = LLVMConstInt(slotType_, static_cast<uintptr_t>(frameType), 0);
469    LLVMBuildStore(builder, llvmFrameType, addr);
470}
471
472LLVMValueRef LLVMIRBuilder::CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller)
473{
474    if (IsInterpreted()) {
475        return LLVMGetParam(function_, static_cast<unsigned>(InterpreterHandlerInputs::SP));
476    }
477    /* 0:calling 1:its caller */
478    std::vector<LLVMValueRef> args = {LLVMConstInt(GetInt32T(), 0, isCaller)};
479    auto fn = LLVMGetNamedFunction(module, "llvm.frameaddress.p0i8");
480    if (!fn) {
481        /* init instrinsic function declare */
482        LLVMTypeRef paramTys1[] = { GetInt32T() };
483        auto fnTy = LLVMFunctionType(GetRawPtrT(), paramTys1, 1, 0);
484        fn = LLVMAddFunction(module, "llvm.frameaddress.p0i8", fnTy);
485    }
486    LLVMValueRef fAddrRet = LLVMBuildCall(builder, fn, args.data(), 1, "");
487    return fAddrRet;
488}
489
490LLVMValueRef LLVMIRBuilder::ReadRegister(LLVMModuleRef &module, [[maybe_unused]] LLVMBuilderRef &builder,
491    LLVMMetadataRef meta)
492{
493    std::vector<LLVMValueRef> args = {LLVMMetadataAsValue(context_, meta)};
494    auto fn = LLVMGetNamedFunction(module, "llvm.read_register.i64");
495    if (!fn) {
496        /* init instrinsic function declare */
497        LLVMTypeRef paramTys1[] = {
498            GetMachineRepType(MachineRep::K_META),
499        };
500        auto fnTy = LLVMFunctionType(GetInt64T(), paramTys1, 1, 0);
501        fn = LLVMAddFunction(module, "llvm.read_register.i64", fnTy);
502    }
503    LLVMValueRef fAddrRet = LLVMBuildCall(builder_, fn, args.data(), 1, "");
504    return fAddrRet;
505}
506
507LLVMBasicBlockRef LLVMIRBuilder::EnsureLBB(BasicBlock *bb) const
508{
509    BasicBlockImpl *impl = EnsureBBImpl(bb);
510    ASSERT(impl != nullptr);
511    if (impl->lBB_) {
512        return impl->lBB_;
513    }
514
515    std::string buf = "B" + std::to_string(bb->GetId());
516    LLVMBasicBlockRef llvmBB = LLVMAppendBasicBlockInContext(context_, function_, buf.c_str());
517    impl->lBB_ = llvmBB;
518    impl->continuation = llvmBB;
519    bb->SetImpl(impl);
520    return llvmBB;
521}
522
523LLVMTypeRef LLVMIRBuilder::GetMachineRepType(MachineRep rep) const
524{
525    LLVMTypeRef dstType;
526    switch (rep) {
527        case MachineRep::K_BIT:
528            dstType = GetInt1T();
529            break;
530        case MachineRep::K_WORD8:
531            dstType = GetInt8T();
532            break;
533        case MachineRep::K_WORD16:
534            dstType = GetInt16T();
535            break;
536        case MachineRep::K_WORD32:
537            dstType = GetInt32T();
538            break;
539        case MachineRep::K_FLOAT64:
540            dstType = GetDoubleT();
541            break;
542        case MachineRep::K_WORD64:
543            dstType = GetInt64T();
544            break;
545        case MachineRep::K_PTR_1:
546            dstType = GetTaggedHPtrT();
547            break;
548        case MachineRep::K_META:
549            dstType = LLVMMetadataTypeInContext(context_);
550            break;
551        default:
552            LOG_ECMA(FATAL) << "this branch is unreachable";
553            UNREACHABLE();
554            break;
555    }
556    return dstType;
557}
558
559void LLVMIRBuilder::HandleReadSp(GateRef gate)
560{
561    ASSERT(acc_.GetOpCode(gate) == OpCode::READSP);
562    VisitReadSp(gate);
563}
564
565void LLVMIRBuilder::HandleCall(GateRef gate)
566{
567    std::vector<GateRef> ins;
568    acc_.GetIns(gate, ins);
569    OpCode callOp = acc_.GetOpCode(gate);
570    if (callOp == OpCode::CALL || callOp == OpCode::NOGC_RUNTIME_CALL ||
571        callOp == OpCode::BUILTINS_CALL || callOp == OpCode::BUILTINS_CALL_WITH_ARGV ||
572        callOp == OpCode::CALL_OPTIMIZED || callOp == OpCode::FAST_CALL_OPTIMIZED ||
573        callOp == OpCode::BASELINE_CALL || callOp == OpCode::ASM_CALL_BARRIER) {
574        VisitCall(gate, ins, callOp);
575    } else {
576        LOG_ECMA(FATAL) << "this branch is unreachable";
577        UNREACHABLE();
578    }
579}
580
581void LLVMIRBuilder::HandleBytecodeCall(GateRef gate)
582{
583    std::vector<GateRef> ins;
584    acc_.GetIns(gate, ins);
585    VisitBytecodeCall(gate, ins);
586}
587
588void LLVMIRBuilder::HandleRuntimeCall(GateRef gate)
589{
590    std::vector<GateRef> ins;
591    acc_.GetIns(gate, ins);
592    VisitRuntimeCall(gate, ins);
593}
594
595LLVMValueRef LLVMIRBuilder::GetFunction(LLVMValueRef glue, const CallSignature *signature,
596                                        LLVMValueRef rtbaseoffset, const std::string &realName) const
597{
598    LLVMTypeRef rtfuncType = llvmModule_->GetFuncType(signature);
599    LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0);
600    LLVMTypeRef glueType = LLVMTypeOf(glue);
601    LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, rtbaseoffset, LLVMPointerType(glueType, 0), "");
602    std::string name = realName.empty()
603            ? signature->GetName()
604            : realName;
605    LLVMValueRef llvmAddr = LLVMBuildLoad(builder_, rtbaseAddr, name.c_str());
606    LLVMValueRef callee = LLVMBuildIntToPtr(builder_, llvmAddr, rtfuncTypePtr, (name + "-cast").c_str());
607    ASSERT(callee != nullptr);
608    return callee;
609}
610
611LLVMValueRef LLVMIRBuilder::GetFunctionFromGlobalValue([[maybe_unused]] LLVMValueRef glue,
612    const CallSignature *signature, LLVMValueRef reloc) const
613{
614    LLVMTypeRef rtfuncType = llvmModule_->GetFuncType(signature);
615    LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0);
616    LLVMValueRef callee = LLVMBuildIntToPtr(builder_, reloc, rtfuncTypePtr, "cast");
617    assert(callee != nullptr);
618    return callee;
619}
620
621bool LLVMIRBuilder::IsInterpreted() const
622{
623    return circuit_->GetFrameType() == FrameType::ASM_INTERPRETER_FRAME;
624}
625
626bool LLVMIRBuilder::IsBaselineBuiltin() const
627{
628    return circuit_->GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME;
629}
630
631bool LLVMIRBuilder::IsOptimized() const
632{
633    return circuit_->GetFrameType() == FrameType::OPTIMIZED_FRAME;
634}
635
636bool LLVMIRBuilder::IsOptimizedJSFunction() const
637{
638    return circuit_->GetFrameType() == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
639        circuit_->GetFrameType() == FrameType::FASTJIT_FUNCTION_FRAME;
640}
641
642void LLVMIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &inList)
643{
644    ASSERT(llvmModule_ != nullptr);
645    StubIdType stubId = RTSTUB_ID(CallRuntime);
646    LLVMValueRef glue = GetGlue(inList);
647    int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
648    LLVMValueRef rtoffset = GetRTStubOffset(glue, stubIndex);
649    LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
650    const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
651
652    auto kind = GetCallExceptionKind(stubIndex, OpCode::RUNTIME_CALL);
653
654    size_t actualNumArgs = 0;
655    LLVMValueRef pcOffset = LLVMConstInt(GetInt32T(), 0, 0);
656    GateRef frameArgs = Circuit::NullGate();
657    ComputeArgCountAndExtraInfo(actualNumArgs, pcOffset, frameArgs, inList, kind);
658
659    std::vector<LLVMValueRef> params;
660    params.push_back(glue); // glue
661    const int index = static_cast<int>(acc_.GetConstantValue(inList[static_cast<int>(CallInputs::TARGET)]));
662    params.push_back(LLVMConstInt(GetInt64T(), index, 0)); // target
663    params.push_back(LLVMConstInt(GetInt64T(),
664        actualNumArgs - static_cast<size_t>(CallInputs::FIRST_PARAMETER), 0)); // argc
665    for (size_t paraIdx = static_cast<size_t>(CallInputs::FIRST_PARAMETER); paraIdx < actualNumArgs; ++paraIdx) {
666        GateRef gateTmp = inList[paraIdx];
667        params.push_back(GetLValue(gateTmp));
668    }
669
670    LLVMTypeRef funcType = llvmModule_->GenerateFuncType(params, signature);
671    std::string targetName = RuntimeStubCSigns::GetRTName(index);
672    LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset, targetName);
673    callee = LLVMBuildPointerCast(builder_, callee, LLVMPointerType(funcType, 0), "");
674    LLVMValueRef runtimeCall = nullptr;
675    if (kind == CallExceptionKind::HAS_PC_OFFSET) {
676        std::vector<LLVMValueRef> values;
677        CollectExraCallSiteInfo(values, pcOffset, frameArgs);
678        runtimeCall = LLVMBuildCall3(builder_, funcType, callee, params.data(), actualNumArgs,
679                                     "", values.data(), values.size());
680    } else {
681        runtimeCall = LLVMBuildCall2(builder_, funcType, callee, params.data(), actualNumArgs, "");
682    }
683    LLVMSetInstructionCallConv(runtimeCall, LLVMWebKitJSCallConv);
684    if (RuntimeStubCSigns::IsCold(index)) {
685        unsigned ColdAttrKind = LLVMGetEnumAttributeKindForName(COLD_ATTR.data(), COLD_ATTR.size());
686        LLVMAttributeRef ColdAttribute = LLVMCreateEnumAttribute(context_, ColdAttrKind, 0);
687        LLVMAddCallSiteAttribute(runtimeCall, LLVMAttributeFunctionIndex, ColdAttribute);
688    }
689    Bind(gate, runtimeCall);
690
691    if (IsLogEnabled()) {
692        SetDebugInfo(gate, runtimeCall);
693    }
694}
695
696bool LLVMIRBuilder::SetDebugInfo(GateRef g, LLVMValueRef r)
697{
698    if (r != nullptr) {
699        LLVMValueKind k = LLVMGetValueKind(r);
700        if (k == LLVMInstructionValueKind) {
701            std::string comment = acc_.ToString(g);
702            circuit_->AddComment(g, std::move(comment));
703            size_t index = 0;
704            circuit_->GetDebugInfo(g, index);
705            LLVMMetadataRef loc = LLVMDIBuilderCreateDebugLocation(context_, index + 1, 0, dFuncMD_, NULL);
706            LLVMInstructionSetDebugLoc(r, loc);
707            return true;
708        }
709    }
710    return false;
711}
712
713void LLVMIRBuilder::HandleRuntimeCallWithArgv(GateRef gate)
714{
715    std::vector<GateRef> ins;
716    acc_.GetIns(gate, ins);
717    VisitRuntimeCallWithArgv(gate, ins);
718}
719
720void LLVMIRBuilder::VisitRuntimeCallWithArgv(GateRef gate, const std::vector<GateRef> &inList)
721{
722    ASSERT(IsOptimized() == true);
723    StubIdType stubId = RTSTUB_ID(CallRuntimeWithArgv);
724    LLVMValueRef glue = GetGlue(inList);
725    int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
726    LLVMValueRef rtoffset = GetRTStubOffset(glue, stubIndex);
727    LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
728    const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
729    LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
730
731    std::vector<LLVMValueRef> params;
732    params.push_back(glue); // glue
733
734    uint64_t index = acc_.GetConstantValue(inList[static_cast<size_t>(CallInputs::TARGET)]);
735    auto targetId = LLVMConstInt(GetInt64T(), index, 0);
736    params.push_back(targetId); // target
737    for (size_t paraIdx = static_cast<size_t>(CallInputs::FIRST_PARAMETER); paraIdx < inList.size(); ++paraIdx) {
738        GateRef gateTmp = inList[paraIdx];
739        params.push_back(GetLValue(gateTmp));
740    }
741
742    LLVMTypeRef funcType = llvmModule_->GenerateFuncType(params, signature);
743    callee = LLVMBuildPointerCast(builder_, callee, LLVMPointerType(funcType, 0), "");
744    LLVMValueRef runtimeCall = LLVMBuildCall2(builder_, funcType, callee, params.data(), inList.size() - 1, "");
745    Bind(gate, runtimeCall);
746
747    if (IsLogEnabled()) {
748        SetDebugInfo(gate, runtimeCall);
749    }
750}
751
752LLVMValueRef LLVMIRBuilder::GetCurrentSP()
753{
754    LLVMMetadataRef meta;
755    if (compCfg_->IsAmd64()) {
756        meta = LLVMMDStringInContext2(context_, "rsp", 4);   // 4 : 4 means len of "rsp"
757    } else {
758        meta = LLVMMDStringInContext2(context_, "sp", 3);   // 3 : 3 means len of "sp"
759    }
760    LLVMMetadataRef metadataNode = LLVMMDNodeInContext2(context_, &meta, 1);
761    LLVMValueRef spValue = ReadRegister(module_, builder_, metadataNode);
762    return spValue;
763}
764
765LLVMValueRef LLVMIRBuilder::GetCurrentFrameType(LLVMValueRef currentSpFrameAddr)
766{
767    LLVMValueRef tmp = LLVMBuildSub(builder_, currentSpFrameAddr, LLVMConstInt(slotType_, slotSize_, 1), "");
768    LLVMValueRef frameTypeAddr =
769        LLVMBuildIntToPtr(builder_, tmp, LLVMPointerType(GetInt64T(), 0), "");
770    LLVMValueRef frameType = LLVMBuildLoad(builder_, frameTypeAddr, "");
771    return frameType;
772}
773
774void LLVMIRBuilder::SetGCLeafFunction(LLVMValueRef call)
775{
776    const char *attrName = "gc-leaf-function";
777    const char *attrValue = "true";
778    LLVMAttributeRef llvmAttr = LLVMCreateStringAttribute(context_, attrName, strlen(attrName), attrValue,
779                                                          strlen(attrValue));
780    LLVMAddCallSiteAttribute(call, LLVMAttributeFunctionIndex, llvmAttr);
781}
782
783void LLVMIRBuilder::SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call)
784{
785    ASSERT(calleeDescriptor != nullptr);
786    if (calleeDescriptor->GetCallConv() == CallSignature::CallConv::GHCCallConv) {
787        LLVMSetTailCall(call, true);
788        SetGCLeafFunction(call);
789        LLVMSetInstructionCallConv(call, LLVMGHCCallConv);
790    } else if (calleeDescriptor->GetCallConv() == CallSignature::CallConv::WebKitJSCallConv) {
791        LLVMSetInstructionCallConv(call, LLVMWebKitJSCallConv);
792    }
793    if (calleeDescriptor->GetTailCall()) {
794        LLVMSetTailCall(call, true);
795    }
796    if (calleeDescriptor->GetGCLeafFunction()) {
797        SetGCLeafFunction(call);
798    }
799}
800
801bool LLVMIRBuilder::IsHeapPointerType(LLVMTypeRef valueType)
802{
803    return LLVMGetTypeKind(valueType) == LLVMPointerTypeKind && LLVMGetPointerAddressSpace(valueType) > 0;
804}
805
806LLVMValueRef LLVMIRBuilder::GetGlue(const std::vector<GateRef> &inList)
807{
808    auto g = inList.at(static_cast<size_t>(CallInputs::GLUE));
809    return GetLValue(g);
810}
811
812LLVMValueRef LLVMIRBuilder::GetLeaveFrameOffset(LLVMValueRef glue)
813{
814    LLVMTypeRef glueType = LLVMTypeOf(glue);
815    return LLVMConstInt(glueType,
816        static_cast<int>(JSThread::GlueData::GetLeaveFrameOffset(compCfg_->Is32Bit())), 0);
817}
818
819LLVMValueRef LLVMIRBuilder::GetRTStubOffset(LLVMValueRef glue, int index)
820{
821    LLVMTypeRef glueType = LLVMTypeOf(glue);
822    return LLVMConstInt(glueType,
823        static_cast<int>(JSThread::GlueData::GetRTStubEntriesOffset(compCfg_->Is32Bit())) + index * slotSize_, 0);
824}
825
826LLVMValueRef LLVMIRBuilder::GetCoStubOffset(LLVMValueRef glue, int index)
827{
828    LLVMTypeRef glueType = LLVMTypeOf(glue);
829    return LLVMConstInt(glueType, JSThread::GlueData::GetCOStubEntriesOffset(compCfg_->Is32Bit()) +
830        static_cast<size_t>(index * slotSize_), 0);
831}
832
833LLVMValueRef LLVMIRBuilder::GetBaselineStubOffset(LLVMValueRef glue, int index)
834{
835    LLVMTypeRef glueType = LLVMTypeOf(glue);
836    return LLVMConstInt(glueType, JSThread::GlueData::GetBaselineStubEntriesOffset(compCfg_->Is32Bit()) +
837                        static_cast<size_t>(index * slotSize_), 0);
838}
839
840LLVMValueRef LLVMIRBuilder::GetBCStubOffset(LLVMValueRef glue)
841{
842    LLVMTypeRef glueType = LLVMTypeOf(glue);
843    return LLVMConstInt(glueType, JSThread::GlueData::GetBCStubEntriesOffset(compCfg_->Is32Bit()), 0);
844}
845
846LLVMValueRef LLVMIRBuilder::GetBCDebugStubOffset(LLVMValueRef glue)
847{
848    LLVMTypeRef glueType = LLVMTypeOf(glue);
849    return LLVMConstInt(glueType, JSThread::GlueData::GetBCDebuggerStubEntriesOffset(compCfg_->Is32Bit()), 0);
850}
851
852LLVMValueRef LLVMIRBuilder::GetBuiltinsStubOffset(LLVMValueRef glue)
853{
854    LLVMTypeRef glueType = LLVMTypeOf(glue);
855    return LLVMConstInt(glueType, JSThread::GlueData::GetBuiltinsStubEntriesOffset(compCfg_->Is32Bit()), 0);
856}
857
858void LLVMIRBuilder::ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs,
859                                                const std::vector<GateRef> &inList, CallExceptionKind kind)
860{
861    if (kind == CallExceptionKind::HAS_PC_OFFSET) {
862        actualNumArgs = inList.size() - 2;  // 2: pcOffset and frameArgs
863        pcOffset = GetLValue(inList.at(actualNumArgs + 1));
864        frameArgs = inList.at(actualNumArgs);
865        ASSERT(acc_.GetOpCode(inList.at(actualNumArgs + 1)) == OpCode::CONSTANT);
866    } else {
867        actualNumArgs = inList.size();
868    }
869}
870
871CallExceptionKind LLVMIRBuilder::GetCallExceptionKind(size_t index, OpCode op) const
872{
873    bool hasPcOffset = IsOptimizedJSFunction() &&
874                       ((op == OpCode::NOGC_RUNTIME_CALL && (kungfu::RuntimeStubCSigns::IsAsmStub(index))) ||
875                        (op == OpCode::CALL) ||
876                        (op == OpCode::RUNTIME_CALL));
877    return hasPcOffset ? CallExceptionKind::HAS_PC_OFFSET : CallExceptionKind::NO_PC_OFFSET;
878}
879
880void LLVMIRBuilder::UpdateLeaveFrame(LLVMValueRef glue)
881{
882    LLVMValueRef leaveFrameOffset = GetLeaveFrameOffset(glue);
883    LLVMValueRef leaveFrameValue = LLVMBuildAdd(builder_, glue, leaveFrameOffset, "");
884    LLVMTypeRef glueType = LLVMTypeOf(glue);
885    LLVMValueRef leaveFrameAddr = LLVMBuildIntToPtr(builder_, leaveFrameValue, LLVMPointerType(glueType, 0), "");
886    LLVMValueRef llvmFpAddr = CallingFp(module_, builder_, true);
887    LLVMValueRef fp = LLVMBuildPtrToInt(builder_, llvmFpAddr, GetInt64T(), "cast_int64_t");
888    LLVMBuildStore(builder_, fp, leaveFrameAddr);
889}
890
891LLVMValueRef LLVMIRBuilder::GetCallee(const std::vector<GateRef> &inList, const CallSignature *signature,
892    const std::string &realName)
893{
894    LLVMTypeRef rtfuncType = llvmModule_->GetFuncType(signature);
895    LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0);
896
897    std::string name = realName.empty()
898            ? signature->GetName()
899            : realName;
900    LLVMValueRef code = GetLValue(inList.at(static_cast<size_t>(CallInputs::TARGET)));
901    LLVMValueRef callee = LLVMBuildIntToPtr(builder_, code, rtfuncTypePtr, (name + "-cast").c_str());
902    ASSERT(callee != nullptr);
903    return callee;
904}
905
906void LLVMIRBuilder::VisitReadSp(GateRef gate)
907{
908    LLVMValueRef spValue = GetCurrentSP();
909    Bind(gate, spValue);
910}
911
912void LLVMIRBuilder::CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset,
913                                            GateRef frameArgs)
914{
915    // pc offset
916    auto pcIndex = LLVMConstInt(GetInt64T(), static_cast<int>(SpecVregIndex::PC_OFFSET_INDEX), 1);
917    values.push_back(pcIndex);
918    values.push_back(pcOffset);
919
920    if (!enableOptInlining_) {
921        return;
922    }
923
924    if (frameArgs == Circuit::NullGate()) {
925        return;
926    }
927    if (acc_.GetOpCode(frameArgs) != OpCode::FRAME_ARGS) {
928        return;
929    }
930    uint32_t maxDepth = acc_.GetFrameDepth(frameArgs, OpCode::FRAME_ARGS);
931    if (maxDepth == 0) {
932        return;
933    }
934
935    maxDepth = std::min(maxDepth, MAX_METHOD_OFFSET_NUM);
936    size_t shift = Deoptimizier::ComputeShift(MAX_METHOD_OFFSET_NUM);
937    ArgumentAccessor argAcc(const_cast<Circuit *>(circuit_));
938    for (int32_t curDepth = static_cast<int32_t>(maxDepth - 1); curDepth >= 0; curDepth--) {
939        ASSERT(acc_.GetOpCode(frameArgs) == OpCode::FRAME_ARGS);
940        // method id
941        uint32_t methodOffset = acc_.TryGetMethodOffset(frameArgs);
942        frameArgs = acc_.GetFrameState(frameArgs);
943        if (methodOffset == FrameStateOutput::INVALID_INDEX) {
944            methodOffset = 0;
945        }
946        int32_t specCallTargetIndex = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) - curDepth;
947        int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(specCallTargetIndex, curDepth, shift);
948        values.emplace_back(LLVMConstInt(GetInt32T(), encodeIndex, false));
949        values.emplace_back(LLVMConstInt(GetInt32T(), methodOffset, false));
950    }
951}
952
953void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList, OpCode op)
954{
955    size_t targetIndex = static_cast<size_t>(CallInputs::TARGET);
956    static_assert(static_cast<size_t>(CallInputs::FIRST_PARAMETER) == 3);
957    const CallSignature *calleeDescriptor = nullptr;
958    LLVMValueRef glue = GetGlue(inList);
959    LLVMValueRef rtoffset;
960    LLVMValueRef rtbaseoffset;
961    LLVMValueRef callee;
962    CallExceptionKind kind = CallExceptionKind::NO_PC_OFFSET;
963    bool isNoGC = false;
964    if (op == OpCode::CALL) {
965        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
966        calleeDescriptor = CommonStubCSigns::Get(index);
967        rtoffset = GetCoStubOffset(glue, index);
968        rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
969        callee = GetFunction(glue, calleeDescriptor, rtbaseoffset);
970        kind = GetCallExceptionKind(index, op);
971    } else if (op == OpCode::NOGC_RUNTIME_CALL) {
972        UpdateLeaveFrame(glue);
973        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
974        calleeDescriptor = RuntimeStubCSigns::Get(index);
975        rtoffset = GetRTStubOffset(glue, index);
976        rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
977        callee = GetFunction(glue, calleeDescriptor, rtbaseoffset);
978        kind = GetCallExceptionKind(index, op);
979    } else if (op == OpCode::CALL_OPTIMIZED) {
980        calleeDescriptor = RuntimeStubCSigns::GetOptimizedCallSign();
981        callee = GetCallee(inList, calleeDescriptor);
982        if (IsOptimizedJSFunction()) {
983            kind = CallExceptionKind::HAS_PC_OFFSET;
984        } else {
985            kind = CallExceptionKind::NO_PC_OFFSET;
986        }
987        isNoGC = acc_.IsNoGC(gate);
988    } else if (op == OpCode::FAST_CALL_OPTIMIZED) {
989        calleeDescriptor = RuntimeStubCSigns::GetOptimizedFastCallSign();
990        callee = GetCallee(inList, calleeDescriptor);
991        if (IsOptimizedJSFunction()) {
992            kind = CallExceptionKind::HAS_PC_OFFSET;
993        } else {
994            kind = CallExceptionKind::NO_PC_OFFSET;
995        }
996        isNoGC = acc_.IsNoGC(gate);
997    } else if (op == OpCode::BASELINE_CALL) {
998        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
999        calleeDescriptor = BaselineStubCSigns::Get(index);
1000        rtoffset = GetBaselineStubOffset(glue, index);
1001        rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
1002        callee = GetFunction(glue, calleeDescriptor, rtbaseoffset);
1003        kind = GetCallExceptionKind(index, op);
1004    } else if (op == OpCode::ASM_CALL_BARRIER) {
1005        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
1006        calleeDescriptor = RuntimeStubCSigns::Get(index);
1007        rtoffset = GetRTStubOffset(glue, index);
1008        rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
1009        callee = GetFunction(glue, calleeDescriptor, rtbaseoffset);
1010        isNoGC = true;
1011    } else {
1012        ASSERT(op == OpCode::BUILTINS_CALL || op == OpCode::BUILTINS_CALL_WITH_ARGV);
1013        LLVMValueRef opcodeOffset = GetLValue(inList.at(targetIndex));
1014        rtoffset = GetBuiltinsStubOffset(glue);
1015        rtbaseoffset = LLVMBuildAdd(
1016            builder_, glue, LLVMBuildAdd(builder_, rtoffset, opcodeOffset, ""), "");
1017        if (op == OpCode::BUILTINS_CALL) {
1018            calleeDescriptor = BuiltinsStubCSigns::BuiltinsCSign();
1019        } else {
1020            calleeDescriptor = BuiltinsStubCSigns::BuiltinsWithArgvCSign();
1021        }
1022        callee = GetFunction(glue, calleeDescriptor, rtbaseoffset);
1023    }
1024
1025    std::vector<LLVMValueRef> params;
1026    const size_t firstArg = static_cast<size_t>(CallInputs::FIRST_PARAMETER);
1027    GateRef glueGate = inList[firstArg];
1028    params.push_back(GetLValue(glueGate));
1029
1030    // get parameter types
1031    LLVMTypeRef calleeFuncType = LLVMGetElementType(LLVMTypeOf(callee));
1032    std::vector<LLVMTypeRef> paramTypes(LLVMCountParamTypes(calleeFuncType));
1033    LLVMGetParamTypes(calleeFuncType, paramTypes.data());
1034
1035    int extraParameterCnt = 0;
1036    size_t actualNumArgs = 0;
1037    LLVMValueRef pcOffset = LLVMConstInt(GetInt32T(), 0, 0);
1038    GateRef frameArgs = Circuit::NullGate();
1039    ComputeArgCountAndExtraInfo(actualNumArgs, pcOffset, frameArgs, inList, kind);
1040    std::vector<CallSignature::ParamAttr> *paramAttr = calleeDescriptor->GetParamAttr();
1041    // then push the actual parameter for js function call
1042    for (size_t paraIdx = firstArg + 1; paraIdx < actualNumArgs; ++paraIdx) {
1043        GateRef gateTmp = inList[paraIdx];
1044        const auto gateTmpType = LLVMTypeOf(GetLValue(gateTmp));
1045        if (paramAttr != nullptr && params.size() < paramAttr->size() &&
1046            paramAttr->at(params.size()) == CallSignature::ParamAttr::Dead) {
1047            params.push_back(LLVMGetUndef(gateTmpType));
1048            continue;
1049        }
1050        if (params.size() < paramTypes.size()) {  // this condition will be false for variadic arguments
1051            const auto paramType = paramTypes.at(params.size());
1052            // match parameter types and function signature types
1053            if (IsHeapPointerType(paramType) && !IsHeapPointerType(gateTmpType)) {
1054                params.push_back(LLVMBuildIntToPtr(builder_,
1055                                                   LLVMBuildBitCast(builder_, GetLValue(gateTmp), GetInt64T(), ""),
1056                                                   paramType, ""));
1057            } else {
1058                params.push_back(LLVMBuildBitCast(builder_, GetLValue(gateTmp), paramType, ""));
1059            }
1060        } else {
1061            params.push_back(GetLValue(gateTmp));
1062        }
1063    }
1064
1065    LLVMValueRef call = nullptr;
1066    if (op == OpCode::ASM_CALL_BARRIER) {
1067        callee = LLVMBuildPointerCast(builder_, callee, llvmModule_->GetRawPtrT(), "");
1068        params.insert(params.begin(), callee);
1069        call = LLVMBuildCall(builder_, ASMBarrierCall_, params.data(), params.size(), "");
1070    } else {
1071        LLVMTypeRef funcType = llvmModule_->GenerateFuncType(params, calleeDescriptor);
1072        callee = LLVMBuildPointerCast(builder_, callee, LLVMPointerType(funcType, 0), "");
1073        if (kind == CallExceptionKind::HAS_PC_OFFSET) {
1074            std::vector<LLVMValueRef> values;
1075            CollectExraCallSiteInfo(values, pcOffset, frameArgs);
1076            call = LLVMBuildCall3(builder_, funcType, callee, params.data(), actualNumArgs - firstArg +
1077                extraParameterCnt, "", values.data(), values.size());
1078        } else {
1079            call = LLVMBuildCall2(builder_, funcType, callee, params.data(), actualNumArgs - firstArg +
1080                extraParameterCnt, "");
1081        }
1082        SetCallConvAttr(calleeDescriptor, call);
1083    }
1084    if (isNoGC) {
1085        SetGCLeafFunction(call);
1086    }
1087    Bind(gate, call);
1088
1089    if (IsLogEnabled()) {
1090        SetDebugInfo(gate, call);
1091    }
1092}
1093
1094void LLVMIRBuilder::VisitBytecodeCall(GateRef gate, const std::vector<GateRef> &inList)
1095{
1096    size_t paraStartIndex = static_cast<size_t>(CallInputs::FIRST_PARAMETER);
1097    size_t targetIndex = static_cast<size_t>(CallInputs::TARGET);
1098    size_t glueIndex = static_cast<size_t>(CallInputs::GLUE);
1099    LLVMValueRef opcodeOffset = GetLValue(inList.at(targetIndex));
1100    ASSERT(llvmModule_ != nullptr);
1101
1102    // start index of bytecode handler csign in llvmModule
1103    LLVMValueRef glue = GetLValue(inList.at(glueIndex));
1104    LLVMValueRef baseOffset = GetBaseOffset(gate, glue);
1105    LLVMValueRef rtbaseoffset = LLVMBuildAdd(
1106        builder_, glue, LLVMBuildAdd(builder_, baseOffset, opcodeOffset, ""), "");
1107    const CallSignature *signature = BytecodeStubCSigns::BCHandler();
1108    LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
1109
1110    std::vector<LLVMValueRef> params;
1111    for (size_t paraIdx = paraStartIndex; paraIdx < inList.size(); ++paraIdx) {
1112        GateRef gateTmp = inList[paraIdx];
1113        params.push_back(GetLValue(gateTmp));
1114    }
1115
1116    LLVMTypeRef funcType = llvmModule_->GenerateFuncType(params, signature);
1117    callee = LLVMBuildPointerCast(builder_, callee, LLVMPointerType(funcType, 0), "");
1118    LLVMValueRef call = LLVMBuildCall2(builder_, funcType, callee, params.data(), inList.size() - paraStartIndex, "");
1119    SetGCLeafFunction(call);
1120    LLVMSetTailCall(call, true);
1121    LLVMSetInstructionCallConv(call, LLVMGHCCallConv);
1122    Bind(gate, call);
1123
1124    if (IsLogEnabled()) {
1125        SetDebugInfo(gate, call);
1126    }
1127}
1128
1129LLVMValueRef LLVMIRBuilder::GetBaseOffset(GateRef gate, LLVMValueRef glue)
1130{
1131    switch (acc_.GetOpCode(gate)) {
1132        case OpCode::BYTECODE_CALL:
1133            return GetBCStubOffset(glue);
1134        case OpCode::DEBUGGER_BYTECODE_CALL:
1135            return GetBCDebugStubOffset(glue);
1136        default:
1137            LOG_ECMA(FATAL) << "this branch is unreachable";
1138            UNREACHABLE();
1139    }
1140}
1141
1142void LLVMIRBuilder::HandleAlloca(GateRef gate)
1143{
1144    return VisitAlloca(gate);
1145}
1146
1147void LLVMIRBuilder::VisitAlloca(GateRef gate)
1148{
1149    uint64_t machineRep = acc_.TryGetValue(gate);
1150    LLVMTypeRef dataType = GetMachineRepType(static_cast<MachineRep>(machineRep));
1151    auto lv = LLVMBuildPtrToInt(builder_,
1152                                LLVMBuildAlloca(builder_, dataType, ""),
1153                                ConvertLLVMTypeFromGate(gate), "");
1154    Bind(gate, lv);
1155}
1156
1157void LLVMIRBuilder::HandlePhi(GateRef gate)
1158{
1159    std::vector<GateRef> ins;
1160    acc_.GetIns(gate, ins);
1161    VisitPhi(gate, ins);
1162}
1163
1164int LLVMIRBuilder::LookupPredBB(GateRef start, int bbID)
1165{
1166    GateId gateId = acc_.GetId(start);
1167    int owner = instID2bbID_[gateId];
1168    if (owner != bbID) {
1169        return owner;
1170    }
1171    GateRef pred = start;
1172    while (owner == bbID) {
1173        pred = acc_.GetState(pred);
1174        auto id = acc_.GetId(pred);
1175        owner = instID2bbID_[id];
1176    }
1177    return owner;
1178}
1179
1180void LLVMIRBuilder::VisitPhi(GateRef gate, const std::vector<GateRef> &phiIns)
1181{
1182    LLVMTypeRef type = ConvertLLVMTypeFromGate(gate);
1183    LLVMValueRef phi = LLVMBuildPhi(builder_, type, "");
1184    if (phiIns.size() > 1) {
1185        Bind(gate, phi);
1186    }
1187    // Collect the states merges of this phi and note the 1-in is the merged states.
1188    std::vector<GateRef> phiStates;
1189    acc_.GetIns(phiIns.at(0), phiStates);
1190    ASSERT(phiStates.size() + 1 == phiIns.size());
1191    for (int i = 1; i < static_cast<int>(phiIns.size()); i++) {
1192        int bbIdx = LookupPredBB(phiStates.at(i - 1), currentBb_->GetId());
1193
1194        int cnt = static_cast<int>(bbID2BB_.count(bbIdx));
1195        // if cnt = 0 means bb with current bbIdx hasn't been created
1196        if (cnt > 0) {
1197            BasicBlock *bb = bbID2BB_[bbIdx].get();
1198            if (bb == nullptr) {
1199                OPTIONAL_LOG_COMPILER(ERROR) << "VisitPhi failed BasicBlock nullptr";
1200                return;
1201            }
1202            BasicBlockImpl *impl = bb->GetImpl<BasicBlockImpl>();
1203            if (impl == nullptr) {
1204                OPTIONAL_LOG_COMPILER(ERROR) << "VisitPhi failed impl nullptr";
1205                return;
1206            }
1207            LLVMBasicBlockRef llvmBB = EnsureLBB(bb);  // The llvm bb
1208            LLVMValueRef value = GetLValue(phiIns.at(i));
1209
1210            if (impl->started) {
1211                LLVMAddIncoming(phi, &value, &llvmBB, 1);
1212            } else {
1213                impl = currentBb_->GetImpl<BasicBlockImpl>();
1214                NotMergedPhiDesc d = { bbIdx, phiIns.at(i), phi };
1215                impl->unmergedPhis_.emplace_back(d);
1216                phiRebuildWorklist_.push_back(currentBb_);
1217            }
1218        } else {
1219            BasicBlockImpl* impl = currentBb_->GetImpl<BasicBlockImpl>();
1220            NotMergedPhiDesc d = { bbIdx, phiIns.at(i), phi };
1221            impl->unmergedPhis_.emplace_back(d);
1222            phiRebuildWorklist_.push_back(currentBb_);
1223        }
1224    }
1225}
1226
1227void LLVMIRBuilder::VisitReturn([[maybe_unused]] GateRef gate, [[maybe_unused]] GateRef popCount,
1228                                const std::vector<GateRef> &operands)
1229{
1230    // [STATE] [DEPEND] [VALUE] [RETURN_LIST]
1231    GateRef operand = operands[2];  // 2: skip 2 in gate that are not data gate
1232    LLVMValueRef returnValue = GetLValue(operand);
1233    LLVMBuildRet(builder_, returnValue);
1234
1235    if (IsLogEnabled()) {
1236        SetDebugInfo(gate, returnValue);
1237    }
1238}
1239
1240void LLVMIRBuilder::HandleReturn(GateRef gate)
1241{
1242    std::vector<GateRef> ins;
1243    acc_.GetIns(gate, ins);
1244    VisitReturn(gate, 1, ins);
1245}
1246
1247void LLVMIRBuilder::VisitReturnVoid([[maybe_unused]] GateRef gate)
1248{
1249    // [STATE] [DEPEND] [VALUE] [RETURN_LIST]
1250    LLVMBuildRetVoid(builder_);
1251}
1252
1253void LLVMIRBuilder::HandleReturnVoid(GateRef gate)
1254{
1255    VisitReturnVoid(gate);
1256}
1257
1258void LLVMIRBuilder::LinkToLLVMCfg(int bbId, const OperandsVector &predecessors)
1259{
1260    BasicBlock *bb = EnsureBB(bbId);
1261    if (bb == nullptr) {
1262        OPTIONAL_LOG_COMPILER(ERROR) << " block create failed ";
1263        return;
1264    }
1265    currentBb_ = bb;
1266    LLVMBasicBlockRef lBB = EnsureLBB(bb);
1267    SetToCfg(bb);
1268    for (int predecessor : predecessors) {
1269        BasicBlock *pre = EnsureBB(predecessor);
1270        if (pre == nullptr) {
1271            OPTIONAL_LOG_COMPILER(ERROR) << " block setup failed, predecessor:%d nullptr" << predecessor;
1272            return;
1273        }
1274        LLVMBasicBlockRef preLBB = EnsureLBB(pre);
1275        LLVMMoveBasicBlockBefore(preLBB, lBB);
1276    }
1277    if (IsPrologue(bbId)) {
1278        GenPrologue();
1279    }
1280}
1281
1282void LLVMIRBuilder::HandleGoto(GateRef gate)
1283{
1284    std::vector<GateRef> outs;
1285    acc_.GetOutStates(gate, outs);
1286    int block = instID2bbID_[acc_.GetId(gate)];
1287    switch (acc_.GetOpCode(gate)) {
1288        case OpCode::MERGE:
1289        case OpCode::LOOP_BEGIN: {
1290            for (const auto &out : outs) {
1291                int bbOut = instID2bbID_[acc_.GetId(out)];
1292                VisitGoto(block, bbOut);
1293            }
1294            break;
1295        }
1296        default: {
1297            int bbOut = instID2bbID_[acc_.GetId(outs[0])];
1298            VisitGoto(block, bbOut);
1299            break;
1300        }
1301    }
1302}
1303
1304void LLVMIRBuilder::VisitGoto(int block, int bbOut)
1305{
1306    if (block == bbOut) {
1307        return;
1308    }
1309    BasicBlock *bb = EnsureBB(bbOut);
1310    if (bb == nullptr) {
1311        OPTIONAL_LOG_COMPILER(ERROR) << " block is nullptr ";
1312        return;
1313    }
1314    llvm::BasicBlock *self = llvm::unwrap(EnsureLBB(bbID2BB_[block].get()));
1315    llvm::BasicBlock *out = llvm::unwrap(EnsureLBB(bbID2BB_[bbOut].get()));
1316    llvm::BranchInst::Create(out, self);
1317    EndCurrentBlock();
1318}
1319
1320void LLVMIRBuilder::HandleConstant(GateRef gate)
1321{
1322    std::bitset<64> value = acc_.GetConstantValue(gate); // 64: bit width
1323    VisitConstant(gate, value);
1324}
1325
1326void LLVMIRBuilder::VisitConstant(GateRef gate, std::bitset<64> value) // 64: bit width
1327{
1328    LLVMValueRef llvmValue = nullptr;
1329    auto machineType = acc_.GetMachineType(gate);
1330    if (machineType == MachineType::ARCH) {
1331        ASSERT(compCfg_->Is64Bit());
1332        machineType = MachineType::I64;
1333    }
1334    if (machineType == MachineType::I32) {
1335        llvmValue = LLVMConstInt(GetInt32T(), value.to_ulong(), 0);
1336    } else if (machineType == MachineType::I64) {
1337        llvmValue = LLVMConstInt(GetInt64T(), value.to_ullong(), 0);
1338        LLVMTypeRef type = ConvertLLVMTypeFromGate(gate);
1339        if (LLVMGetTypeKind(type) == LLVMPointerTypeKind) {
1340            llvmValue = LLVMBuildIntToPtr(builder_, llvmValue, type, "");
1341        } else if (LLVMGetTypeKind(type) == LLVMIntegerTypeKind) {
1342            // do nothing
1343        } else {
1344            LOG_ECMA(FATAL) << "this branch is unreachable";
1345            UNREACHABLE();
1346        }
1347    } else if (machineType == MachineType::F64) {
1348        auto doubleValue = base::bit_cast<double>(value.to_ullong()); // actual double value
1349        llvmValue = LLVMConstReal(GetDoubleT(), doubleValue);
1350    } else if (machineType == MachineType::I8) {
1351        llvmValue = LLVMConstInt(GetInt8T(), value.to_ulong(), 0);
1352    } else if (machineType == MachineType::I16) {
1353        llvmValue = LLVMConstInt(GetInt16T(), value.to_ulong(), 0);
1354    } else if (machineType == MachineType::I1) {
1355        llvmValue = LLVMConstInt(GetInt1T(), value.to_ulong(), 0);
1356    } else {
1357        LOG_ECMA(FATAL) << "this branch is unreachable";
1358        UNREACHABLE();
1359    }
1360    Bind(gate, llvmValue);
1361}
1362
1363void LLVMIRBuilder::HandleConstString(GateRef gate)
1364{
1365    const ChunkVector<char> &str = acc_.GetConstantString(gate); // 64: bit width
1366    VisitConstString(gate, str);
1367}
1368
1369void LLVMIRBuilder::VisitConstString(GateRef gate, const ChunkVector<char> &str) // 64: bit width
1370{
1371    ASSERT(acc_.GetMachineType(gate) == MachineType::ARCH);
1372    LLVMValueRef llvmValue1 = LLVMConstStringInContext(context_, str.data(), str.size(), 0);
1373    LLVMValueRef addr = LLVMBuildAlloca(builder_, LLVMTypeOf(llvmValue1), "");
1374    LLVMBuildStore(builder_, llvmValue1, addr);
1375    Bind(gate, addr);
1376}
1377
1378void LLVMIRBuilder::HandleRelocatableData(GateRef gate)
1379{
1380    uint64_t value = acc_.TryGetValue(gate);
1381    VisitRelocatableData(gate, value);
1382}
1383
1384void LLVMIRBuilder::VisitRelocatableData(GateRef gate, uint64_t value)
1385{
1386    LLVMValueRef globalValue = LLVMAddGlobal(module_, GetInt64T(), "G");
1387    LLVMSetInitializer(globalValue, LLVMConstInt(GetInt64T(), value, 0));
1388    Bind(gate, globalValue);
1389}
1390
1391void LLVMIRBuilder::HandleZExtInt(GateRef gate)
1392{
1393    std::vector<GateRef> ins;
1394    acc_.GetIns(gate, ins);
1395    VisitZExtInt(gate, ins[0]);
1396}
1397
1398void LLVMIRBuilder::HandleSExtInt(GateRef gate)
1399{
1400    std::vector<GateRef> ins;
1401    acc_.GetIns(gate, ins);
1402    VisitSExtInt(gate, ins[0]);
1403}
1404
1405void LLVMIRBuilder::HandleParameter(GateRef gate)
1406{
1407    return VisitParameter(gate);
1408}
1409
1410void LLVMIRBuilder::VisitParameter(GateRef gate)
1411{
1412    int argth = static_cast<int>(acc_.TryGetValue(gate));
1413    LLVMValueRef value = LLVMGetParam(function_, argth);
1414    ASSERT(LLVMTypeOf(value) == ConvertLLVMTypeFromGate(gate));
1415    Bind(gate, value);
1416    // NOTE: caller put args, otherwise crash
1417    ASSERT(value != nullptr);
1418}
1419
1420void LLVMIRBuilder::SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value)
1421{
1422    ASSERT(IsOptimizedJSFunction());
1423    size_t reservedOffset = 0;
1424    LLVMValueRef llvmFpAddr = CallingFp(module_, builder_, false);
1425    LLVMValueRef frameAddr = LLVMBuildPtrToInt(builder_, llvmFpAddr, slotType_, "cast_int_t");
1426    if (circuit_->GetFrameType() == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
1427        reservedOffset = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
1428    } else {
1429        reservedOffset = FASTJITFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
1430    }
1431    LLVMValueRef frameJSFuncSlotAddr = LLVMBuildSub(builder_, frameAddr, LLVMConstInt(slotType_,
1432        reservedOffset, false), "");
1433    LLVMValueRef jsFuncAddr = LLVMBuildIntToPtr(builder_, frameJSFuncSlotAddr,
1434        LLVMPointerType(slotType_, 0), "jsfunc.Addr");
1435    LLVMValueRef jsFuncValue = LLVMBuildPtrToInt(builder_, value, slotType_, "cast_to_i64");
1436    LLVMBuildStore(builder_, jsFuncValue, jsFuncAddr);
1437}
1438
1439void LLVMIRBuilder::HandleBranch(GateRef gate)
1440{
1441    std::vector<GateRef> ins;
1442    acc_.GetIns(gate, ins);
1443    std::vector<GateRef> outs;
1444    acc_.GetOutStates(gate, outs);
1445    GateRef bTrue = (acc_.GetOpCode(outs[0]) == OpCode::IF_TRUE) ? outs[0] : outs[1];
1446    GateRef bFalse = (acc_.GetOpCode(outs[0]) == OpCode::IF_FALSE) ? outs[0] : outs[1];
1447    int bbTrue = instID2bbID_[acc_.GetId(bTrue)];
1448    int bbFalse = instID2bbID_[acc_.GetId(bFalse)];
1449    VisitBranch(gate, ins[1], bbTrue, bbFalse);
1450}
1451
1452void LLVMIRBuilder::HandleMod(GateRef gate)
1453{
1454    auto g0 = acc_.GetIn(gate, 0);
1455    auto g1 = acc_.GetIn(gate, 1);
1456    VisitMod(gate, g0, g1);
1457}
1458
1459void LLVMIRBuilder::VisitMod(GateRef gate, GateRef e1, GateRef e2)
1460{
1461    LLVMValueRef e1Value = GetLValue(e1);
1462    LLVMValueRef e2Value = GetLValue(e2);
1463    LLVMValueRef result = nullptr;
1464    ASSERT(ConvertLLVMTypeFromGate(gate) == ConvertLLVMTypeFromGate(e1));
1465    ASSERT(ConvertLLVMTypeFromGate(gate) == ConvertLLVMTypeFromGate(e2));
1466    auto machineType = acc_.GetMachineType(gate);
1467    if (machineType == MachineType::I32) {
1468        result = LLVMBuildSRem(builder_, e1Value, e2Value, "");
1469    } else if (machineType == MachineType::F64) {
1470        result = LLVMBuildFRem(builder_, e1Value, e2Value, "");
1471    } else {
1472        LOG_ECMA(FATAL) << "this branch is unreachable";
1473        UNREACHABLE();
1474    }
1475    Bind(gate, result);
1476
1477    if (IsLogEnabled()) {
1478        SetDebugInfo(gate, result);
1479    }
1480}
1481
1482void LLVMIRBuilder::HandleFinishAllocate(GateRef gate)
1483{
1484    auto g0 = acc_.GetValueIn(gate, 0);
1485    VisitFinishAllocate(gate, g0);
1486}
1487
1488void LLVMIRBuilder::VisitFinishAllocate(GateRef gate, GateRef e1)
1489{
1490    LLVMValueRef result = GetLValue(e1);
1491    Bind(gate, result);
1492    if (IsLogEnabled()) {
1493        SetDebugInfo(gate, result);
1494    }
1495}
1496
1497void LLVMIRBuilder::VisitBranch(GateRef gate, GateRef cmp, int btrue, int bfalse)
1498{
1499    if (gate2LValue_.count(cmp) == 0) {
1500        OPTIONAL_LOG_COMPILER(ERROR) << "Branch condition gate is nullptr!";
1501        return;
1502    }
1503    LLVMValueRef cond = GetLValue(cmp);
1504
1505    BasicBlock *trueBB = EnsureBB(btrue);
1506    BasicBlock *falseBB = EnsureBB(bfalse);
1507    EnsureLBB(trueBB);
1508    EnsureLBB(falseBB);
1509
1510    LLVMBasicBlockRef llvmTrueBB = trueBB->GetImpl<BasicBlockImpl>()->lBB_;
1511    LLVMBasicBlockRef llvmFalseBB = falseBB->GetImpl<BasicBlockImpl>()->lBB_;
1512    LLVMValueRef result = LLVMBuildCondBr(builder_, cond, llvmTrueBB, llvmFalseBB);
1513    EndCurrentBlock();
1514
1515    if (enableOptBranchProfiling_ && acc_.HasBranchWeight(gate)) {
1516        auto trueWeight = acc_.GetTrueWeight(gate);
1517        auto falseWeight = acc_.GetFalseWeight(gate);
1518        LLVMMetadataRef branch_weights = LLVMMDStringInContext2(context_, "branch_weights", 14);
1519        LLVMMetadataRef weight1 = LLVMValueAsMetadata(LLVMConstInt(LLVMIntType(32), trueWeight, 0));
1520        LLVMMetadataRef weight2 = LLVMValueAsMetadata(LLVMConstInt(LLVMIntType(32), falseWeight, 0));
1521        LLVMMetadataRef mds[] = {branch_weights, weight1, weight2};
1522        LLVMMetadataRef metadata = LLVMMDNodeInContext2(context_, mds, 3);
1523        LLVMValueRef metadata_value = LLVMMetadataAsValue(context_, metadata);
1524        LLVMSetMetadata(result, LLVMGetMDKindID("prof", 4), metadata_value); // 4: length of "prof"
1525    }
1526    Bind(gate, result);
1527
1528    if (IsLogEnabled()) {
1529        SetDebugInfo(gate, result);
1530    }
1531}
1532
1533void LLVMIRBuilder::HandleSwitch(GateRef gate)
1534{
1535    std::vector<GateRef> ins;
1536    acc_.GetIns(gate, ins);
1537    std::vector<GateRef> outs;
1538    acc_.GetOutStates(gate, outs);
1539    VisitSwitch(gate, ins[1], outs);
1540}
1541
1542void LLVMIRBuilder::VisitSwitch(GateRef gate, GateRef input, const std::vector<GateRef> &outList)
1543{
1544    LLVMValueRef cond = GetLValue(input);
1545    int caseNum = static_cast<int>(outList.size());
1546    BasicBlock *curOutBB = nullptr;
1547    LLVMBasicBlockRef llvmDefaultOutBB = nullptr;
1548    for (int i = 0; i < caseNum; i++) {
1549        curOutBB = EnsureBB(instID2bbID_[acc_.GetId(outList[i])]);
1550        EnsureLBB(curOutBB);
1551        if (acc_.GetOpCode(outList[i]) == OpCode::DEFAULT_CASE) {
1552            llvmDefaultOutBB = curOutBB->GetImpl<BasicBlockImpl>()->lBB_;
1553        }
1554    }
1555    LLVMValueRef result = LLVMBuildSwitch(builder_, cond, llvmDefaultOutBB, static_cast<uint32_t>(caseNum - 1));
1556    LLVMBasicBlockRef llvmCurOutBB = nullptr;
1557    for (int i = 0; i < caseNum; i++) {
1558        if (acc_.GetOpCode(outList[i]) == OpCode::DEFAULT_CASE) {
1559            continue;
1560        }
1561        curOutBB = EnsureBB(instID2bbID_[acc_.GetId(outList[i])]);
1562        llvmCurOutBB = curOutBB->GetImpl<BasicBlockImpl>()->lBB_;
1563        LLVMAddCase(result, LLVMConstInt(ConvertLLVMTypeFromGate(input), acc_.TryGetValue(outList[i]), 0),
1564                    llvmCurOutBB);
1565    }
1566    EndCurrentBlock();
1567    Bind(gate, result);
1568
1569    if (IsLogEnabled()) {
1570        SetDebugInfo(gate, result);
1571    }
1572}
1573
1574unsigned LLVMIRBuilder::GetPtrAddressSpace(LLVMValueRef v) const
1575{
1576    auto ty = LLVMTypeOf(v);
1577    if (LLVMGetTypeKind(ty) == LLVMPointerTypeKind) {
1578        return LLVMGetPointerAddressSpace(ty);
1579    }
1580    return 0;
1581}
1582
1583void LLVMIRBuilder::VisitLoad(GateRef gate, GateRef base)
1584{
1585    LLVMValueRef baseAddr = GetLValue(base);
1586
1587    LLVMTypeRef returnType = ConvertLLVMTypeFromGate(gate);
1588    LLVMTypeRef memType = LLVMPointerType(returnType, GetPtrAddressSpace(baseAddr));
1589    baseAddr = CanonicalizeToPtr(baseAddr, memType);
1590
1591    LLVMValueRef result = LLVMBuildLoad(builder_, baseAddr, "");
1592    auto order = acc_.GetMemoryAttribute(gate);
1593    switch (order.GetOrder()) {
1594        case MemoryAttribute::MEMORY_ORDER_RELEASE: {
1595            LLVMSetOrdering(result, LLVMAtomicOrderingRelease);
1596            break;
1597        }
1598        case MemoryAttribute::NOT_ATOMIC: {
1599            break;
1600        }
1601        default: {
1602            UNREACHABLE();
1603            break;
1604        }
1605    }
1606    Bind(gate, result);
1607
1608    if (IsLogEnabled()) {
1609        SetDebugInfo(gate, result);
1610    }
1611}
1612
1613void LLVMIRBuilder::VisitStore(GateRef gate, GateRef base, GateRef value)
1614{
1615    LLVMValueRef baseAddr = GetLValue(base);
1616    LLVMValueRef data = GetLValue(value);
1617
1618    LLVMTypeRef returnType = ConvertLLVMTypeFromGate(value);
1619    LLVMTypeRef ptrType = LLVMPointerType(returnType, GetPtrAddressSpace(baseAddr));
1620    baseAddr = CanonicalizeToPtr(baseAddr, ptrType);
1621
1622    LLVMValueRef result = LLVMBuildStore(builder_, data, baseAddr);
1623    auto order = acc_.GetMemoryAttribute(gate);
1624    switch (order.GetOrder()) {
1625        case MemoryAttribute::MEMORY_ORDER_RELEASE: {
1626            LLVMSetOrdering(result, LLVMAtomicOrderingRelease);
1627            break;
1628        }
1629        case MemoryAttribute::NOT_ATOMIC: {
1630            break;
1631        }
1632        default: {
1633            UNREACHABLE();
1634            break;
1635        }
1636    }
1637    Bind(gate, result);
1638
1639    if (IsLogEnabled()) {
1640        SetDebugInfo(gate, result);
1641    }
1642}
1643
1644LLVMValueRef LLVMIRBuilder::CanonicalizeToInt(LLVMValueRef value) const
1645{
1646    if (LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind) {
1647        return LLVMBuildPtrToInt(builder_, value, GetInt64T(), "");
1648    } else if (LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMIntegerTypeKind) {
1649        return value;
1650    } else {
1651        LOG_COMPILER(FATAL) << "can't Canonicalize to Int64: ";
1652        UNREACHABLE();
1653    }
1654}
1655
1656LLVMValueRef LLVMIRBuilder::CanonicalizeToPtr(LLVMValueRef value, LLVMTypeRef ptrType) const
1657{
1658    LLVMTypeRef valueT = LLVMTypeOf(value);
1659    if (LLVMGetTypeKind(valueT) == LLVMPointerTypeKind) {
1660        if (valueT != ptrType) {
1661            return LLVMBuildPointerCast(builder_, value, ptrType, "");
1662        }
1663    } else if (LLVMGetTypeKind(valueT) == LLVMIntegerTypeKind) {
1664        LLVMValueRef result = LLVMBuildIntToPtr(builder_, value, ptrType, "");
1665        return result;
1666    } else {
1667        LOG_COMPILER(FATAL) << "can't Canonicalize to Ptr: ";
1668        UNREACHABLE();
1669    }
1670    return value;
1671}
1672
1673LLVMValueRef LLVMIRBuilder::CanonicalizeToPtr(LLVMValueRef value) const
1674{
1675    LLVMTypeRef valueT = LLVMTypeOf(value);
1676    if (LLVMGetTypeKind(valueT) == LLVMPointerTypeKind) {
1677        auto ptrType = LLVMPointerType(GetInt8T(), GetPtrAddressSpace(value));
1678        return LLVMBuildPointerCast(builder_, value, ptrType, "");
1679    } else if (LLVMGetTypeKind(valueT) == LLVMIntegerTypeKind) {
1680        LLVMValueRef result = LLVMBuildIntToPtr(builder_, value, GetRawPtrT(), "");
1681        return result;
1682    } else {
1683        LOG_COMPILER(FATAL) << "can't Canonicalize to Ptr: ";
1684        UNREACHABLE();
1685    }
1686}
1687
1688void LLVMIRBuilder::HandleIntRev(GateRef gate)
1689{
1690    std::vector<GateRef> ins;
1691    acc_.GetIns(gate, ins);
1692    VisitIntRev(gate, ins[0]);
1693}
1694
1695void LLVMIRBuilder::VisitIntRev(GateRef gate, GateRef e1)
1696{
1697    LLVMValueRef e1Value = GetLValue(e1);
1698    ASSERT(ConvertLLVMTypeFromGate(gate) == ConvertLLVMTypeFromGate(e1));
1699    auto machineType = acc_.GetMachineType(gate);
1700    LLVMValueRef result = nullptr;
1701    if (machineType <= MachineType::I64 && machineType >= MachineType::I1) {
1702        result = LLVMBuildNot(builder_, e1Value, "");
1703    } else {
1704        LOG_ECMA(FATAL) << "this branch is unreachable";
1705        UNREACHABLE();
1706    }
1707    Bind(gate, result);
1708
1709    if (IsLogEnabled()) {
1710        SetDebugInfo(gate, result);
1711    }
1712}
1713
1714bool LLVMIRBuilder::IsLInteger(LLVMValueRef v) const
1715{
1716    LLVMTypeRef r = LLVMTypeOf(v);
1717    return LLVMGetTypeKind(r) == LLVMIntegerTypeKind;
1718}
1719
1720bool LLVMIRBuilder::IsLPointer(LLVMValueRef v) const
1721{
1722    LLVMTypeRef r = LLVMTypeOf(v);
1723    return LLVMGetTypeKind(r) == LLVMPointerTypeKind;
1724}
1725
1726LLVMValueRef LLVMIRBuilder::PointerAdd(LLVMValueRef baseAddr, LLVMValueRef offsetInByte, LLVMTypeRef rep)
1727{
1728    LLVMValueRef ptr = CanonicalizeToPtr(baseAddr);
1729    LLVMValueRef dstRef8 = LLVMBuildGEP(builder_, ptr, &offsetInByte, 1, "");
1730    LLVMValueRef result = LLVMBuildPointerCast(builder_, dstRef8, rep, "");
1731    return result;
1732}
1733
1734LLVMTypeRef LLVMIRBuilder::ConvertLLVMTypeFromGate(GateRef gate) const
1735{
1736    if (acc_.IsGCRelated(gate)) {
1737        return GetTaggedHPtrT();
1738    }
1739    MachineType t = acc_.GetMachineType(gate);
1740    switch (t) {
1741        case MachineType::NOVALUE:
1742            return GetVoidT();
1743        case MachineType::I1:
1744            return GetInt1T();
1745        case MachineType::I8:
1746            return GetInt8T();
1747        case MachineType::I16:
1748            return GetInt16T();
1749        case MachineType::I32:
1750            return GetInt32T();
1751        case MachineType::I64:
1752            return GetInt64T();
1753        case MachineType::F32:
1754            return GetFloatT();
1755        case MachineType::F64:
1756            return GetDoubleT();
1757        case MachineType::ARCH: {
1758            return GetInt64T();
1759        }
1760        default:
1761            LOG_ECMA(FATAL) << "this branch is unreachable";
1762            UNREACHABLE();
1763    }
1764}
1765
1766int64_t LLVMIRBuilder::GetBitWidthFromMachineType(MachineType machineType) const
1767{
1768    switch (machineType) {
1769        case NOVALUE:
1770            return 0;
1771        case ARCH:
1772            return 48;  // 48: Pointer representation in different architectures
1773        case I1:
1774            return 1;
1775        case I8:
1776            return 8; // 8: bit width
1777        case I16:
1778            return 16; // 16: bit width
1779        case I32:
1780            return 32; // 32: bit width
1781        case I64:
1782            return 64; // 64: bit width
1783        case F32:
1784            return 32; // 32: bit width
1785        case F64:
1786            return 64; // 64: bit width
1787        case FLEX:
1788        case ANYVALUE:
1789            LOG_ECMA(FATAL) << "this branch is unreachable";
1790            UNREACHABLE();
1791        default:
1792            LOG_ECMA(FATAL) << "this branch is unreachable";
1793            UNREACHABLE();
1794    }
1795}
1796
1797void LLVMIRBuilder::HandleAdd(GateRef gate)
1798{
1799    auto g0 = acc_.GetIn(gate, 0);
1800    auto g1 = acc_.GetIn(gate, 1);
1801    VisitAdd(gate, g0, g1);
1802}
1803
1804void LLVMIRBuilder::HandleTruncFloatToInt(GateRef gate)
1805{
1806    auto g0 = acc_.GetIn(gate, 0);
1807    VisitTruncFloatToInt(gate, g0);
1808}
1809
1810void LLVMIRBuilder::VisitTruncFloatToInt(GateRef gate, GateRef e1)
1811{
1812    LLVMValueRef e1Value = GetLValue(e1);
1813    auto machineType = acc_.GetMachineType(e1);
1814    LLVMValueRef result = nullptr;
1815    if (machineType <= MachineType::F64 && machineType >= MachineType::F32) {
1816        result = LLVMBuildFPToSI(builder_, e1Value, ConvertLLVMTypeFromGate(gate), "");
1817    } else {
1818        LOG_ECMA(FATAL) << "this branch is unreachable";
1819        UNREACHABLE();
1820    }
1821    Bind(gate, result);
1822
1823    if (IsLogEnabled()) {
1824        SetDebugInfo(gate, result);
1825    }
1826}
1827
1828void LLVMIRBuilder::VisitAdd(GateRef gate, GateRef e1, GateRef e2)
1829{
1830    LLVMValueRef e1Value = GetLValue(e1);
1831    LLVMValueRef e2Value = GetLValue(e2);
1832    LLVMValueRef result = nullptr;
1833
1834    LLVMTypeRef returnType = ConvertLLVMTypeFromGate(gate);
1835    auto machineType = acc_.GetMachineType(gate);
1836    if (IsAddIntergerType(machineType)) {
1837        auto e1Type = LLVMGetTypeKind(ConvertLLVMTypeFromGate(e1));
1838        if (e1Type == LLVMPointerTypeKind) {
1839            result = PointerAdd(e1Value, e2Value, returnType);
1840        } else {
1841            LLVMValueRef tmp1Value = LLVMBuildIntCast2(builder_, e1Value, returnType, 0, "");
1842            LLVMValueRef tmp2Value = LLVMBuildIntCast2(builder_, e2Value, returnType, 0, "");
1843            result = LLVMBuildAdd(builder_, tmp1Value, tmp2Value, "");
1844            if (LLVMTypeOf(tmp1Value) != LLVMTypeOf(tmp2Value)) {
1845                ASSERT(LLVMTypeOf(tmp1Value) == LLVMTypeOf(tmp2Value));
1846            }
1847        }
1848    } else if (machineType == MachineType::F64) {
1849        result = LLVMBuildFAdd(builder_, e1Value, e2Value, "");
1850    } else {
1851        LOG_ECMA(FATAL) << "this branch is unreachable";
1852        UNREACHABLE();
1853    }
1854    Bind(gate, result);
1855
1856    if (IsLogEnabled()) {
1857        SetDebugInfo(gate, result);
1858    }
1859}
1860
1861void LLVMIRBuilder::HandleSub(GateRef gate)
1862{
1863    auto g0 = acc_.GetIn(gate, 0);
1864    auto g1 = acc_.GetIn(gate, 1);
1865    VisitSub(gate, g0, g1);
1866}
1867
1868void LLVMIRBuilder::VisitSub(GateRef gate, GateRef e1, GateRef e2)
1869{
1870    LLVMValueRef e1Value = GetLValue(e1);
1871    LLVMValueRef e2Value = GetLValue(e2);
1872    LLVMValueRef result = nullptr;
1873    auto machineType = acc_.GetMachineType(gate);
1874    if (machineType == MachineType::I16 || machineType == MachineType::I32 ||
1875        machineType == MachineType::I64 || machineType == MachineType::ARCH) {
1876        result = LLVMBuildSub(builder_, e1Value, e2Value, "");
1877    } else if (machineType == MachineType::F64) {
1878        result = LLVMBuildFSub(builder_, e1Value, e2Value, "");
1879    } else {
1880        LOG_ECMA(FATAL) << "this branch is unreachable";
1881        UNREACHABLE();
1882    }
1883    Bind(gate, result);
1884
1885    if (IsLogEnabled()) {
1886        SetDebugInfo(gate, result);
1887    }
1888}
1889
1890void LLVMIRBuilder::HandleMul(GateRef gate)
1891{
1892    auto g0 = acc_.GetIn(gate, 0);
1893    auto g1 = acc_.GetIn(gate, 1);
1894    VisitMul(gate, g0, g1);
1895}
1896
1897void LLVMIRBuilder::VisitMul(GateRef gate, GateRef e1, GateRef e2)
1898{
1899    LLVMValueRef e1Value = GetLValue(e1);
1900    LLVMValueRef e2Value = GetLValue(e2);
1901    LLVMValueRef result = nullptr;
1902    auto machineType = acc_.GetMachineType(gate);
1903    if (IsMulIntergerType(machineType)) {
1904        result = LLVMBuildMul(builder_, e1Value, e2Value, "");
1905    } else if (machineType == MachineType::F64) {
1906        result = LLVMBuildFMul(builder_, e1Value, e2Value, "");
1907    } else {
1908        LOG_ECMA(FATAL) << "this branch is unreachable";
1909        UNREACHABLE();
1910    }
1911    Bind(gate, result);
1912
1913    if (IsLogEnabled()) {
1914        SetDebugInfo(gate, result);
1915    }
1916}
1917
1918void LLVMIRBuilder::HandleFloatDiv(GateRef gate)
1919{
1920    auto g0 = acc_.GetIn(gate, 0);
1921    auto g1 = acc_.GetIn(gate, 1);
1922    VisitFloatDiv(gate, g0, g1);
1923}
1924
1925void LLVMIRBuilder::HandleIntDiv(GateRef gate)
1926{
1927    auto g0 = acc_.GetIn(gate, 0);
1928    auto g1 = acc_.GetIn(gate, 1);
1929    VisitIntDiv(gate, g0, g1);
1930}
1931
1932void LLVMIRBuilder::HandleUDiv(GateRef gate)
1933{
1934    auto g0 = acc_.GetIn(gate, 0);
1935    auto g1 = acc_.GetIn(gate, 1);
1936    VisitUDiv(gate, g0, g1);
1937}
1938
1939void LLVMIRBuilder::HandleIntOr(GateRef gate)
1940{
1941    auto g0 = acc_.GetIn(gate, 0);
1942    auto g1 = acc_.GetIn(gate, 1);
1943    VisitIntOr(gate, g0, g1);
1944}
1945
1946void LLVMIRBuilder::HandleIntXor(GateRef gate)
1947{
1948    auto g0 = acc_.GetIn(gate, 0);
1949    auto g1 = acc_.GetIn(gate, 1);
1950    VisitIntXor(gate, g0, g1);
1951}
1952
1953void LLVMIRBuilder::HandleIntLsr(GateRef gate)
1954{
1955    auto g0 = acc_.GetIn(gate, 0);
1956    auto g1 = acc_.GetIn(gate, 1);
1957    VisitIntLsr(gate, g0, g1);
1958}
1959
1960void LLVMIRBuilder::HandleIntAsr(GateRef gate)
1961{
1962    auto g0 = acc_.GetIn(gate, 0);
1963    auto g1 = acc_.GetIn(gate, 1);
1964    VisitIntAsr(gate, g0, g1);
1965}
1966
1967void LLVMIRBuilder::HandleCmp(GateRef gate)
1968{
1969    GateRef left = acc_.GetIn(gate, 0);
1970    GateRef right = acc_.GetIn(gate, 1);
1971    VisitCmp(gate, left, right);
1972}
1973
1974void LLVMIRBuilder::HandleAddWithOverflow(GateRef gate)
1975{
1976    GateRef left = acc_.GetIn(gate, 0);
1977    GateRef right = acc_.GetIn(gate, 1);
1978    ASSERT(acc_.GetMachineType(left) == MachineType::I32);
1979    ASSERT(acc_.GetMachineType(right) == MachineType::I32);
1980    VisitAddWithOverflow(gate, left, right);
1981}
1982
1983void LLVMIRBuilder::VisitAddWithOverflow(GateRef gate, GateRef e1, GateRef e2)
1984{
1985    LLVMValueRef e1Value = GetLValue(e1);
1986    LLVMValueRef e2Value = GetLValue(e2);
1987    std::vector<LLVMValueRef> args = { e1Value, e2Value };
1988    auto fn = LLVMGetNamedFunction(module_, "llvm.sadd.with.overflow.i32");
1989    if (!fn) {
1990        /* init instrinsic function declare */
1991        LLVMTypeRef paramTys1[] = { GetInt32T(), GetInt32T() };
1992        LLVMTypeRef structTys[] = { GetInt32T(), GetInt1T() };
1993        LLVMTypeRef returnType = LLVMStructTypeInContext(context_, structTys, 2, 0);
1994        auto fnTy = LLVMFunctionType(returnType, paramTys1, 2, 0);
1995        fn = LLVMAddFunction(module_, "llvm.sadd.with.overflow.i32", fnTy);
1996    }
1997    LLVMValueRef result = LLVMBuildCall(builder_, fn, args.data(), 2, "");
1998    Bind(gate, result);
1999
2000    if (IsLogEnabled()) {
2001        SetDebugInfo(gate, result);
2002    }
2003}
2004
2005void LLVMIRBuilder::HandleSubWithOverflow(GateRef gate)
2006{
2007    GateRef left = acc_.GetIn(gate, 0);
2008    GateRef right = acc_.GetIn(gate, 1);
2009    ASSERT(acc_.GetMachineType(left) == MachineType::I32);
2010    ASSERT(acc_.GetMachineType(right) == MachineType::I32);
2011    VisitSubWithOverflow(gate, left, right);
2012}
2013
2014void LLVMIRBuilder::VisitSubWithOverflow(GateRef gate, GateRef e1, GateRef e2)
2015{
2016    LLVMValueRef e1Value = GetLValue(e1);
2017    LLVMValueRef e2Value = GetLValue(e2);
2018    std::vector<LLVMValueRef> args = { e1Value, e2Value };
2019    auto fn = LLVMGetNamedFunction(module_, "llvm.ssub.with.overflow.i32");
2020    if (!fn) {
2021        /* init instrinsic function declare */
2022        LLVMTypeRef paramTys1[] = { GetInt32T(), GetInt32T() };
2023        LLVMTypeRef structTys[] = { GetInt32T(), GetInt1T() };
2024        LLVMTypeRef returnType = LLVMStructTypeInContext(context_, structTys, 2, 0);
2025        auto fnTy = LLVMFunctionType(returnType, paramTys1, 2, 0);
2026        fn = LLVMAddFunction(module_, "llvm.ssub.with.overflow.i32", fnTy);
2027    }
2028    LLVMValueRef result = LLVMBuildCall(builder_, fn, args.data(), 2, "");
2029    Bind(gate, result);
2030
2031    if (IsLogEnabled()) {
2032        SetDebugInfo(gate, result);
2033    }
2034}
2035
2036void LLVMIRBuilder::HandleMulWithOverflow(GateRef gate)
2037{
2038    GateRef left = acc_.GetIn(gate, 0);
2039    GateRef right = acc_.GetIn(gate, 1);
2040    ASSERT(acc_.GetMachineType(left) == MachineType::I32);
2041    ASSERT(acc_.GetMachineType(right) == MachineType::I32);
2042    VisitMulWithOverflow(gate, left, right);
2043}
2044
2045void LLVMIRBuilder::VisitMulWithOverflow(GateRef gate, GateRef e1, GateRef e2)
2046{
2047    LLVMValueRef e1Value = GetLValue(e1);
2048    LLVMValueRef e2Value = GetLValue(e2);
2049    std::vector<LLVMValueRef> args = { e1Value, e2Value };
2050    auto fn = LLVMGetNamedFunction(module_, "llvm.smul.with.overflow.i32");
2051    if (!fn) {
2052        /* init instrinsic function declare */
2053        LLVMTypeRef paramTys1[] = { GetInt32T(), GetInt32T() };
2054        LLVMTypeRef structTys[] = { GetInt32T(), GetInt1T() };
2055        LLVMTypeRef returnType = LLVMStructTypeInContext(context_, structTys, 2, 0);
2056        auto fnTy = LLVMFunctionType(returnType, paramTys1, 2, 0);
2057        fn = LLVMAddFunction(module_, "llvm.smul.with.overflow.i32", fnTy);
2058    }
2059    LLVMValueRef result = LLVMBuildCall(builder_, fn, args.data(), 2, "");
2060    Bind(gate, result);
2061
2062    if (IsLogEnabled()) {
2063        SetDebugInfo(gate, result);
2064    }
2065}
2066
2067void LLVMIRBuilder::HandleExtractValue(GateRef gate)
2068{
2069    GateRef pointer = acc_.GetIn(gate, 0);
2070    GateRef index = acc_.GetIn(gate, 1);
2071    VisitExtractValue(gate, pointer, index);
2072}
2073
2074void LLVMIRBuilder::VisitExtractValue(GateRef gate, GateRef e1, GateRef e2)
2075{
2076    LLVMValueRef e1Value = GetLValue(e1);
2077    ASSERT((acc_.GetOpCode(e2) == OpCode::CONSTANT) && acc_.GetMachineType(e2) == MachineType::I32);
2078    uint32_t index = static_cast<uint32_t>(acc_.GetConstantValue(e2));
2079    LLVMValueRef result = LLVMBuildExtractValue(builder_, e1Value, index, "");
2080    Bind(gate, result);
2081
2082    if (IsLogEnabled()) {
2083        SetDebugInfo(gate, result);
2084    }
2085}
2086
2087void LLVMIRBuilder::HandleSqrt(GateRef gate)
2088{
2089    GateRef param = acc_.GetIn(gate, 0);
2090    VisitSqrt(gate, param);
2091}
2092
2093void LLVMIRBuilder::VisitSqrt(GateRef gate, GateRef e1)
2094{
2095    LLVMValueRef e1Value = GetLValue(e1);
2096    std::vector<LLVMValueRef> args = { e1Value };
2097    auto fn = LLVMGetNamedFunction(module_, "llvm.sqrt.f64");
2098    if (!fn) {
2099        /* init instrinsic function declare */
2100        LLVMTypeRef paramTys1[] = { GetDoubleT() };
2101        auto fnTy = LLVMFunctionType(GetDoubleT(), paramTys1, 1, 0);
2102        fn = LLVMAddFunction(module_, "llvm.sqrt.f64", fnTy);
2103    }
2104    LLVMValueRef result = LLVMBuildCall(builder_, fn, args.data(), 1, "");
2105    Bind(gate, result);
2106
2107    if (IsLogEnabled()) {
2108        SetDebugInfo(gate, result);
2109    }
2110}
2111
2112void LLVMIRBuilder::HandleExp(GateRef gate)
2113{
2114    GateRef base = acc_.GetIn(gate, 0U);
2115    GateRef power = acc_.GetIn(gate, 1U);
2116    VisitExp(gate, base, power);
2117}
2118
2119void LLVMIRBuilder::VisitExp([[maybe_unused]] GateRef gate, [[maybe_unused]] GateRef e1, [[maybe_unused]] GateRef e2)
2120{
2121#ifdef SUPPORT_LLVM_INTRINSICS_WITH_CALLS
2122    llvm::Value *e1Value = llvm::unwrap(GetLValue(e1));
2123    llvm::Value *e2Value = llvm::unwrap(GetLValue(e2));
2124
2125    [[maybe_unused]] auto machineType = acc_.GetMachineType(gate);
2126    ASSERT(machineType == MachineType::F64);
2127    ASSERT(acc_.GetMachineType(e1) == machineType);
2128    ASSERT(acc_.GetMachineType(e2) == machineType);
2129
2130    llvm::Value *result = nullptr;
2131
2132    constexpr double one = 1.0;
2133    if (acc_.IsConstant(e1) && acc_.GetFloat64FromConstant(e1) == std::exp(one)) {
2134        llvm::Intrinsic::ID llvmId = llvm::Intrinsic::exp;
2135        result = llvm::unwrap(builder_)->CreateUnaryIntrinsic(llvmId, e2Value);
2136    } else {
2137        llvm::Intrinsic::ID llvmId = llvm::Intrinsic::pow;
2138        result = llvm::unwrap(builder_)->CreateBinaryIntrinsic(llvmId, e1Value, e2Value);
2139    }
2140#else
2141    UNREACHABLE();
2142#endif
2143}
2144
2145void LLVMIRBuilder::HandleCeil(GateRef gate)
2146{
2147    GateRef param = acc_.GetIn(gate, 0);
2148    VisitCeil(gate, param);
2149}
2150
2151void LLVMIRBuilder::VisitCeil(GateRef gate, GateRef e1)
2152{
2153    llvm::Value *e1Value = llvm::unwrap(GetLValue(e1));
2154    ASSERT(acc_.GetMachineType(e1) == acc_.GetMachineType(gate));
2155    llvm::Intrinsic::ID llvmId = llvm::Intrinsic::ceil;
2156    llvm::Value *result = llvm::unwrap(builder_)->CreateUnaryIntrinsic(llvmId, e1Value);
2157    Bind(gate, llvm::wrap(result));
2158
2159    if (IsLogEnabled()) {
2160        SetDebugInfo(gate, llvm::wrap(result));
2161    }
2162}
2163
2164template<typename... Ts>
2165static llvm::CallInst *BuildLLVMIntrinsic(llvm::IRBuilder<> *builder, llvm::Intrinsic::ID llvmId, Ts... inputs)
2166{
2167    static_assert((std::is_same_v<Ts, llvm::Value *> && ...));
2168    if constexpr (sizeof...(inputs) == 1) {
2169        return builder->CreateUnaryIntrinsic(llvmId, inputs...);
2170    } else {
2171        static_assert(sizeof...(inputs) == 2);
2172        return builder->CreateBinaryIntrinsic(llvmId, inputs...);
2173    }
2174}
2175
2176void LLVMIRBuilder::HandleAbs(GateRef gate)
2177{
2178    VisitAbs(gate, acc_.GetIn(gate, 0));
2179}
2180
2181void LLVMIRBuilder::VisitAbs(GateRef gate, GateRef e1)
2182{
2183    auto machineType = acc_.GetMachineType(gate);
2184    ASSERT(acc_.GetMachineType(e1) == machineType);
2185    llvm::Intrinsic::ID llvmId = 0;
2186    auto *builder = llvm::unwrap(builder_);
2187    llvm::Value *value = llvm::unwrap(GetLValue(e1));
2188    LLVMValueRef result;
2189    if (machineType == MachineType::I32) {
2190        llvmId = llvm::Intrinsic::abs;
2191        llvm::Type *type = llvm::Type::getInt1Ty(*llvm::unwrap(context_));
2192        llvm::Value *poison = llvm::Constant::getIntegerValue(type, llvm::APInt(1, 0));
2193        result = llvm::wrap(BuildLLVMIntrinsic(builder, llvmId, value, poison));
2194    } else if (machineType == MachineType::F64) {
2195        llvmId = llvm::Intrinsic::fabs;
2196        result = llvm::wrap(BuildLLVMIntrinsic(builder, llvmId, value));
2197    } else {
2198        LOG_ECMA(FATAL) << "`Abs` type should be untagged double or signed int";
2199        UNREACHABLE();
2200    }
2201    Bind(gate, result);
2202
2203    if (IsLogEnabled()) {
2204        SetDebugInfo(gate, result);
2205    }
2206}
2207
2208void LLVMIRBuilder::HandleMin(GateRef gate)
2209{
2210    VisitMin(gate, acc_.GetIn(gate, 0), acc_.GetIn(gate, 1U));
2211}
2212
2213void LLVMIRBuilder::VisitMin(GateRef gate, GateRef e1, GateRef e2)
2214{
2215    auto machineType = acc_.GetMachineType(gate);
2216    ASSERT(acc_.GetMachineType(e1) == machineType);
2217    ASSERT(acc_.GetMachineType(e2) == machineType);
2218    llvm::Intrinsic::ID llvmId = 0;
2219    if (machineType == MachineType::I32) {
2220        llvmId = llvm::Intrinsic::smin;
2221    } else if (machineType == MachineType::F64) {
2222        llvmId = llvm::Intrinsic::minimum;
2223    } else {
2224        LOG_ECMA(FATAL) << "`Min` type should be untagged double or signed int";
2225        UNREACHABLE();
2226    }
2227    VisitIntrinsic(gate, llvmId, e1, e2);
2228}
2229
2230void LLVMIRBuilder::HandleMax(GateRef gate)
2231{
2232    VisitMax(gate, acc_.GetIn(gate, 0), acc_.GetIn(gate, 1U));
2233}
2234
2235void LLVMIRBuilder::VisitMax(GateRef gate, GateRef e1, GateRef e2)
2236{
2237    auto machineType = acc_.GetMachineType(gate);
2238    ASSERT(acc_.GetMachineType(e1) == machineType);
2239    ASSERT(acc_.GetMachineType(e2) == machineType);
2240    llvm::Intrinsic::ID llvmId = 0;
2241    if (machineType == MachineType::I32) {
2242        llvmId = llvm::Intrinsic::smax;
2243    } else if (machineType == MachineType::F64) {
2244        llvmId = llvm::Intrinsic::maximum;
2245    } else {
2246        LOG_ECMA(FATAL) << "`Max` type should be untagged double or signed int";
2247        UNREACHABLE();
2248    }
2249    VisitIntrinsic(gate, llvmId, e1, e2);
2250}
2251
2252void LLVMIRBuilder::HandleFloor(GateRef gate)
2253{
2254    VisitIntrinsic(gate, llvm::Intrinsic::floor, acc_.GetIn(gate, 0));
2255}
2256
2257template<typename... Ts>
2258void LLVMIRBuilder::VisitIntrinsic(GateRef gate, llvm::Intrinsic::ID llvmId, Ts... inputs)
2259{
2260    static_assert((std::is_same_v<Ts, GateRef> && ...));
2261
2262    auto *builder = llvm::unwrap(builder_);
2263    LLVMValueRef result = llvm::wrap(BuildLLVMIntrinsic(builder, llvmId, llvm::unwrap(GetLValue(inputs))...));
2264    Bind(gate, result);
2265
2266    if (IsLogEnabled()) {
2267        SetDebugInfo(gate, result);
2268    }
2269}
2270
2271LLVMIntPredicate LLVMIRBuilder::ConvertLLVMPredicateFromICMP(ICmpCondition cond)
2272{
2273    switch (cond) {
2274        case ICmpCondition::SLT:
2275            return LLVMIntSLT;
2276        case ICmpCondition::SLE:
2277            return LLVMIntSLE;
2278        case ICmpCondition::SGT:
2279            return LLVMIntSGT;
2280        case ICmpCondition::SGE:
2281            return LLVMIntSGE;
2282        case ICmpCondition::ULT:
2283            return LLVMIntULT;
2284        case ICmpCondition::ULE:
2285            return LLVMIntULE;
2286        case ICmpCondition::UGT:
2287            return LLVMIntUGT;
2288        case ICmpCondition::UGE:
2289            return LLVMIntUGE;
2290        case ICmpCondition::NE:
2291            return LLVMIntNE;
2292        case ICmpCondition::EQ:
2293            return LLVMIntEQ;
2294        default:
2295            LOG_COMPILER(FATAL) << "unexpected cond!";
2296            UNREACHABLE();
2297    }
2298    return LLVMIntEQ;
2299}
2300
2301LLVMRealPredicate LLVMIRBuilder::ConvertLLVMPredicateFromFCMP(FCmpCondition cond)
2302{
2303    switch (cond) {
2304        case FCmpCondition::OLT:
2305            return LLVMRealOLT;
2306        case FCmpCondition::OLE:
2307            return LLVMRealOLE;
2308        case FCmpCondition::OGT:
2309            return LLVMRealOGT;
2310        case FCmpCondition::OGE:
2311            return LLVMRealOGE;
2312        case FCmpCondition::ONE:
2313            return LLVMRealONE;
2314        case FCmpCondition::OEQ:
2315            return LLVMRealOEQ;
2316        default:
2317            LOG_COMPILER(FATAL) << "unexpected cond!";
2318            UNREACHABLE();
2319    }
2320    return LLVMRealOEQ;
2321}
2322
2323void LLVMIRBuilder::VisitCmp(GateRef gate, GateRef e1, GateRef e2)
2324{
2325    LLVMValueRef e1Value = GetLValue(e1);
2326    LLVMValueRef e2Value = GetLValue(e2);
2327    LLVMValueRef result = nullptr;
2328    [[maybe_unused]] auto e1ValCode = acc_.GetMachineType(e1);
2329    [[maybe_unused]] auto e2ValCode = acc_.GetMachineType(e2);
2330    ASSERT((e1ValCode == e2ValCode) ||
2331        (compCfg_->Is64Bit() && (e1ValCode == MachineType::ARCH) && (e2ValCode == MachineType::I64)) ||
2332        (compCfg_->Is64Bit() && (e2ValCode == MachineType::ARCH) && (e1ValCode == MachineType::I64)));
2333    LLVMIntPredicate intOpcode = LLVMIntEQ;
2334    LLVMRealPredicate realOpcode = LLVMRealPredicateFalse;
2335    auto op = acc_.GetOpCode(gate);
2336    if (op == OpCode::ICMP) {
2337        auto cond = acc_.GetICmpCondition(gate);
2338        intOpcode = ConvertLLVMPredicateFromICMP(cond);
2339        result = LLVMBuildICmp(builder_, intOpcode, e1Value, e2Value, "");
2340    } else if (op == OpCode::FCMP) {
2341        auto cond = acc_.GetFCmpCondition(gate);
2342        realOpcode = ConvertLLVMPredicateFromFCMP(cond);
2343        result = LLVMBuildFCmp(builder_, realOpcode, e1Value, e2Value, "");
2344    } else {
2345        LOG_ECMA(FATAL) << "this branch is unreachable";
2346        UNREACHABLE();
2347    }
2348    Bind(gate, result);
2349
2350    if (IsLogEnabled()) {
2351        SetDebugInfo(gate, result);
2352    }
2353}
2354
2355void LLVMIRBuilder::HandleLoad(GateRef gate)
2356{
2357    VisitLoad(gate, acc_.GetIn(gate, 1));
2358}
2359
2360void LLVMIRBuilder::HandleStore(GateRef gate)
2361{
2362    GateRef addr = acc_.GetValueIn(gate, 0);
2363    GateRef value = acc_.GetValueIn(gate, 1);
2364    VisitStore(gate, addr, value);
2365}
2366
2367void LLVMIRBuilder::HandleChangeInt32ToDouble(GateRef gate)
2368{
2369    VisitChangeInt32ToDouble(gate, acc_.GetIn(gate, 0));
2370}
2371
2372void LLVMIRBuilder::HandleChangeUInt32ToDouble(GateRef gate)
2373{
2374    VisitChangeUInt32ToDouble(gate, acc_.GetIn(gate, 0));
2375}
2376
2377void LLVMIRBuilder::HandleChangeDoubleToInt32(GateRef gate)
2378{
2379    VisitChangeDoubleToInt32(gate, acc_.GetIn(gate, 0));
2380}
2381
2382void LLVMIRBuilder::HandleChangeTaggedPointerToInt64(GateRef gate)
2383{
2384    VisitChangeTaggedPointerToInt64(gate, acc_.GetIn(gate, 0));
2385}
2386
2387void LLVMIRBuilder::HandleChangeInt64ToTagged(GateRef gate)
2388{
2389    VisitChangeInt64ToTagged(gate, acc_.GetIn(gate, 0));
2390}
2391
2392void LLVMIRBuilder::HandleDoubleTrunc(GateRef gate)
2393{
2394    GateRef param = acc_.GetIn(gate, 0);
2395    VisitDoubleTrunc(gate, param);
2396}
2397
2398void LLVMIRBuilder::VisitDoubleTrunc(GateRef gate, GateRef e1)
2399{
2400    llvm::Value *e1Value = llvm::unwrap(GetLValue(e1));
2401    ASSERT(acc_.GetMachineType(e1) == acc_.GetMachineType(gate));
2402    llvm::Intrinsic::ID llvmId = llvm::Intrinsic::trunc;
2403    llvm::Value *result = llvm::unwrap(builder_)->CreateUnaryIntrinsic(llvmId, e1Value);
2404    Bind(gate, llvm::wrap(result));
2405
2406    if (IsLogEnabled()) {
2407        SetDebugInfo(gate, llvm::wrap(result));
2408    }
2409}
2410
2411void LLVMIRBuilder::VisitIntDiv(GateRef gate, GateRef e1, GateRef e2)
2412{
2413    LLVMValueRef e1Value = GetLValue(e1);
2414    LLVMValueRef e2Value = GetLValue(e2);
2415    LLVMValueRef result = LLVMBuildSDiv(builder_, e1Value, e2Value, "");
2416    Bind(gate, result);
2417
2418    if (IsLogEnabled()) {
2419        SetDebugInfo(gate, result);
2420    }
2421}
2422
2423void LLVMIRBuilder::VisitUDiv(GateRef gate, GateRef e1, GateRef e2)
2424{
2425    LLVMValueRef e1Value = GetLValue(e1);
2426    LLVMValueRef e2Value = GetLValue(e2);
2427    LLVMValueRef result = LLVMBuildUDiv(builder_, e1Value, e2Value, "");
2428    Bind(gate, result);
2429
2430    if (IsLogEnabled()) {
2431        SetDebugInfo(gate, result);
2432    }
2433}
2434
2435void LLVMIRBuilder::VisitFloatDiv(GateRef gate, GateRef e1, GateRef e2)
2436{
2437    LLVMValueRef e1Value = GetLValue(e1);
2438    LLVMValueRef e2Value = GetLValue(e2);
2439
2440    LLVMValueRef result = LLVMBuildFDiv(builder_, e1Value, e2Value, "");
2441    Bind(gate, result);
2442
2443    if (IsLogEnabled()) {
2444        SetDebugInfo(gate, result);
2445    }
2446}
2447
2448void LLVMIRBuilder::VisitIntOr(GateRef gate, GateRef e1, GateRef e2)
2449{
2450    LLVMValueRef e1Value = GetLValue(e1);
2451    LLVMValueRef e2Value = GetLValue(e2);
2452    LLVMValueRef result = LLVMBuildOr(builder_, e1Value, e2Value, "");
2453    Bind(gate, result);
2454
2455    if (IsLogEnabled()) {
2456        SetDebugInfo(gate, result);
2457    }
2458}
2459
2460void LLVMIRBuilder::HandleIntAnd(GateRef gate)
2461{
2462    auto g0 = acc_.GetIn(gate, 0);
2463    auto g1 = acc_.GetIn(gate, 1);
2464    VisitIntAnd(gate, g0, g1);
2465}
2466
2467void LLVMIRBuilder::VisitIntAnd(GateRef gate, GateRef e1, GateRef e2)
2468{
2469    LLVMValueRef e1Value = GetLValue(e1);
2470    LLVMValueRef e2Value = GetLValue(e2);
2471    LLVMValueRef result = LLVMBuildAnd(builder_, e1Value, e2Value, "");
2472    Bind(gate, result);
2473
2474    if (IsLogEnabled()) {
2475        SetDebugInfo(gate, result);
2476    }
2477}
2478
2479void LLVMIRBuilder::VisitIntXor(GateRef gate, GateRef e1, GateRef e2)
2480{
2481    LLVMValueRef e1Value = GetLValue(e1);
2482    LLVMValueRef e2Value = GetLValue(e2);
2483    LLVMValueRef result = LLVMBuildXor(builder_, e1Value, e2Value, "");
2484    Bind(gate, result);
2485
2486    if (IsLogEnabled()) {
2487        SetDebugInfo(gate, result);
2488    }
2489}
2490
2491void LLVMIRBuilder::VisitIntLsr(GateRef gate, GateRef e1, GateRef e2)
2492{
2493    LLVMValueRef e1Value = GetLValue(e1);
2494    LLVMValueRef e2Value = GetLValue(e2);
2495    LLVMValueRef result = LLVMBuildLShr(builder_, e1Value, e2Value, "");
2496    Bind(gate, result);
2497
2498    if (IsLogEnabled()) {
2499        SetDebugInfo(gate, result);
2500    }
2501}
2502
2503void LLVMIRBuilder::VisitIntAsr(GateRef gate, GateRef e1, GateRef e2)
2504{
2505    LLVMValueRef e1Value = GetLValue(e1);
2506    LLVMValueRef e2Value = GetLValue(e2);
2507    LLVMValueRef result = LLVMBuildAShr(builder_, e1Value, e2Value, "");
2508    Bind(gate, result);
2509
2510    if (IsLogEnabled()) {
2511        SetDebugInfo(gate, result);
2512    }
2513}
2514
2515void LLVMIRBuilder::HandleIntLsl(GateRef gate)
2516{
2517    auto g0 = acc_.GetIn(gate, 0);
2518    auto g1 = acc_.GetIn(gate, 1);
2519    VisitIntLsl(gate, g0, g1);
2520}
2521
2522void LLVMIRBuilder::VisitIntLsl(GateRef gate, GateRef e1, GateRef e2)
2523{
2524    LLVMValueRef e1Value = GetLValue(e1);
2525    LLVMValueRef e2Value = GetLValue(e2);
2526    LLVMValueRef result = LLVMBuildShl(builder_, e1Value, e2Value, "");
2527    Bind(gate, result);
2528
2529    if (IsLogEnabled()) {
2530        SetDebugInfo(gate, result);
2531    }
2532}
2533
2534void LLVMIRBuilder::VisitZExtInt(GateRef gate, GateRef e1)
2535{
2536    LLVMValueRef e1Value = GetLValue(e1);
2537    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) <=
2538           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
2539    LLVMValueRef result = LLVMBuildZExt(builder_, e1Value, ConvertLLVMTypeFromGate(gate), "");
2540    Bind(gate, result);
2541
2542    if (IsLogEnabled()) {
2543        SetDebugInfo(gate, result);
2544    }
2545}
2546
2547void LLVMIRBuilder::VisitSExtInt(GateRef gate, GateRef e1)
2548{
2549    LLVMValueRef e1Value = GetLValue(e1);
2550    LLVMValueRef result = LLVMBuildSExt(builder_, e1Value, ConvertLLVMTypeFromGate(gate), "");
2551    Bind(gate, result);
2552
2553    if (IsLogEnabled()) {
2554        SetDebugInfo(gate, result);
2555    }
2556}
2557
2558void LLVMIRBuilder::HandleCastIntXToIntY(GateRef gate)
2559{
2560    VisitCastIntXToIntY(gate, acc_.GetIn(gate, 0));
2561}
2562
2563void LLVMIRBuilder::VisitCastIntXToIntY(GateRef gate, GateRef e1)
2564{
2565    LLVMValueRef e1Value = GetLValue(e1);
2566    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) >=
2567           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
2568    LLVMValueRef result = LLVMBuildIntCast2(builder_, e1Value, ConvertLLVMTypeFromGate(gate), 1, "");
2569    Bind(gate, result);
2570
2571    if (IsLogEnabled()) {
2572        SetDebugInfo(gate, result);
2573    }
2574}
2575
2576void LLVMIRBuilder::HandleFPExt(GateRef gate)
2577{
2578    VisitFPExt(gate, acc_.GetIn(gate, 0));
2579}
2580
2581void LLVMIRBuilder::VisitFPExt(GateRef gate, GateRef e1)
2582{
2583    LLVMValueRef e1Value = GetLValue(e1);
2584    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) <=
2585           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
2586    LLVMValueRef result = LLVMBuildFPExt(builder_, e1Value, ConvertLLVMTypeFromGate(gate), "");
2587    Bind(gate, result);
2588
2589    if (IsLogEnabled()) {
2590        SetDebugInfo(gate, result);
2591    }
2592}
2593
2594void LLVMIRBuilder::HandleFPTrunc(GateRef gate)
2595{
2596    VisitFPTrunc(gate, acc_.GetIn(gate, 0));
2597}
2598
2599void LLVMIRBuilder::VisitFPTrunc(GateRef gate, GateRef e1)
2600{
2601    LLVMValueRef e1Value = GetLValue(e1);
2602    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) >=
2603           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
2604    LLVMValueRef result = LLVMBuildFPTrunc(builder_, e1Value, ConvertLLVMTypeFromGate(gate), "");
2605    Bind(gate, result);
2606
2607    if (IsLogEnabled()) {
2608        SetDebugInfo(gate, result);
2609    }
2610}
2611
2612void LLVMIRBuilder::VisitChangeInt32ToDouble(GateRef gate, GateRef e1)
2613{
2614    LLVMValueRef e1Value = GetLValue(e1);
2615    LLVMValueRef result = LLVMBuildSIToFP(builder_, e1Value, ConvertLLVMTypeFromGate(gate), "");
2616    Bind(gate, result);
2617
2618    if (IsLogEnabled()) {
2619        SetDebugInfo(gate, result);
2620    }
2621}
2622
2623void LLVMIRBuilder::VisitChangeUInt32ToDouble(GateRef gate, GateRef e1)
2624{
2625    LLVMValueRef e1Value = GetLValue(e1);
2626    LLVMValueRef result = LLVMBuildUIToFP(builder_, e1Value, GetDoubleT(), "");
2627    Bind(gate, result);
2628
2629    if (IsLogEnabled()) {
2630        SetDebugInfo(gate, result);
2631    }
2632}
2633
2634void LLVMIRBuilder::VisitChangeDoubleToInt32(GateRef gate, GateRef e1)
2635{
2636    LLVMValueRef e1Value = GetLValue(e1);
2637    LLVMValueRef result = LLVMBuildFPToSI(builder_, e1Value, GetInt32T(), "");
2638    Bind(gate, result);
2639
2640    if (IsLogEnabled()) {
2641        SetDebugInfo(gate, result);
2642    }
2643}
2644
2645void LLVMIRBuilder::VisitChangeTaggedPointerToInt64(GateRef gate, GateRef e1)
2646{
2647    LLVMValueRef e1Value = GetLValue(e1);
2648    LLVMValueRef result = CanonicalizeToInt(e1Value);
2649    Bind(gate, result);
2650
2651    if (IsLogEnabled()) {
2652        SetDebugInfo(gate, result);
2653    }
2654}
2655
2656void LLVMIRBuilder::VisitChangeInt64ToTagged(GateRef gate, GateRef e1)
2657{
2658    LLVMValueRef e1Value = GetLValue(e1);
2659    ASSERT(LLVMGetTypeKind(LLVMTypeOf(e1Value)) == LLVMIntegerTypeKind);
2660    LLVMValueRef result = LLVMBuildIntToPtr(builder_, e1Value, GetTaggedHPtrT(), "");
2661    Bind(gate, result);
2662
2663    if (IsLogEnabled()) {
2664        SetDebugInfo(gate, result);
2665    }
2666}
2667
2668void LLVMIRBuilder::HandleBitCast(GateRef gate)
2669{
2670    VisitBitCast(gate, acc_.GetIn(gate, 0));
2671}
2672
2673void LLVMIRBuilder::VisitBitCast(GateRef gate, GateRef e1)
2674{
2675    LLVMValueRef e1Value = GetLValue(e1);
2676    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(gate)) ==
2677           GetBitWidthFromMachineType(acc_.GetMachineType(e1)));
2678    auto returnType = ConvertLLVMTypeFromGate(gate);
2679    LLVMValueRef result = LLVMBuildBitCast(builder_, e1Value, returnType, "");
2680    Bind(gate, result);
2681
2682    if (IsLogEnabled()) {
2683        SetDebugInfo(gate, result);
2684    }
2685}
2686
2687void LLVMIRBuilder::HandleDeoptCheck(GateRef gate)
2688{
2689    int block = instID2bbID_[acc_.GetId(gate)];
2690    std::vector<GateRef> outs;
2691    acc_.GetOutStates(gate, outs);
2692    int bbOut = instID2bbID_[acc_.GetId(outs[0])]; // 0: output
2693
2694    BasicBlock *trueBB = EnsureBB(bbOut);
2695    LLVMBasicBlockRef llvmTrueBB = EnsureLBB(trueBB);
2696    std::string buf = "deopt if false B" + std::to_string(block);
2697    LLVMBasicBlockRef llvmFalseBB = LLVMAppendBasicBlock(function_, buf.c_str());
2698    GateRef cmp = acc_.GetValueIn(gate, 0); // 0: cond
2699    LLVMValueRef cond = GetLValue(cmp);
2700    LLVMValueRef result = LLVMBuildCondBr(builder_, cond, llvmTrueBB, llvmFalseBB);
2701
2702    if (enableOptBranchProfiling_) {
2703        LLVMMetadataRef branch_weights = LLVMMDStringInContext2(context_, "branch_weights", 14);
2704        LLVMMetadataRef weight1 = LLVMValueAsMetadata(LLVMConstInt(LLVMIntType(32), BranchWeight::DEOPT_WEIGHT, 0));
2705        LLVMMetadataRef weight2 = LLVMValueAsMetadata(LLVMConstInt(LLVMIntType(32), BranchWeight::ONE_WEIGHT, 0));
2706        LLVMMetadataRef mds[] = {branch_weights, weight1, weight2};
2707        LLVMMetadataRef metadata = LLVMMDNodeInContext2(context_, mds, 3);  // 3: size of mds
2708        LLVMValueRef metadata_value = LLVMMetadataAsValue(context_, metadata);
2709        LLVMSetMetadata(result, LLVMGetMDKindID("prof", 4), metadata_value);    // 4: length of "prof"
2710    }
2711
2712    EndCurrentBlock();
2713
2714    LLVMPositionBuilderAtEnd(builder_, llvmFalseBB);
2715    LLVMBasicBlockRef preLBB = EnsureLBB(EnsureBB(block));
2716    LLVMMoveBasicBlockBefore(preLBB, llvmFalseBB);
2717
2718    VisitDeoptCheck(gate);
2719    LLVMValueRef returnValue = GetLValue(gate);
2720    if (IsLogEnabled()) {
2721        SetDebugInfo(gate, returnValue);
2722    }
2723    LLVMBuildRet(builder_, returnValue);
2724    Bind(gate, result);
2725}
2726
2727void LLVMIRBuilder::HandleClz32(GateRef gate)
2728{
2729    VisitClz32(gate, acc_.GetIn(gate, 0));
2730}
2731
2732void LLVMIRBuilder::VisitClz32(GateRef gate,  GateRef param)
2733{
2734    LLVMValueRef value = GetLValue(param);
2735    LLVMValueRef trueConst = LLVMConstInt(GetInt1T(), 0, true);
2736
2737    llvm::CallInst *result = llvm::unwrap(builder_)->CreateBinaryIntrinsic(llvm::Intrinsic::ctlz,
2738                                                                           llvm::unwrap(value),
2739                                                                           llvm::unwrap(trueConst));
2740    Bind(gate, llvm::wrap(result));
2741
2742    if (IsLogEnabled()) {
2743        SetDebugInfo(gate, value);
2744    }
2745}
2746
2747LLVMTypeRef LLVMIRBuilder::GetExperimentalDeoptTy()
2748{
2749    auto fnTy = LLVMFunctionType(GetTaggedHPtrT(), nullptr, 0, 1);
2750    return fnTy;
2751}
2752
2753LLVMValueRef LLVMModule::GetDeoptFunction()
2754{
2755    auto fn = LLVMGetNamedFunction(module_, Deoptimizier::GetLLVMDeoptRelocateSymbol());
2756    return fn;
2757}
2758
2759void LLVMIRBuilder::GenDeoptEntry(LLVMModuleRef &module)
2760{
2761    // glue type depth
2762    std::vector<LLVMTypeRef> paramTys = { GetInt64T(), GetInt64T(), GetInt64T() };
2763    auto funcType = LLVMFunctionType(GetInt64T(), paramTys.data(),  paramTys.size(), 0);
2764    auto function = LLVMAddFunction(module, Deoptimizier::GetLLVMDeoptRelocateSymbol(), funcType);
2765    LLVMSetFunctionCallConv(function, LLVMCCallConv);
2766    llvmModule_->SetFunction(LLVMModule::kDeoptEntryOffset, function, false);
2767
2768    LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context_, function, "entry");
2769    LLVMBuilderRef builder = LLVMCreateBuilderInContext(context_);
2770    LLVMPositionBuilderAtEnd(builder, entry);
2771
2772    auto reservedSlotsSize = OptimizedFrame::ComputeReservedSize(slotSize_);
2773    LLVMAddTargetDependentFunctionAttr(function, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
2774    SaveFrameTypeOnFrame(FrameType::OPTIMIZED_FRAME, builder);
2775
2776    LLVMValueRef glue = LLVMGetParam(function, 0);
2777    LLVMValueRef check = LLVMGetParam(function, 1);
2778    LLVMValueRef depth = LLVMGetParam(function, 2);
2779
2780    StubIdType stubId = RTSTUB_ID(DeoptHandlerAsm);
2781    int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
2782    LLVMValueRef rtoffset = LLVMBuildAdd(builder, glue, GetRTStubOffset(glue, stubIndex), "");
2783    LLVMValueRef patchAddr = LLVMBuildIntToPtr(builder, rtoffset, GetTaggedPtrT(), "");
2784    LLVMValueRef llvmAddr = LLVMBuildLoad(builder, patchAddr, "");
2785    LLVMTypeRef rtfuncTypePtr = LLVMPointerType(funcType, 0);
2786    LLVMValueRef callee = LLVMBuildIntToPtr(builder, llvmAddr, rtfuncTypePtr, "");
2787    std::vector<LLVMValueRef> params = {glue, check, depth};
2788    LLVMValueRef runtimeCall = LLVMBuildCall2(builder, funcType, callee, params.data(), params.size(), "");
2789    LLVMBuildRet(builder, runtimeCall);
2790    LLVMPositionBuilderAtEnd(builder, entry);
2791    LLVMDisposeBuilder(builder);
2792}
2793
2794LLVMValueRef LLVMIRBuilder::GetExperimentalDeopt(LLVMModuleRef &module)
2795{
2796    /* 0:calling 1:its caller */
2797    auto fn = LLVMGetNamedFunction(module, "llvm.experimental.deoptimize.p1i64");
2798    if (!fn) {
2799        auto fnTy = GetExperimentalDeoptTy();
2800        fn = LLVMAddFunction(module, "llvm.experimental.deoptimize.p1i64", fnTy);
2801        GenDeoptEntry(module);
2802    }
2803    return fn;
2804}
2805
2806LLVMValueRef LLVMIRBuilder::ConvertBoolToTaggedBoolean(GateRef gate)
2807{
2808    LLVMValueRef value = GetLValue(gate);
2809    LLVMValueRef e1Value = LLVMBuildZExt(builder_, value, GetInt64T(), "");
2810    auto tagMask = LLVMConstInt(GetInt64T(), JSTaggedValue::TAG_BOOLEAN_MASK, 0);
2811    LLVMValueRef result = LLVMBuildOr(builder_, e1Value, tagMask, "");
2812    return LLVMBuildIntToPtr(builder_, result, GetTaggedHPtrT(), "");
2813}
2814
2815LLVMValueRef LLVMIRBuilder::ConvertInt32ToTaggedInt(GateRef gate)
2816{
2817    LLVMValueRef value = GetLValue(gate);
2818    return ConvertInt32ToTaggedInt(value);
2819}
2820
2821LLVMValueRef LLVMIRBuilder::ConvertInt32ToTaggedInt(LLVMValueRef value)
2822{
2823    LLVMValueRef e1Value = LLVMBuildSExt(builder_, value, GetInt64T(), "");
2824    auto tagMask = LLVMConstInt(GetInt64T(), JSTaggedValue::TAG_INT, 0);
2825    LLVMValueRef result = LLVMBuildOr(builder_, e1Value, tagMask, "");
2826    return LLVMBuildIntToPtr(builder_, result, GetTaggedHPtrT(), "");
2827}
2828
2829LLVMValueRef LLVMIRBuilder::ConvertFloat64ToTaggedDouble(GateRef gate)
2830{
2831    LLVMValueRef value = GetLValue(gate);
2832    LLVMValueRef e1Value = LLVMBuildBitCast(builder_, value, GetInt64T(), "");
2833    auto offset = LLVMConstInt(GetInt64T(), JSTaggedValue::DOUBLE_ENCODE_OFFSET, 0);
2834    LLVMValueRef result = LLVMBuildAdd(builder_, e1Value, offset, "");
2835    return LLVMBuildIntToPtr(builder_, result, GetTaggedHPtrT(), "");
2836}
2837
2838LLVMValueRef LLVMIRBuilder::ConvertToTagged(GateRef gate)
2839{
2840    auto machineType = acc_.GetMachineType(gate);
2841    switch (machineType) {
2842        case MachineType::I1:
2843            return ConvertBoolToTaggedBoolean(gate);
2844        case MachineType::I32:
2845            return ConvertInt32ToTaggedInt(gate);
2846        case MachineType::F64:
2847            return ConvertFloat64ToTaggedDouble(gate);
2848        case MachineType::I64:
2849            break;
2850        default:
2851            LOG_COMPILER(FATAL) << "unexpected machineType!";
2852            UNREACHABLE();
2853            break;
2854    }
2855    return gate2LValue_.at(gate);
2856}
2857
2858void LLVMIRBuilder::SaveDeoptVregInfo(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift,
2859                                      GateRef gate)
2860{
2861    int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(index, curDepth, shift);
2862    values.emplace_back(LLVMConstInt(GetInt32T(), encodeIndex, false));
2863    values.emplace_back(ConvertToTagged(gate));
2864}
2865
2866void LLVMIRBuilder::SaveDeoptVregInfoWithI64(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth,
2867                                             size_t shift, GateRef gate)
2868{
2869    LLVMValueRef value = LLVMBuildIntCast2(builder_, gate2LValue_.at(gate), GetInt32T(), 1, "");
2870    int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(index, curDepth, shift);
2871    values.emplace_back(LLVMConstInt(GetInt32T(), encodeIndex, false));
2872    values.emplace_back(ConvertInt32ToTaggedInt(value));
2873}
2874
2875void LLVMIRBuilder::VisitDeoptCheck(GateRef gate)
2876{
2877    LLVMValueRef glue = gate2LValue_.at(acc_.GetGlueFromArgList());
2878    GateRef deoptFrameState = acc_.GetValueIn(gate, 1); // 1: frame state
2879    ASSERT(acc_.GetOpCode(deoptFrameState) == OpCode::FRAME_STATE);
2880    std::vector<LLVMValueRef> params;
2881    params.push_back(glue); // glue
2882    GateRef deoptType = acc_.GetValueIn(gate, 2); // 2: deopt type
2883    uint64_t v = acc_.GetConstantValue(deoptType);
2884    params.push_back(ConvertInt32ToTaggedInt(LLVMConstInt(GetInt32T(), static_cast<uint32_t>(v), false))); // deoptType
2885    LLVMValueRef callee = GetExperimentalDeopt(module_);
2886    LLVMTypeRef funcType = GetExperimentalDeoptTy();
2887
2888    std::vector<LLVMValueRef> values;
2889    size_t maxDepth = acc_.GetFrameDepth(deoptFrameState, OpCode::FRAME_STATE);
2890    params.push_back(ConvertInt32ToTaggedInt(LLVMConstInt(GetInt32T(), static_cast<uint32_t>(maxDepth), false)));
2891    size_t shift = Deoptimizier::ComputeShift(maxDepth);
2892    GateRef frameState = deoptFrameState;
2893    ArgumentAccessor argAcc(const_cast<Circuit *>(circuit_));
2894    for (int32_t curDepth = static_cast<int32_t>(maxDepth); curDepth >= 0; curDepth--) {
2895        ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE);
2896        GateRef frameValues = acc_.GetValueIn(frameState, 1); // 1: frame values
2897        const size_t numValueIn = acc_.GetNumValueIn(frameValues);
2898        ASSERT(numValueIn > 1);
2899        const size_t envIndex = numValueIn - 2; // 2: env valueIn index
2900        const size_t accIndex = numValueIn - 1; // 1: acc valueIn index
2901        GateRef env = acc_.GetValueIn(frameValues, envIndex);
2902        GateRef acc = acc_.GetValueIn(frameValues, accIndex);
2903        auto pc = acc_.TryGetPcOffset(frameState);
2904        GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
2905        GateRef newTarget = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::NEW_TARGET);
2906        GateRef thisObj = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::THIS_OBJECT);
2907        GateRef actualArgc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::ACTUAL_ARGC);
2908        // vreg
2909        for (size_t i = 0; i < envIndex; i++) {
2910            GateRef vregValue = acc_.GetValueIn(frameValues, i);
2911            if (acc_.IsConstantTaggedValue(vregValue, JSTaggedValue::VALUE_OPTIMIZED_OUT)) {
2912                continue;
2913            }
2914            SaveDeoptVregInfo(values, i, curDepth, shift, vregValue);
2915        }
2916        // env
2917        if (!acc_.IsConstantTaggedValue(env, JSTaggedValue::VALUE_OPTIMIZED_OUT)) {
2918            int32_t specEnvVregIndex = static_cast<int32_t>(SpecVregIndex::ENV_INDEX);
2919            SaveDeoptVregInfo(values, specEnvVregIndex, curDepth, shift, env);
2920        }
2921        // acc
2922        if (!acc_.IsConstantTaggedValue(acc, JSTaggedValue::VALUE_OPTIMIZED_OUT)) {
2923            int32_t specAccVregIndex = static_cast<int32_t>(SpecVregIndex::ACC_INDEX);
2924            SaveDeoptVregInfo(values, specAccVregIndex, curDepth, shift, acc);
2925        }
2926        // pc offset
2927        int32_t specPcOffsetIndex = static_cast<int32_t>(SpecVregIndex::PC_OFFSET_INDEX);
2928        int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(specPcOffsetIndex, curDepth, shift);
2929        values.emplace_back(LLVMConstInt(GetInt32T(), encodeIndex, false));
2930        values.emplace_back(LLVMConstInt(GetInt32T(), pc, false));
2931        // func
2932        int32_t specCallTargetIndex = static_cast<int32_t>(SpecVregIndex::FUNC_INDEX);
2933        SaveDeoptVregInfo(values, specCallTargetIndex, curDepth, shift, jsFunc);
2934        // newTarget
2935        int32_t specNewTargetIndex = static_cast<int32_t>(SpecVregIndex::NEWTARGET_INDEX);
2936        SaveDeoptVregInfo(values, specNewTargetIndex, curDepth, shift, newTarget);
2937        // this object
2938        int32_t specThisIndex = static_cast<int32_t>(SpecVregIndex::THIS_OBJECT_INDEX);
2939        SaveDeoptVregInfo(values, specThisIndex, curDepth, shift, thisObj);
2940        int32_t specArgcIndex = static_cast<int32_t>(SpecVregIndex::ACTUAL_ARGC_INDEX);
2941        SaveDeoptVregInfoWithI64(values, specArgcIndex, curDepth, shift, actualArgc);
2942        frameState = acc_.GetFrameState(frameState);
2943    }
2944    LLVMValueRef runtimeCall =
2945        LLVMBuildCall3(builder_, funcType, callee, params.data(), params.size(), "", values.data(), values.size());
2946    Bind(gate, runtimeCall);
2947}
2948
2949LLVMModule::LLVMModule(NativeAreaAllocator* allocator, const std::string &name, bool logDbg, const std::string &triple)
2950    : IRModule(allocator, logDbg, triple)
2951{
2952    context_ = LLVMContextCreate();
2953    module_ = LLVMModuleCreateWithNameInContext(name.c_str(), context_);
2954    LLVMSetTarget(module_, triple.c_str());
2955    dBuilder_ = LLVMCreateDIBuilder(module_);
2956    dFileMD_ = LLVMDIBuilderCreateFile(dBuilder_, name.c_str(), name.size(), ".", 1);
2957    dUnitMD_ = LLVMDIBuilderCreateCompileUnit(dBuilder_, LLVMDWARFSourceLanguageC_plus_plus, dFileMD_, "ArkCompiler",
2958                                              0, 0, NULL, 0, 0, NULL, 0, LLVMDWARFEmissionFull,
2959                                              0, 0, 0, "/", 1, "", 0);
2960
2961    voidT_ = LLVMVoidTypeInContext(context_);
2962    int1T_ = LLVMInt1TypeInContext(context_);
2963    int8T_ = LLVMInt8TypeInContext(context_);
2964    int16T_ = LLVMInt16TypeInContext(context_);
2965    int32T_ = LLVMInt32TypeInContext(context_);
2966    int64T_ = LLVMInt64TypeInContext(context_);
2967    floatT_ = LLVMFloatTypeInContext(context_);
2968    doubleT_ = LLVMDoubleTypeInContext(context_);
2969    taggedHPtrT_ = LLVMPointerType(LLVMInt64TypeInContext(context_), 1);
2970    taggedPtrT_ = LLVMPointerType(LLVMInt64TypeInContext(context_), 0);
2971    rawPtrT_ = LLVMPointerType(LLVMInt8TypeInContext(context_), 0);
2972}
2973
2974LLVMModule::~LLVMModule()
2975{
2976    if (module_ != nullptr) {
2977        LLVMDisposeModule(module_);
2978        module_ = nullptr;
2979    }
2980    if (context_ != nullptr) {
2981        LLVMContextDispose(context_);
2982        context_ = nullptr;
2983    }
2984    if (dBuilder_ != nullptr) {
2985        LLVMDisposeDIBuilder(dBuilder_);
2986        dBuilder_ = nullptr;
2987    }
2988}
2989
2990void LLVMModule::InitialLLVMFuncTypeAndFuncByModuleCSigns()
2991{
2992    for (size_t i = 0; i < callSigns_.size(); i++) {
2993        const CallSignature* cs = callSigns_[i];
2994        ASSERT(!cs->GetName().empty());
2995        LLVMValueRef value = AddAndGetFunc(cs);
2996        SetFunction(i, value, false);
2997    }
2998}
2999
3000void LLVMModule::SetUpForCommonStubs()
3001{
3002    CommonStubCSigns::GetCSigns(callSigns_);
3003    InitialLLVMFuncTypeAndFuncByModuleCSigns();
3004}
3005
3006void LLVMModule::SetUpForBytecodeHandlerStubs()
3007{
3008    BytecodeStubCSigns::GetCSigns(callSigns_);
3009    InitialLLVMFuncTypeAndFuncByModuleCSigns();
3010}
3011
3012void LLVMModule::SetUpForBuiltinsStubs()
3013{
3014    BuiltinsStubCSigns::GetCSigns(callSigns_);
3015    InitialLLVMFuncTypeAndFuncByModuleCSigns();
3016}
3017
3018void LLVMModule::SetUpForBaselineStubs()
3019{
3020    BaselineStubCSigns::GetCSigns(callSigns_);
3021    InitialLLVMFuncTypeAndFuncByModuleCSigns();
3022}
3023
3024LLVMValueRef LLVMModule::AddAndGetFunc(const CallSignature *stubDescriptor)
3025{
3026    auto funcType = GetFuncType(stubDescriptor);
3027    return LLVMAddFunction(module_, stubDescriptor->GetName().c_str(), funcType);
3028}
3029
3030LLVMTypeRef LLVMModule::GetFuncType(const CallSignature *stubDescriptor)
3031{
3032    LLVMTypeRef returnType = ConvertLLVMTypeFromVariableType(stubDescriptor->GetReturnType());
3033    std::vector<LLVMTypeRef> paramTys;
3034    auto paramCount = stubDescriptor->GetParametersCount();
3035    int extraParameterCnt = 0;
3036    auto paramsType = stubDescriptor->GetParametersType();
3037    if (paramsType != nullptr) {
3038        LLVMTypeRef glueType = ConvertLLVMTypeFromVariableType(paramsType[0]);
3039        paramTys.push_back(glueType);
3040
3041        for (size_t i = 1; i < paramCount; i++) {
3042            paramTys.push_back(ConvertLLVMTypeFromVariableType(paramsType[i]));
3043        }
3044    }
3045    auto functype = LLVMFunctionType(returnType, paramTys.data(), paramCount + extraParameterCnt,
3046        stubDescriptor->IsVariadicArgs());
3047    return functype;
3048}
3049
3050LLVMTypeRef LLVMModule::GenerateFuncType(const std::vector<LLVMValueRef> &params, const CallSignature *stubDescriptor)
3051{
3052    LLVMTypeRef returnType = ConvertLLVMTypeFromVariableType(stubDescriptor->GetReturnType());
3053    std::vector<LLVMTypeRef> paramTys;
3054    for (auto value : params) {
3055        paramTys.emplace_back(LLVMTypeOf(value));
3056    }
3057    auto functionType = LLVMFunctionType(returnType, paramTys.data(), paramTys.size(), false);
3058    return functionType;
3059}
3060
3061LLVMTypeRef LLVMModule::ConvertLLVMTypeFromVariableType(VariableType type)
3062{
3063    std::map<VariableType, LLVMTypeRef> machineTypeMap = {
3064        {VariableType::VOID(), GetVoidT() },
3065        {VariableType::BOOL(), GetInt1T() },
3066        {VariableType::INT8(), GetInt8T() },
3067        {VariableType::INT16(), GetInt16T() },
3068        {VariableType::INT32(), GetInt32T() },
3069        {VariableType::INT64(), GetInt64T() },
3070        {VariableType::INT8(), GetInt8T() },
3071        {VariableType::INT16(), GetInt16T() },
3072        {VariableType::INT32(), GetInt32T() },
3073        {VariableType::INT64(), GetInt64T() },
3074        {VariableType::FLOAT32(), GetFloatT() },
3075        {VariableType::FLOAT64(), GetDoubleT() },
3076        {VariableType::NATIVE_POINTER(), GetInt64T() },
3077        {VariableType::JS_POINTER(), GetTaggedHPtrT() },
3078        {VariableType::JS_ANY(), GetTaggedHPtrT()},
3079    };
3080    return machineTypeMap[type];
3081}
3082
3083LLVMValueRef LLVMModule::AddFunc(const panda::ecmascript::MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile)
3084{
3085    LLVMTypeRef returnType = NewLType(MachineType::I64, GateType::TaggedValue());  // possibly get it for circuit
3086    LLVMTypeRef glue = NewLType(MachineType::I64, GateType::NJSValue());
3087    uint32_t paramCount = 0;
3088    std::vector<LLVMTypeRef> paramTys = { glue };
3089    if (!methodLiteral->IsFastCall()) {
3090        LLVMTypeRef actualArgc = NewLType(MachineType::I64, GateType::NJSValue());
3091        LLVMTypeRef actualArgv = NewLType(MachineType::I64, GateType::NJSValue());
3092        paramTys.emplace_back(actualArgc);
3093        paramTys.emplace_back(actualArgv);
3094        auto funcIndex = static_cast<uint32_t>(CommonArgIdx::FUNC);
3095        auto numOfComArgs = static_cast<uint32_t>(CommonArgIdx::NUM_OF_ARGS);
3096        paramCount = methodLiteral->GetNumArgsWithCallField() + numOfComArgs;
3097        auto numOfRestArgs = paramCount - funcIndex;
3098        paramTys.insert(paramTys.end(), numOfRestArgs, NewLType(MachineType::I64, GateType::TaggedValue()));
3099    } else {
3100        auto funcIndex = static_cast<uint32_t>(FastCallArgIdx::FUNC);
3101        auto numOfComArgs = static_cast<uint32_t>(FastCallArgIdx::NUM_OF_ARGS);
3102        paramCount = methodLiteral->GetNumArgsWithCallField() + numOfComArgs;
3103        auto numOfRestArgs = paramCount - funcIndex;
3104        paramTys.insert(paramTys.end(), numOfRestArgs, NewLType(MachineType::I64, GateType::TaggedValue()));
3105    }
3106    auto funcType = LLVMFunctionType(returnType, paramTys.data(), paramCount, false); // not variable args
3107
3108    std::string name = GetFuncName(methodLiteral, jsPandaFile);
3109    auto offsetInPandaFile = methodLiteral->GetMethodId().GetOffset();
3110    auto function = LLVMAddFunction(module_, name.c_str(), funcType);
3111    ASSERT(offsetInPandaFile != LLVMModule::kDeoptEntryOffset);
3112    SetFunction(offsetInPandaFile, function, methodLiteral->IsFastCall());
3113
3114    return function;
3115}
3116
3117LLVMTypeRef LLVMModule::NewLType(MachineType machineType, GateType gateType)
3118{
3119    VariableType vType(machineType, gateType);
3120    return ConvertLLVMTypeFromVariableType(vType);
3121}
3122}  // namespace panda::ecmascript::kungfu
3123