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/maple/litecg_ir_builder.h"
17
18#include <cmath>
19#include <cstdint>
20
21#include "ecmascript/compiler/argument_accessor.h"
22#include "ecmascript/compiler/bc_call_signature.h"
23#include "ecmascript/compiler/baseline/baseline_call_signature.h"
24#include "ecmascript/compiler/circuit.h"
25#include "ecmascript/compiler/call_signature.h"
26#include "ecmascript/compiler/common_stub_csigns.h"
27#include "ecmascript/compiler/gate.h"
28#include "ecmascript/compiler/rt_call_signature.h"
29#include "ecmascript/deoptimizer/deoptimizer.h"
30#include "ecmascript/frames.h"
31#include "ecmascript/js_function.h"
32#include "ecmascript/js_thread.h"
33#include "ecmascript/method.h"
34#include "triple.h"
35#include "lmir_builder.h"
36
37namespace panda::ecmascript::kungfu {
38using FunctionBuilder = maple::litecg::LMIRBuilder::FunctionBuilder;
39using SwitchBuilder = maple::litecg::LMIRBuilder::SwitchBuilder;
40using Function = maple::litecg::Function;
41using LMIRBuilder = maple::litecg::LMIRBuilder;
42using BB = maple::litecg::BB;
43using Expr = maple::litecg::Expr;
44using Stmt = maple::litecg::Stmt;
45using Const = maple::litecg::Const;
46using LiteCGType = maple::litecg::Type;
47using IntCmpCondition = maple::litecg::IntCmpCondition;
48using FloatCmpCondition = maple::litecg::FloatCmpCondition;
49using Var = maple::litecg::Var;
50using PregIdx = maple::litecg::PregIdx;
51using IntrinsicId = maple::litecg::IntrinsicId;
52using maple::litecg::LiteCGValue;
53using maple::litecg::LiteCGValueKind;
54
55using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, Expr>;
56
57LiteCGIRBuilder::LiteCGIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit,
58                                 LMIRModule *module, const CompilationConfig *cfg, CallSignature::CallConv callConv,
59                                 bool enableLog, bool enableOptInlining,
60                                 const panda::ecmascript::MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile,
61                                 const std::string &funcName)
62    : scheduledGates_(schedule),
63      circuit_(circuit),
64      lmirModule_(module),
65      compCfg_(cfg),
66      callConv_(callConv),
67      enableLog_(enableLog),
68      enableOptInlining_(enableOptInlining),
69      methodLiteral_(methodLiteral),
70      jsPandaFile_(jsPandaFile),
71      funcName_(funcName),
72      acc_(circuit),
73      cf_(*module->GetModule())
74{
75    lmirBuilder_ = new LMIRBuilder(*module->GetModule());
76    maple::theMIRModule = module->GetModule();
77    ASSERT(compCfg_->Is64Bit());
78    slotSize_ = sizeof(uint64_t);
79    slotType_ = lmirBuilder_->i64Type;
80    InitializeHandlers();
81    if (cfg != nullptr) {
82        maple::Triple::GetTriple().Init(cfg->IsAArch64());
83    }
84}
85
86LiteCGIRBuilder::~LiteCGIRBuilder()
87{
88    delete lmirBuilder_;
89}
90
91void LiteCGIRBuilder::BuildInstID2BBIDMap()
92{
93    for (size_t bbIdx = 0; bbIdx < scheduledGates_->size(); bbIdx++) {
94        const std::vector<GateRef> &bb = scheduledGates_->at(bbIdx);
95        for (size_t instIdx = bb.size(); instIdx > 0; instIdx--) {
96            GateId gateId = acc_.GetId(bb[instIdx - 1]);
97            instID2bbID_[gateId] = static_cast<int>(bbIdx);
98        }
99    }
100}
101
102BB &LiteCGIRBuilder::GetOrCreateBB(int bbID)
103{
104    auto itr = bbID2BB_.find(bbID);
105    if (itr != bbID2BB_.end()) {
106        return *(itr->second);
107    }
108    BB &bb = lmirBuilder_->CreateBB();
109    bbID2BB_[bbID] = &bb;
110    return bb;
111}
112
113BB &LiteCGIRBuilder::GetFirstBB()
114{
115    // Obtain the first BB (i.e. the BB with id zero) for inserting prologue information
116    return GetOrCreateBB(0);
117}
118
119BB &LiteCGIRBuilder::CreateBB()
120{
121    BB &bb = lmirBuilder_->CreateBB(false);
122    return bb;
123}
124
125LiteCGType *LiteCGIRBuilder::ConvertLiteCGTypeFromGate(GateRef gate, bool isSigned) const
126{
127    if (acc_.IsGCRelated(gate)) {
128        return lmirBuilder_->i64RefType;
129    }
130
131    MachineType t = acc_.GetMachineType(gate);
132    switch (t) {
133        case MachineType::NOVALUE:
134            return lmirBuilder_->voidType;
135        case MachineType::I1:
136            return lmirBuilder_->u1Type;
137        case MachineType::I8:
138            return isSigned ? lmirBuilder_->i8Type : lmirBuilder_->u8Type;
139        case MachineType::I16:
140            return isSigned ? lmirBuilder_->i16Type : lmirBuilder_->u16Type;
141        case MachineType::I32:
142            return isSigned ? lmirBuilder_->i32Type : lmirBuilder_->u32Type;
143        case MachineType::I64:
144            return isSigned ? lmirBuilder_->i64Type : lmirBuilder_->u64Type;
145        case MachineType::F32:
146            return lmirBuilder_->f32Type;
147        case MachineType::F64:
148            return lmirBuilder_->f64Type;
149        case MachineType::ARCH:
150            return isSigned ? lmirBuilder_->i64Type : lmirBuilder_->u64Type;
151        default:
152            LOG_ECMA(FATAL) << "this branch is unreachable";
153            UNREACHABLE();
154    }
155}
156
157void LiteCGIRBuilder::AddFunc()
158{
159    // setup function type
160    std::string funcName = lmirModule_->GetFuncName(methodLiteral_, jsPandaFile_);
161    FunctionBuilder funcBuilder = lmirBuilder_->DefineFunction(funcName);
162    funcBuilder.Param(lmirBuilder_->i64Type, "glue");
163    if (circuit_->IsOsr()) {
164        funcBuilder.Param(lmirBuilder_->i64PtrType, "interpSp");
165    } else if (!methodLiteral_->IsFastCall()) {
166        funcBuilder.Param(lmirBuilder_->i64Type, "actualArgc")
167            .Param(lmirBuilder_->i64PtrType, "actualArgv")
168            .Param(lmirBuilder_->i64RefType, "func")
169            .Param(lmirBuilder_->i64RefType, "new_target")
170            .Param(lmirBuilder_->i64RefType, "this_object");
171        for (uint32_t i = 0; i < methodLiteral_->GetNumArgsWithCallField(); ++i) {
172            funcBuilder.Param(lmirBuilder_->i64RefType, "param" + std::to_string(i));
173        }
174    } else {
175        funcBuilder.Param(lmirBuilder_->i64RefType, "func").Param(lmirBuilder_->i64RefType, "this_object");
176        for (uint32_t i = 0; i < methodLiteral_->GetNumArgsWithCallField(); ++i) {
177            funcBuilder.Param(lmirBuilder_->i64RefType, "param" + std::to_string(i));
178        }
179    }
180
181    funcBuilder.CallConvAttribute(ConvertCallAttr(callConv_));
182    Function &function = funcBuilder.Return(lmirBuilder_->i64RefType).Done();
183    lmirBuilder_->SetCurFunc(function);
184    lmirBuilder_->RenameFormal2Preg(function);
185    GenPrologue(function);
186    auto offsetInPandaFile = methodLiteral_->GetMethodId().GetOffset();
187    lmirModule_->SetFunction(offsetInPandaFile, funcName, methodLiteral_->IsFastCall());
188}
189
190// deal with derived reference
191void LiteCGIRBuilder::CollectDerivedRefInfo()
192{
193    auto GetPregFromGate = [&](GateRef gate)->PregIdx {
194        LiteCGValue value = gate2Expr_[gate];
195        ASSERT(value.kind == LiteCGValueKind::kPregKind);
196        return std::get<PregIdx>(value.data);
197    };
198
199    // collect base references for derived phi reference
200    for (auto &pair : bbID2basePhis_) {
201        for (auto &desc : pair.second) {
202            Expr expr = GetExprFromGate(desc.operand);
203            if (derivedPhiGate2BasePhiPreg_.find(desc.operand) != derivedPhiGate2BasePhiPreg_.end()) {
204                expr = lmirBuilder_->Regread(derivedPhiGate2BasePhiPreg_[desc.operand]);
205            }
206            Stmt &tmpPhiAssign = lmirBuilder_->Regassign(expr, desc.phi);
207            lmirBuilder_->AppendStmtBeforeBranch(GetOrCreateBB(desc.predBBId), tmpPhiAssign);
208        }
209    }
210
211    std::set<PregIdx> baseRefSet;
212    // set common derived reference
213    for (auto it : derivedGate2BaseGate_) {
214        if (GetExprFromGate(it.second).IsConstValue() || GetExprFromGate(it.first).IsConstValue()) {
215            continue;
216        }
217        ASSERT(!GetExprFromGate(it.second).IsDread());
218        PregIdx derivedIdx = GetPregFromGate(it.first);
219        PregIdx baseIdx = GetPregFromGate(it.second);
220        baseRefSet.insert(baseIdx);
221        lmirBuilder_->SetFunctionDerived2BaseRef(derivedIdx, baseIdx);
222    }
223
224    // set phi derived reference
225    for (auto it : derivedPhiGate2BasePhiPreg_) {
226        PregIdx derivedIdx = GetPregFromGate(it.first);
227        PregIdx baseIdx = it.second;
228        if (baseRefSet.find(derivedIdx) != baseRefSet.end()) {
229            LOG_COMPILER(FATAL) << "shouldn't occur nested derived reference" << std::endl;
230            UNREACHABLE();
231        }
232        lmirBuilder_->SetFunctionDerived2BaseRef(derivedIdx, baseIdx);
233    }
234
235    bbID2basePhis_.clear();
236    derivedPhiGate2BasePhiPreg_.clear();
237    derivedGate2BaseGate_.clear();
238    derivedGateCache_.clear();
239}
240
241void LiteCGIRBuilder::HandleBB(const std::vector<GateRef> &bb, std::unordered_set<OpCode> &usedOpcodeSet)
242{
243    for (size_t instIdx = bb.size(); instIdx > 0; instIdx--) {
244        GateRef gate = bb[instIdx - 1];
245        OpCode opcode = acc_.GetOpCode(gate);
246        if (IsLogEnabled()) {
247            lmirBuilder_->SetCurrentDebugComment(acc_.ToString(gate));
248        }
249        switch (opcode) {
250            case OpCode::STATE_ENTRY:
251                HandleGoto(gate);
252                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::STATE_ENTRY);
253                break;
254            case OpCode::RETURN:
255                HandleReturn(gate);
256                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::RETURN);
257                break;
258            case OpCode::RETURN_VOID:
259                HandleReturnVoid(gate);
260                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::RETURN_VOID);
261                break;
262            case OpCode::IF_BRANCH:
263                HandleBranch(gate);
264                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::IF_BRANCH);
265                break;
266            case OpCode::ORDINARY_BLOCK:
267                HandleGoto(gate);
268                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ORDINARY_BLOCK);
269                break;
270            case OpCode::IF_TRUE:
271                HandleGoto(gate);
272                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::IF_TRUE);
273                break;
274            case OpCode::IF_FALSE:
275                HandleGoto(gate);
276                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::IF_FALSE);
277                break;
278            case OpCode::SWITCH_BRANCH:
279                HandleSwitch(gate);
280                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SWITCH_BRANCH);
281                break;
282            case OpCode::SWITCH_CASE:
283                HandleGoto(gate);
284                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SWITCH_CASE);
285                break;
286            case OpCode::MERGE:
287                HandleGoto(gate);
288                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::MERGE);
289                break;
290            case OpCode::DEFAULT_CASE:
291                HandleGoto(gate);
292                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::DEFAULT_CASE);
293                break;
294            case OpCode::LOOP_BEGIN:
295                HandleGoto(gate);
296                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::LOOP_BACK);
297                break;
298            case OpCode::LOOP_BACK:
299                HandleGoto(gate);
300                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::LOOP_BEGIN);
301                break;
302            case OpCode::VALUE_SELECTOR:
303                HandlePhi(gate);
304                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::VALUE_SELECTOR);
305                break;
306            case OpCode::RUNTIME_CALL:
307                HandleRuntimeCall(gate);
308                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::RUNTIME_CALL);
309                break;
310            case OpCode::RUNTIME_CALL_WITH_ARGV:
311                HandleRuntimeCallWithArgv(gate);
312                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::RUNTIME_CALL_WITH_ARGV);
313                break;
314            case OpCode::NOGC_RUNTIME_CALL:
315                HandleCall(gate);
316                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::NOGC_RUNTIME_CALL);
317                break;
318            case OpCode::CALL_OPTIMIZED:
319                HandleCall(gate);
320                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::CALL_OPTIMIZED);
321                break;
322            case OpCode::FAST_CALL_OPTIMIZED:
323                HandleCall(gate);
324                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FAST_CALL_OPTIMIZED);
325                break;
326            case OpCode::CALL:
327                HandleCall(gate);
328                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::CALL);
329                break;
330            case OpCode::BASELINE_CALL:
331                HandleCall(gate);
332                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::BASELINE_CALL);
333                break;
334            case OpCode::BUILTINS_CALL:
335                HandleCall(gate);
336                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::BUILTINS_CALL);
337                break;
338            case OpCode::BUILTINS_CALL_WITH_ARGV:
339                HandleCall(gate);
340                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::BUILTINS_CALL_WITH_ARGV);
341                break;
342            case OpCode::ARG:
343                HandleParameter(gate);
344                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ARG);
345                break;
346            case OpCode::CONSTANT:
347                HandleConstant(gate);
348                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::CONSTANT);
349                break;
350            case OpCode::ZEXT:
351                HandleZExtInt(gate);
352                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ZEXT);
353                break;
354            case OpCode::SEXT:
355                HandleSExtInt(gate);
356                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SEXT);
357                break;
358            case OpCode::TRUNC:
359                HandleCastIntXToIntY(gate);
360                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::TRUNC);
361                break;
362            case OpCode::FEXT:
363                HandleFPExt(gate);
364                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FEXT);
365                break;
366            case OpCode::FTRUNC:
367                HandleFPTrunc(gate);
368                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FTRUNC);
369                break;
370            case OpCode::REV:
371                HandleIntRev(gate);
372                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::REV);
373                break;
374            case OpCode::ADD:
375                HandleAdd(gate);
376                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ADD);
377                break;
378            case OpCode::SUB:
379                HandleSub(gate);
380                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SUB);
381                break;
382            case OpCode::MUL:
383                HandleMul(gate);
384                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::MUL);
385                break;
386            case OpCode::FDIV:
387                HandleFloatDiv(gate);
388                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FDIV);
389                break;
390            case OpCode::SDIV:
391                HandleIntDiv(gate);
392                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SDIV);
393                break;
394            case OpCode::UDIV:
395                HandleUDiv(gate);
396                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::UDIV);
397                break;
398            case OpCode::AND:
399                HandleIntAnd(gate);
400                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::AND);
401                break;
402            case OpCode::OR:
403                HandleIntOr(gate);
404                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::OR);
405                break;
406            case OpCode::XOR:
407                HandleIntXor(gate);
408                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::XOR);
409                break;
410            case OpCode::LSR:
411                HandleIntLsr(gate);
412                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::LSR);
413                break;
414            case OpCode::ASR:
415                HandleIntAsr(gate);
416                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ASR);
417                break;
418            case OpCode::ICMP:
419                HandleCmp(gate);
420                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ICMP);
421                break;
422            case OpCode::FCMP:
423                HandleCmp(gate);
424                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FCMP);
425                break;
426            case OpCode::LOAD:
427                HandleLoad(gate);
428                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::LOAD);
429                break;
430            case OpCode::STORE_WITHOUT_BARRIER:
431                HandleStore(gate);
432                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::STORE_WITHOUT_BARRIER);
433                break;
434            case OpCode::SIGNED_INT_TO_FLOAT:
435                HandleChangeInt32ToDouble(gate);
436                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SIGNED_INT_TO_FLOAT);
437                break;
438            case OpCode::UNSIGNED_INT_TO_FLOAT:
439                HandleChangeUInt32ToDouble(gate);
440                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::UNSIGNED_INT_TO_FLOAT);
441                break;
442            case OpCode::FLOAT_TO_SIGNED_INT:
443                HandleChangeDoubleToInt32(gate);
444                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FLOAT_TO_SIGNED_INT);
445                break;
446            case OpCode::TAGGED_TO_INT64:
447                HandleChangeTaggedPointerToInt64(gate);
448                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::TAGGED_TO_INT64);
449                break;
450            case OpCode::INT64_TO_TAGGED:
451                HandleChangeInt64ToTagged(gate);
452                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::INT64_TO_TAGGED);
453                break;
454            case OpCode::BITCAST:
455                HandleBitCast(gate);
456                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::BITCAST);
457                break;
458            case OpCode::LSL:
459                HandleIntLsl(gate);
460                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::LSL);
461                break;
462            case OpCode::SMOD:
463                HandleMod(gate);
464                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SMOD);
465                break;
466            case OpCode::FMOD:
467                HandleMod(gate);
468                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FMOD);
469                break;
470            case OpCode::DEOPT_CHECK:
471                HandleDeoptCheck(gate);
472                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::DEOPT_CHECK);
473                break;
474            case OpCode::TRUNC_FLOAT_TO_INT64:
475                HandleTruncFloatToInt(gate);
476                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::TRUNC_FLOAT_TO_INT64);
477                break;
478            case OpCode::TRUNC_FLOAT_TO_INT32:
479                HandleTruncFloatToInt(gate);
480                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::TRUNC_FLOAT_TO_INT32);
481                break;
482            case OpCode::ADD_WITH_OVERFLOW:
483                HandleAddWithOverflow(gate);
484                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ADD_WITH_OVERFLOW);
485                break;
486            case OpCode::SUB_WITH_OVERFLOW:
487                HandleSubWithOverflow(gate);
488                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SUB_WITH_OVERFLOW);
489                break;
490            case OpCode::MUL_WITH_OVERFLOW:
491                HandleMulWithOverflow(gate);
492                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::MUL_WITH_OVERFLOW);
493                break;
494            case OpCode::EXP:
495                HandleExp(gate);
496                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::EXP);
497                break;
498            case OpCode::ABS:
499                HandleAbs(gate);
500                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::ABS);
501                break;
502            case OpCode::MIN:
503                HandleMin(gate);
504                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::MIN);
505                break;
506            case OpCode::MAX:
507                HandleMax(gate);
508                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::MAX);
509                break;
510            case OpCode::CLZ32:
511                HandleClz32(gate);
512                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::CLZ32);
513                break;
514            case OpCode::DOUBLE_TRUNC:
515                HandleDoubleTrunc(gate);
516                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::DOUBLE_TRUNC);
517                break;
518            case OpCode::CEIL:
519                HandleCeil(gate);
520                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::CEIL);
521                break;
522            case OpCode::FLOOR:
523                HandleFloor(gate);
524                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FLOOR);
525                break;
526            case OpCode::EXTRACT_VALUE:
527                HandleExtractValue(gate);
528                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::EXTRACT_VALUE);
529                break;
530            case OpCode::SQRT:
531                HandleSqrt(gate);
532                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::SQRT);
533                break;
534            case OpCode::READSP:
535                HandleReadSp(gate);
536                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::READSP);
537                break;
538            case OpCode::FINISH_ALLOCATE:
539                HandleFinishAllocate(gate);
540                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::FINISH_ALLOCATE);
541                break;
542            case OpCode::INITVREG:
543                HandleInitVreg(gate);
544                InsertUsedOpcodeSet(usedOpcodeSet, OpCode::INITVREG);
545                break;
546            default:
547                if (illegalOpHandlers_.find(acc_.GetOpCode(gate)) == illegalOpHandlers_.end()) {
548                    LOG_COMPILER(FATAL) << "can't process opcode: " << acc_.GetOpCode(gate) << std::endl;
549                }
550        }
551        if (IsLogEnabled()) {
552            lmirBuilder_->ClearCurrentDebugComment();
553        }
554    }
555}
556void LiteCGIRBuilder::Build()
557{
558    BuildInstID2BBIDMap();
559    AddFunc();
560    LOG_COMPILER(INFO) << "============== building litecg ir=======" << std::endl;
561
562    std::unordered_set<OpCode> usedOpcodeSet;
563    for (size_t bbIdx = 0; bbIdx < scheduledGates_->size(); bbIdx++) {
564        const std::vector<GateRef> &bb = scheduledGates_->at(bbIdx);
565        HandleBB(bb, usedOpcodeSet);
566    }
567
568    if (enableLog_) {
569        for (auto &opcode : usedOpcodeSet) {
570            LOG_COMPILER(INFO) << "OPCODE: " << opcode << std::endl;
571        }
572    }
573
574    CollectDerivedRefInfo();
575
576    std::map<int, std::vector<std::pair<PregIdx, PregIdx>>> bbID2phiAssign;
577    for (auto &pair : bbID2unmergedPhis_) {
578        for (auto &desc : pair.second) {
579            Expr value = GetExprFromGate(desc.operand);
580            PregIdx tmpPhiPregIdx = lmirBuilder_->CreatePreg(value.GetType());
581            Stmt &tmpPhiAssign = lmirBuilder_->Regassign(value, tmpPhiPregIdx);
582            lmirBuilder_->AppendStmtBeforeBranch(GetOrCreateBB(desc.predBBId), tmpPhiAssign);
583            bbID2phiAssign[desc.predBBId].emplace_back(std::make_pair(tmpPhiPregIdx, desc.phi));
584        }
585    }
586
587    for (auto &pair: bbID2phiAssign) {
588        for (auto &expr: pair.second) {
589            auto &stmt =  lmirBuilder_->Regassign(lmirBuilder_->Regread(expr.first), expr.second);
590            lmirBuilder_->AppendStmtBeforeBranch(GetOrCreateBB(pair.first), stmt);
591        }
592    }
593    bbID2unmergedPhis_.clear();
594    bbID2phiAssign.clear();
595
596    lmirBuilder_->AppendBB(lmirBuilder_->GetLastPosBB());
597}
598
599void LiteCGIRBuilder::AssistGenPrologue(const size_t reservedSlotsSize, FrameType frameType,
600                                        maple::litecg::Function &function)
601{
602    lmirBuilder_->SetFuncFrameResverdSlot(reservedSlotsSize);
603    if (circuit_->IsOsr()) {
604        auto osrFrameType = methodLiteral_->IsFastCall() ? FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME : frameType;
605        SaveFrameTypeOnFrame(function, osrFrameType);
606        return;
607    }
608    auto ArgList = circuit_->GetArgRoot();
609    auto uses = acc_.Uses(ArgList);
610    for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) {
611        int argth = static_cast<int>(acc_.TryGetValue(*useIt));
612        Var &value = lmirBuilder_->GetParam(function, argth);
613        int funcIndex = 0;
614        if (methodLiteral_->IsFastCall()) {
615            frameType = FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
616            funcIndex = static_cast<int>(FastCallArgIdx::FUNC);
617        } else {
618            funcIndex = static_cast<int>(CommonArgIdx::FUNC);
619        }
620        if (argth == funcIndex) {
621            SaveByteCodePcOnOptJSFuncFrame(value);
622            SaveJSFuncOnOptJSFuncFrame(function, value, funcIndex);
623            SaveFrameTypeOnFrame(function, frameType);
624        }
625    }
626}
627
628void LiteCGIRBuilder::GenPrologue(maple::litecg::Function &function)
629{
630    auto frameType = circuit_->GetFrameType();
631    if (IsInterpreted() || IsBaselineBuiltin()) {
632        return;
633    }
634    lmirBuilder_->SetFuncFramePointer("all");
635    size_t reservedSlotsSize = 0;
636    if (frameType == FrameType::OPTIMIZED_FRAME) {
637        reservedSlotsSize = OptimizedFrame::ComputeReservedSize(slotSize_);
638        lmirBuilder_->SetFuncFrameResverdSlot(reservedSlotsSize);
639        SaveFrameTypeOnFrame(function, frameType);
640    } else if (frameType == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
641        reservedSlotsSize = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
642        lmirBuilder_->SetFuncFrameResverdSlot(reservedSlotsSize);
643        if (circuit_->IsOsr()) {
644            auto osrFrameType = methodLiteral_->IsFastCall() ? FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME
645                                                             : frameType;
646            SaveFrameTypeOnFrame(function, osrFrameType);
647            return;
648        }
649        auto ArgList = circuit_->GetArgRoot();
650        auto uses = acc_.Uses(ArgList);
651        for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) {
652            int argth = static_cast<int>(acc_.TryGetValue(*useIt));
653            Var &value = lmirBuilder_->GetParam(function, argth);
654            int funcIndex = 0;
655            if (methodLiteral_->IsFastCall()) {
656                frameType = FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME;
657                funcIndex = static_cast<int>(FastCallArgIdx::FUNC);
658            } else {
659                funcIndex = static_cast<int>(CommonArgIdx::FUNC);
660            }
661            if (argth == funcIndex) {
662                SaveJSFuncOnOptJSFuncFrame(function, value, funcIndex);
663                SaveFrameTypeOnFrame(function, frameType);
664            }
665        }
666    } else if (frameType == FrameType::FASTJIT_FUNCTION_FRAME) {
667        reservedSlotsSize = FASTJITFunctionFrame::ComputeReservedPcOffset(slotSize_);
668        AssistGenPrologue(reservedSlotsSize, frameType, function);
669    } else {
670        LOG_COMPILER(FATAL) << "frameType interpret type error !";
671        ASSERT_PRINT(static_cast<uintptr_t>(frameType), "is not support !");
672    }
673}
674
675void LiteCGIRBuilder::SaveByteCodePcOnOptJSFuncFrame(maple::litecg::Var &value)
676{
677    ASSERT(circuit_->GetFrameType() == FrameType::FASTJIT_FUNCTION_FRAME);
678    // load method
679    Expr func = lmirBuilder_->Cvt(lmirBuilder_->i64PtrType, slotType_, lmirBuilder_->GenExprFromVar(value));
680    Expr offsetMethod = lmirBuilder_->ConstVal(
681        lmirBuilder_->CreateIntConst(lmirBuilder_->i64PtrType, JSFunctionBase::METHOD_OFFSET));
682    Expr addrMethod = lmirBuilder_->Add(lmirBuilder_->i64PtrType, func, offsetMethod);
683    Expr method = lmirBuilder_->Iread(
684        lmirBuilder_->i64PtrType, addrMethod, lmirBuilder_->CreatePtrType(lmirBuilder_->i64PtrType));
685    // load byteCodePc
686    Expr offsetByteCodePc = lmirBuilder_->ConstVal(
687        lmirBuilder_->CreateIntConst(lmirBuilder_->i64PtrType, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
688    Expr addrByteCodePc = lmirBuilder_->Add(lmirBuilder_->i64PtrType, method, offsetByteCodePc);
689    Expr byteCodePc = lmirBuilder_->Iread(
690        lmirBuilder_->i64PtrType, addrByteCodePc, lmirBuilder_->CreatePtrType(lmirBuilder_->i64PtrType));
691    // push byteCodePc
692    Expr fpAddr = CallingFp(false);
693    Expr frameAddr = lmirBuilder_->Cvt(fpAddr.GetType(), lmirBuilder_->i64Type, fpAddr);
694    size_t reservedOffset = FASTJITFunctionFrame::ComputeReservedPcOffset(slotSize_);
695    Expr frameByteCodePcSlotAddr =
696        lmirBuilder_->Sub(frameAddr.GetType(), frameAddr,
697                          lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, reservedOffset)));
698    Expr byteCodePcAddr =
699        lmirBuilder_->Cvt(frameByteCodePcSlotAddr.GetType(),
700                          lmirBuilder_->CreatePtrType(slotType_), frameByteCodePcSlotAddr);
701    auto &stmt = lmirBuilder_->Iassign(byteCodePc, byteCodePcAddr, byteCodePcAddr.GetType());
702    lmirBuilder_->AppendStmt(GetFirstBB(), stmt);
703}
704
705void LiteCGIRBuilder::SaveJSFuncOnOptJSFuncFrame(maple::litecg::Function &function, maple::litecg::Var &value,
706                                                 int funcIndex)
707{
708    ASSERT(IsOptimizedJSFunction());
709    if (compCfg_->IsAArch64()) {
710        auto frameType = circuit_->GetFrameType();
711        if (frameType == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
712            function.SetFuncInfo(OptimizedJSFunctionFrame::GetFunctionToFpDelta(), true, funcIndex);
713        } else if (frameType == FrameType::FASTJIT_FUNCTION_FRAME) {
714            function.SetFuncInfo(FASTJITFunctionFrame::GetFunctionToFpDelta(), true, funcIndex);
715        }
716    } else {
717        Expr fpAddr = CallingFp(false);
718        Expr frameAddr = lmirBuilder_->Cvt(fpAddr.GetType(), lmirBuilder_->i64Type, fpAddr);
719        size_t reservedOffset = 0;
720        if (circuit_->GetFrameType() == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
721            reservedOffset = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
722        } else {
723            reservedOffset = FASTJITFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
724        }
725
726        Expr frameJSFuncSlotAddr =
727            lmirBuilder_->Sub(frameAddr.GetType(), frameAddr,
728                lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, reservedOffset)));
729        Expr jsFuncAddr =
730            lmirBuilder_->Cvt(frameJSFuncSlotAddr.GetType(),
731                lmirBuilder_->CreatePtrType(slotType_), frameJSFuncSlotAddr);
732        Expr jsFuncValue = lmirBuilder_->Cvt(lmirBuilder_->i64PtrType, slotType_, lmirBuilder_->GenExprFromVar(value));
733        auto &stmt = lmirBuilder_->Iassign(jsFuncValue, jsFuncAddr, jsFuncAddr.GetType());
734        lmirBuilder_->AppendStmt(GetFirstBB(), stmt);
735    }
736}
737
738void LiteCGIRBuilder::SaveFrameTypeOnFrame(maple::litecg::Function &function, FrameType frameType)
739{
740    if (compCfg_->IsAArch64()) {
741        function.SetFrameTypeInfo(-slotSize_, true, static_cast<int>(frameType));
742        return;
743    }
744    Expr fpAddr = CallingFp(false);
745    Expr frameAddr = lmirBuilder_->Cvt(fpAddr.GetType(), lmirBuilder_->i64Type, fpAddr);
746    Expr frameJSFuncSlotAddr = lmirBuilder_->Sub(
747        frameAddr.GetType(), frameAddr, lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, slotSize_)));
748    Expr jsFuncAddr =
749        lmirBuilder_->Cvt(frameJSFuncSlotAddr.GetType(), lmirBuilder_->CreatePtrType(slotType_), frameJSFuncSlotAddr);
750    Expr liteFramType =
751        lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i64Type, static_cast<uintptr_t>(frameType)));
752    auto &stmt = lmirBuilder_->Iassign(liteFramType, jsFuncAddr, jsFuncAddr.GetType());
753    lmirBuilder_->AppendStmt(GetFirstBB(), stmt);
754}
755
756Expr LiteCGIRBuilder::GetGlue(const std::vector<GateRef> &inList)
757{
758    GateRef glueGate = inList[static_cast<size_t>(CallInputs::GLUE)];
759    auto itr = gate2Expr_.find(glueGate);
760    if (itr != gate2Expr_.end()) {
761        return GetExprFromGate(glueGate);
762    }
763    Expr glue = lmirBuilder_->Dread(lmirBuilder_->GetLocalVar("glue"));
764    SaveGate2Expr(glueGate, glue);
765    return glue;
766}
767
768void LiteCGIRBuilder::SaveGate2Expr(GateRef gate, Expr expr, bool isGlueAdd)
769{
770    if (isGlueAdd) {
771        gate2Expr_[gate] = {LiteCGValueKind::kGlueAdd, lmirBuilder_->GetConstFromExpr(expr)};
772        return;
773    } else if (expr.IsDread()) {
774        gate2Expr_[gate] = {LiteCGValueKind::kSymbolKind, lmirBuilder_->GetLocalVarFromExpr(expr)};
775        return;
776    } else if (expr.IsRegread()) {
777        gate2Expr_[gate] = {LiteCGValueKind::kPregKind, lmirBuilder_->GetPregIdxFromExpr(expr)};
778        return;
779    } else if (expr.IsConstValue()) {
780        gate2Expr_[gate] = {LiteCGValueKind::kConstKind, lmirBuilder_->GetConstFromExpr(expr)};
781        return;
782    }
783    auto *newNode = cf_.Fold(expr.GetNode());
784    if (newNode == nullptr || !newNode->IsConstval()) {
785        // check expr is not agg
786        BB &curBB = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
787        PregIdx pregIdx = lmirBuilder_->CreatePreg(expr.GetType());
788        lmirBuilder_->AppendStmt(curBB, lmirBuilder_->Regassign(expr, pregIdx));
789        gate2Expr_[gate] = {LiteCGValueKind::kPregKind, pregIdx};
790        return;
791    }
792    gate2Expr_[gate] = {LiteCGValueKind::kConstKind, static_cast<maple::ConstvalNode*>(newNode)->GetConstVal()};
793}
794
795void LiteCGIRBuilder::SaveGate2Expr(GateRef gate, PregIdx pregIdx1, PregIdx pregIdx2)
796{
797    gate2Expr_[gate] = {LiteCGValueKind::kPregPairKind, std::make_pair(pregIdx1, pregIdx2)};
798}
799
800Expr LiteCGIRBuilder::GetConstant(GateRef gate)
801{
802    std::bitset<64> value = acc_.GetConstantValue(gate); // 64 for bit width
803    auto machineType = acc_.GetMachineType(gate);
804    if (machineType == MachineType::ARCH) {
805        ASSERT(compCfg_->Is64Bit());
806        machineType = MachineType::I64;
807    }
808
809    Const *constVal = nullptr;
810    if (machineType == MachineType::I32) {
811        constVal = &(lmirBuilder_->CreateIntConst(lmirBuilder_->i32Type, static_cast<int64_t>(value.to_ulong())));
812    } else if (machineType == MachineType::I64) {
813        constVal = &(lmirBuilder_->CreateIntConst(lmirBuilder_->i64Type, static_cast<int64_t>(value.to_ulong())));
814        LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
815        if (lmirBuilder_->LiteCGGetTypeKind(type) == maple::litecg::kLiteCGTypePointer) {
816            Expr constExpr = lmirBuilder_->Cvt(lmirBuilder_->i64Type, type, lmirBuilder_->ConstVal(*constVal));
817            return constExpr;
818        } else if (lmirBuilder_->LiteCGGetTypeKind(type) == maple::litecg::kLiteCGTypeScalar) {
819            // do nothing
820        } else {
821            LOG_ECMA(FATAL) << "this branch is unreachable";
822            UNREACHABLE();
823        }
824    } else if (machineType == MachineType::F64) {
825        auto doubleValue = base::bit_cast<double>(value.to_ullong());  // actual double value
826        constVal = &(lmirBuilder_->CreateDoubleConst(static_cast<double>(doubleValue)));
827    } else if (machineType == MachineType::I8) {
828        constVal = &(lmirBuilder_->CreateIntConst(lmirBuilder_->u8Type, static_cast<int64_t>(value.to_ulong())));
829    } else if (machineType == MachineType::I16) {
830        constVal = &(lmirBuilder_->CreateIntConst(lmirBuilder_->u16Type, static_cast<int64_t>(value.to_ulong())));
831    } else if (machineType == MachineType::I1) {
832        constVal = &(lmirBuilder_->CreateIntConst(lmirBuilder_->u1Type, static_cast<int64_t>(value.to_ulong())));
833    } else {
834        LOG_ECMA(FATAL) << "this branch is unreachable";
835        UNREACHABLE();
836    }
837    return lmirBuilder_->ConstVal(*constVal);
838}
839
840Expr LiteCGIRBuilder::GetExprFromGate(GateRef gate)
841{
842    if (acc_.GetOpCode(gate) == OpCode::CONSTANT) {
843        return GetConstant(gate);
844    }
845    LiteCGValue value = gate2Expr_[gate];
846    if (value.kind == LiteCGValueKind::kSymbolKind) {
847        return lmirBuilder_->Dread(*std::get<maple::MIRSymbol*>(value.data));
848    } else if (value.kind == LiteCGValueKind::kConstKind) {
849        return lmirBuilder_->ConstVal(*std::get<maple::MIRConst*>(value.data));
850    } else if (value.kind == LiteCGValueKind::kGlueAdd) {
851        auto glue = acc_.GetGlueFromArgList();
852        return lmirBuilder_->Add(ConvertLiteCGTypeFromGate(glue), GetExprFromGate(glue),
853            lmirBuilder_->ConstVal(*std::get<maple::MIRConst*>(value.data)));
854    }
855    ASSERT(value.kind == LiteCGValueKind::kPregKind);
856    return lmirBuilder_->Regread(std::get<PregIdx>(value.data));
857}
858
859Expr LiteCGIRBuilder::GetExprFromGate(GateRef gate, uint32_t index)
860{
861    LiteCGValue value = gate2Expr_[gate];
862    ASSERT(value.kind == LiteCGValueKind::kPregPairKind);
863    ASSERT(index == 0 || index == 1);
864    std::pair<PregIdx, PregIdx> pair = std::get<std::pair<PregIdx, PregIdx>>(value.data);
865    if (index == 0) {
866        return lmirBuilder_->Regread(pair.first);
867    }
868    return lmirBuilder_->Regread(pair.second);
869}
870
871void LiteCGIRBuilder::InitializeHandlers()
872{
873    illegalOpHandlers_ = {OpCode::NOP,
874                          OpCode::CIRCUIT_ROOT,
875                          OpCode::DEPEND_ENTRY,
876                          OpCode::DEAD,
877                          OpCode::RETURN_LIST,
878                          OpCode::ARG_LIST,
879                          OpCode::THROW,
880                          OpCode::DEPEND_SELECTOR,
881                          OpCode::DEPEND_RELAY,
882                          OpCode::FRAME_STATE,
883                          OpCode::STATE_SPLIT,
884                          OpCode::FRAME_ARGS,
885                          OpCode::LOOP_EXIT_DEPEND,
886                          OpCode::LOOP_EXIT,
887                          OpCode::START_ALLOCATE,
888                          OpCode::FINISH_ALLOCATE,
889                          OpCode::FRAME_VALUES,
890                          OpCode::ASM_CALL_BARRIER};
891}
892
893void LiteCGIRBuilder::HandleReturnVoid([[maybe_unused]] GateRef gate)
894{
895    return;
896}
897
898void LiteCGIRBuilder::HandleGoto(GateRef gate)
899{
900    std::vector<GateRef> outs;
901    acc_.GetOutStates(gate, outs);
902    int block = instID2bbID_[acc_.GetId(gate)];
903    int bbOut = instID2bbID_[acc_.GetId(outs[0])];
904    switch (acc_.GetOpCode(gate)) {
905        case OpCode::MERGE:
906        case OpCode::LOOP_BEGIN: {
907            for (const auto &out : outs) {
908                bbOut = instID2bbID_[acc_.GetId(out)];
909                VisitGoto(block, bbOut);
910            }
911            break;
912        }
913        default: {
914            VisitGoto(block, bbOut);
915            break;
916        }
917    }
918}
919
920void LiteCGIRBuilder::VisitGoto(int block, int bbOut)
921{
922    if (block == bbOut) {
923        return;
924    }
925    BB &srcBB = GetOrCreateBB(block);
926    BB &destBB = GetOrCreateBB(bbOut);
927
928    lmirBuilder_->AppendStmt(srcBB, lmirBuilder_->Goto(destBB));
929    lmirBuilder_->AppendBB(srcBB);
930}
931
932void LiteCGIRBuilder::HandleParameter(GateRef gate)
933{
934    return VisitParameter(gate);
935}
936
937void LiteCGIRBuilder::VisitParameter(GateRef gate)
938{
939    std::vector<GateRef> outs;
940    acc_.GetOuts(gate, outs);
941    if (outs.empty()) {
942        return;
943    }
944    size_t argth = static_cast<size_t>(acc_.TryGetValue(gate));
945    Var &param = lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), argth);
946    SaveGate2Expr(gate, lmirBuilder_->GenExprFromVar(param));
947}
948
949void LiteCGIRBuilder::HandleConstant(GateRef gate)
950{
951    // no need to deal with constant separately
952    (void)gate;
953    return;
954}
955
956void LiteCGIRBuilder::HandleAdd(GateRef gate)
957{
958    auto g0 = acc_.GetIn(gate, 0);
959    auto g1 = acc_.GetIn(gate, 1);
960    VisitAdd(gate, g0, g1);
961}
962
963Expr LiteCGIRBuilder::CanonicalizeToPtr(Expr expr, LiteCGType *type)
964{
965    if (lmirBuilder_->LiteCGGetTypeKind(expr.GetType()) == maple::litecg::kLiteCGTypePointer) {
966        if (expr.GetType() == type) {
967            return expr;
968        }
969        return lmirBuilder_->Cvt(expr.GetType(), type, expr);
970    } else if (lmirBuilder_->LiteCGGetTypeKind(expr.GetType()) == maple::litecg::kLiteCGTypeScalar) {
971        return lmirBuilder_->Cvt(lmirBuilder_->i64Type, type, expr);
972    } else {
973        LOG_COMPILER(FATAL) << "can't Canonicalize to Ptr: ";
974        UNREACHABLE();
975    }
976    return expr;
977}
978
979void LiteCGIRBuilder::VisitAdd(GateRef gate, GateRef e1, GateRef e2)
980{
981    Expr e1Value = GetExprFromGate(e1);
982    Expr e2Value = GetExprFromGate(e2);
983    // save glue + offset
984    if (e1 == acc_.GetGlueFromArgList() && acc_.GetOpCode(e2) == OpCode::CONSTANT) {
985        SaveGate2Expr(gate, e2Value, true);
986        return;
987    }
988
989    Expr result;
990    /*
991     *  If the first operand is pointer, special treatment is needed
992     *  1) add, pointer, int
993     *  2) add, vector{i8* x 2}, int
994     */
995    LiteCGType *returnType = ConvertLiteCGTypeFromGate(gate);
996    auto machineType = acc_.GetMachineType(gate);
997    if (IsAddIntergerType(machineType)) {
998        auto e1Type = ConvertLiteCGTypeFromGate(e1);
999        auto e1TypeKind = lmirBuilder_->LiteCGGetTypeKind(e1Type);
1000        auto e2Type = ConvertLiteCGTypeFromGate(e2);
1001        if (e1TypeKind == maple::litecg::kLiteCGTypePointer) {
1002            Expr tmp1 = lmirBuilder_->Cvt(e1Type, lmirBuilder_->i64Type, e1Value);
1003            Expr tmp2 =
1004                (e2Type == lmirBuilder_->i64Type) ? e2Value : lmirBuilder_->Cvt(e2Type, lmirBuilder_->i64Type, e2Value);
1005            Expr tmp3 = lmirBuilder_->Add(lmirBuilder_->i64Type, tmp1, tmp2);
1006            result = lmirBuilder_->Cvt(lmirBuilder_->i64Type, returnType, tmp3);
1007            SaveGate2Expr(gate, result);
1008            // set the base reference of derived reference
1009            if (e1Type == lmirBuilder_->i64RefType) {
1010                ASSERT(!e1Value.IsDread());
1011                auto e1BaseIter = derivedGate2BaseGate_.find(e1);
1012                derivedGate2BaseGate_[gate] = (e1BaseIter == derivedGate2BaseGate_.end() ? e1 : e1BaseIter->second);
1013            }
1014            return;
1015        } else {
1016            Expr tmp1Expr = (e1Type == returnType) ? e1Value : lmirBuilder_->Cvt(e1Type, returnType, e1Value);
1017            Expr tmp2Expr = (e2Type == returnType) ? e2Value : lmirBuilder_->Cvt(e2Type, returnType, e2Value);
1018            result = lmirBuilder_->Add(returnType, tmp1Expr, tmp2Expr);
1019        }
1020    } else if (machineType == MachineType::F64) {
1021        result = lmirBuilder_->Add(lmirBuilder_->f64Type, e1Value, e2Value);
1022    } else {
1023        LOG_ECMA(FATAL) << "this branch is unreachable";
1024        UNREACHABLE();
1025    }
1026    SaveGate2Expr(gate, result);
1027}
1028
1029void LiteCGIRBuilder::HandleLoad(GateRef gate)
1030{
1031    VisitLoad(gate, acc_.GetIn(gate, 1));
1032}
1033
1034void LiteCGIRBuilder::VisitLoad(GateRef gate, GateRef base)
1035{
1036    Expr baseAddr = GetExprFromGate(base);
1037
1038    LiteCGType *returnType = ConvertLiteCGTypeFromGate(gate);
1039    LiteCGType *memType = (lmirBuilder_->IsHeapPointerType(returnType)) ? lmirBuilder_->CreateRefType(returnType)
1040                                                                        : lmirBuilder_->CreatePtrType(returnType);
1041    baseAddr = CanonicalizeToPtr(baseAddr, memType);
1042    Expr result = lmirBuilder_->Iread(returnType, baseAddr, memType);
1043    SaveGate2Expr(gate, result);
1044}
1045
1046void LiteCGIRBuilder::HandleCmp(GateRef gate)
1047{
1048    GateRef left = acc_.GetIn(gate, 0);
1049    GateRef right = acc_.GetIn(gate, 1);
1050    VisitCmp(gate, left, right);
1051}
1052
1053IntCmpCondition LiteCGIRBuilder::ConvertLiteCGPredicateFromICMP(ICmpCondition cond) const
1054{
1055    switch (cond) {
1056        case ICmpCondition::SLT:
1057            return IntCmpCondition::kSLT;
1058        case ICmpCondition::SLE:
1059            return IntCmpCondition::kSLE;
1060        case ICmpCondition::SGT:
1061            return IntCmpCondition::kSGT;
1062        case ICmpCondition::SGE:
1063            return IntCmpCondition::kSGE;
1064        case ICmpCondition::ULT:
1065            return IntCmpCondition::kULT;
1066        case ICmpCondition::ULE:
1067            return IntCmpCondition::kULE;
1068        case ICmpCondition::UGT:
1069            return IntCmpCondition::kUGT;
1070        case ICmpCondition::UGE:
1071            return IntCmpCondition::kUGE;
1072        case ICmpCondition::NE:
1073            return IntCmpCondition::kNE;
1074        case ICmpCondition::EQ:
1075            return IntCmpCondition::kEQ;
1076        default:
1077            LOG_COMPILER(FATAL) << "unexpected cond!";
1078            UNREACHABLE();
1079    }
1080    return IntCmpCondition::kEQ;
1081}
1082
1083FloatCmpCondition LiteCGIRBuilder::ConvertLiteCGPredicateFromFCMP(FCmpCondition cond) const
1084{
1085    switch (cond) {
1086        case FCmpCondition::OLT:
1087            return FloatCmpCondition::kOLT;
1088        case FCmpCondition::OLE:
1089            return FloatCmpCondition::kOLE;
1090        case FCmpCondition::OGT:
1091            return FloatCmpCondition::kOGT;
1092        case FCmpCondition::OGE:
1093            return FloatCmpCondition::kOGE;
1094        case FCmpCondition::ONE:
1095            return FloatCmpCondition::kONE;
1096        case FCmpCondition::OEQ:
1097            return FloatCmpCondition::kOEQ;
1098        default:
1099            LOG_COMPILER(FATAL) << "unexpected cond!";
1100            UNREACHABLE();
1101    }
1102    return FloatCmpCondition::kOEQ;
1103}
1104
1105void LiteCGIRBuilder::VisitCmp(GateRef gate, GateRef e1, GateRef e2)
1106{
1107    Expr e1Value = GetExprFromGate(e1);
1108    Expr e2Value = GetExprFromGate(e2);
1109    LiteCGType *returnType = ConvertLiteCGTypeFromGate(gate);
1110
1111    [[maybe_unused]] auto e1ValCode = acc_.GetMachineType(e1);
1112    [[maybe_unused]] auto e2ValCode = acc_.GetMachineType(e2);
1113    ASSERT((e1ValCode == e2ValCode) ||
1114           (compCfg_->Is64Bit() && (e1ValCode == MachineType::ARCH) && (e2ValCode == MachineType::I64)) ||
1115           (compCfg_->Is64Bit() && (e2ValCode == MachineType::ARCH) && (e1ValCode == MachineType::I64)));
1116    auto op = acc_.GetOpCode(gate);
1117    if (op == OpCode::ICMP) {
1118        auto cond = acc_.GetICmpCondition(gate);
1119        auto litecgCond = ConvertLiteCGPredicateFromICMP(cond);
1120        Expr result = lmirBuilder_->ICmp(returnType, e1Value, e2Value, litecgCond);
1121        SaveGate2Expr(gate, result);
1122    } else if (op == OpCode::FCMP) {
1123        auto cond = acc_.GetFCmpCondition(gate);
1124        auto litecgCond = ConvertLiteCGPredicateFromFCMP(cond);
1125        Expr result = lmirBuilder_->FCmp(returnType, e1Value, e2Value, litecgCond);
1126        SaveGate2Expr(gate, result);
1127    } else {
1128        LOG_ECMA(FATAL) << "this branch is unreachable";
1129        UNREACHABLE();
1130    }
1131}
1132
1133void LiteCGIRBuilder::HandleBranch(GateRef gate)
1134{
1135    std::vector<GateRef> ins;
1136    acc_.GetIns(gate, ins);
1137    std::vector<GateRef> outs;
1138    acc_.GetOutStates(gate, outs);
1139    GateRef bTrue = (acc_.GetOpCode(outs[0]) == OpCode::IF_TRUE) ? outs[0] : outs[1];
1140    GateRef bFalse = (acc_.GetOpCode(outs[0]) == OpCode::IF_FALSE) ? outs[0] : outs[1];
1141    int bbTrue = instID2bbID_[acc_.GetId(bTrue)];
1142    int bbFalse = instID2bbID_[acc_.GetId(bFalse)];
1143    VisitBranch(gate, ins[1], bbTrue, bbFalse);
1144}
1145
1146void LiteCGIRBuilder::VisitBranch(GateRef gate, GateRef cmp, int btrue, int bfalse)
1147{
1148    if ((gate2Expr_.count(cmp) == 0) && (acc_.GetOpCode(cmp) != OpCode::CONSTANT)) {
1149        OPTIONAL_LOG_COMPILER(ERROR) << "Branch condition gate is nullptr!";
1150        return;
1151    }
1152    uint32_t trueWeight = 0;
1153    uint32_t falseWeight = 0;
1154    if (acc_.HasBranchWeight(gate)) {
1155        trueWeight = acc_.GetTrueWeight(gate);
1156        falseWeight = acc_.GetFalseWeight(gate);
1157    }
1158    BB &curBB = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
1159    lmirBuilder_->AppendBB(curBB);
1160    BB &bb = CreateBB();
1161    BB &trueBB = GetOrCreateBB(btrue);
1162    BB &falseBB = GetOrCreateBB(bfalse);
1163    // we hope that branch with higher probability can be placed immediatly behind
1164    if (trueWeight < falseWeight) {
1165        Stmt &stmt = lmirBuilder_->Goto(falseBB);
1166        lmirBuilder_->AppendStmt(bb, stmt);
1167        lmirBuilder_->AppendBB(bb);
1168        Expr cond = GetExprFromGate(cmp);
1169        Stmt &condBR = lmirBuilder_->CondGoto(cond, trueBB, true);
1170        lmirBuilder_->AppendStmt(curBB, condBR);
1171        return;
1172    }
1173    Stmt &stmt = lmirBuilder_->Goto(trueBB);
1174    lmirBuilder_->AppendStmt(bb, stmt);
1175    lmirBuilder_->AppendBB(bb);
1176    Expr cond = GetExprFromGate(cmp);
1177    Stmt &condBR = lmirBuilder_->CondGoto(cond, falseBB, false);
1178    lmirBuilder_->AppendStmt(curBB, condBR);
1179}
1180
1181void LiteCGIRBuilder::HandleReturn(GateRef gate)
1182{
1183    std::vector<GateRef> ins;
1184    acc_.GetIns(gate, ins);
1185    VisitReturn(gate, 1, ins);
1186}
1187
1188void LiteCGIRBuilder::VisitReturn([[maybe_unused]] GateRef gate, [[maybe_unused]] GateRef popCount,
1189                                  const std::vector<GateRef> &operands)
1190{
1191    // [STATE] [DEPEND] [VALUE] [RETURN_LIST]
1192    GateRef operand = operands[2];  // 2: skip 2 in gate that are not data gate
1193    Expr returnValue = GetExprFromGate(operand);
1194    Stmt &returnNode = lmirBuilder_->Return(returnValue);
1195    BB &curBB = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
1196    lmirBuilder_->AppendStmt(curBB, returnNode);
1197    lmirBuilder_->AppendBB(curBB);
1198}
1199
1200Expr LiteCGIRBuilder::GetRTStubOffset(Expr glue, int index)
1201{
1202    size_t slotOffset = JSThread::GlueData::GetRTStubEntriesOffset(compCfg_->Is32Bit()) + index * slotSize_;
1203    Const &constVal = lmirBuilder_->CreateIntConst(glue.GetType(), static_cast<int64_t>(slotOffset));
1204    return lmirBuilder_->ConstVal(constVal);
1205}
1206
1207Expr LiteCGIRBuilder::GetCoStubOffset(Expr glue, int index) const
1208{
1209    size_t offset =
1210        JSThread::GlueData::GetCOStubEntriesOffset(compCfg_->Is32Bit()) + static_cast<size_t>(index * slotSize_);
1211    Const &constVal = lmirBuilder_->CreateIntConst(glue.GetType(), static_cast<int64_t>(offset));
1212    return lmirBuilder_->ConstVal(constVal);
1213}
1214
1215Expr LiteCGIRBuilder::GetBaselineStubOffset(Expr glue, int index) const
1216{
1217    size_t offset =
1218        JSThread::GlueData::GetBaselineStubEntriesOffset(compCfg_->Is32Bit()) + static_cast<size_t>(index * slotSize_);
1219    Const &constVal = lmirBuilder_->CreateIntConst(glue.GetType(), static_cast<int64_t>(offset));
1220    return lmirBuilder_->ConstVal(constVal);
1221}
1222
1223void LiteCGIRBuilder::HandleRuntimeCall(GateRef gate)
1224{
1225    std::vector<GateRef> ins;
1226    acc_.GetIns(gate, ins);
1227    VisitRuntimeCall(gate, ins);
1228};
1229
1230LiteCGType *LiteCGIRBuilder::ConvertLiteCGTypeFromVariableType(VariableType type) const
1231{
1232    std::map<VariableType, LiteCGType *> machineTypeMap = {
1233        {VariableType::VOID(), lmirBuilder_->voidType},
1234        {VariableType::BOOL(), lmirBuilder_->u1Type},
1235        {VariableType::INT8(), lmirBuilder_->i8Type},
1236        {VariableType::INT16(), lmirBuilder_->i16Type},
1237        {VariableType::INT32(), lmirBuilder_->i32Type},
1238        {VariableType::INT64(), lmirBuilder_->i64Type},
1239        {VariableType::FLOAT32(), lmirBuilder_->f32Type},
1240        {VariableType::FLOAT64(), lmirBuilder_->f64Type},
1241        {VariableType::NATIVE_POINTER(), lmirBuilder_->i64Type},
1242        {VariableType::JS_POINTER(), lmirBuilder_->i64RefType},
1243        {VariableType::JS_ANY(), lmirBuilder_->i64RefType},
1244    };
1245    return machineTypeMap[type];
1246}
1247
1248LiteCGType *LiteCGIRBuilder::GenerateFuncType(const std::vector<Expr> &params, const CallSignature *stubDescriptor)
1249{
1250    LiteCGType *retType = ConvertLiteCGTypeFromVariableType(stubDescriptor->GetReturnType());
1251    std::vector<LiteCGType *> paramTys;
1252    for (auto value : params) {
1253        paramTys.emplace_back(value.GetType());
1254    }
1255    LiteCGType *functionType = lmirBuilder_->CreateFuncType(paramTys, retType, false);
1256    return functionType;
1257}
1258
1259LiteCGType *LiteCGIRBuilder::GetFuncType(const CallSignature *stubDescriptor) const
1260{
1261    LiteCGType *returnType = ConvertLiteCGTypeFromVariableType(stubDescriptor->GetReturnType());
1262    std::vector<LiteCGType *> paramTys;
1263    auto paramCount = stubDescriptor->GetParametersCount();
1264    auto paramsType = stubDescriptor->GetParametersType();
1265    if (paramsType != nullptr) {
1266        LiteCGType *glueType = ConvertLiteCGTypeFromVariableType(paramsType[0]);
1267        paramTys.push_back(glueType);
1268
1269        for (size_t i = 1; i < paramCount; i++) {
1270            paramTys.push_back(ConvertLiteCGTypeFromVariableType(paramsType[i]));
1271        }
1272    }
1273    auto funcType = lmirBuilder_->CreateFuncType(paramTys, returnType, stubDescriptor->IsVariadicArgs());
1274    return funcType;
1275}
1276
1277Expr LiteCGIRBuilder::GetFunction(BB &bb, Expr glue, const CallSignature *signature, Expr rtbaseoffset,
1278                                  const std::string &realName) const
1279{
1280    LiteCGType *rtfuncType = GetFuncType(signature);
1281    LiteCGType *rtfuncTypePtr = lmirBuilder_->CreatePtrType(rtfuncType);
1282    LiteCGType *rtFuncTypePtrPtr = lmirBuilder_->CreatePtrType(rtfuncTypePtr);
1283    LiteCGType *glueType = (glue.GetType());
1284    LiteCGType *glueTypePtr = lmirBuilder_->CreatePtrType(glueType);
1285    Expr rtbaseAddr = lmirBuilder_->Cvt(rtbaseoffset.GetType(), glueTypePtr, rtbaseoffset);
1286
1287    Expr funcAddr = lmirBuilder_->Iread(glueType, rtbaseAddr, glueTypePtr);
1288    Expr callee = lmirBuilder_->Cvt(glueType, rtFuncTypePtrPtr, funcAddr);
1289
1290    std::string name = realName.empty() ? signature->GetName() : realName;
1291    Stmt &comment = lmirBuilder_->Comment("function: " + name);
1292    lmirBuilder_->AppendStmt(bb, comment);
1293    PregIdx funcPregIdx = lmirBuilder_->CreatePreg(callee.GetType());
1294    Stmt &funcAddrNode = lmirBuilder_->Regassign(callee, funcPregIdx);
1295    lmirBuilder_->AppendStmt(bb, funcAddrNode);
1296
1297    return lmirBuilder_->Regread(funcPregIdx);
1298}
1299
1300bool LiteCGIRBuilder::IsOptimizedJSFunction() const
1301{
1302    return circuit_->GetFrameType() == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
1303        circuit_->GetFrameType() == FrameType::FASTJIT_FUNCTION_FRAME;
1304}
1305
1306bool LiteCGIRBuilder::IsOptimized() const
1307{
1308    return circuit_->GetFrameType() == FrameType::OPTIMIZED_FRAME;
1309}
1310
1311CallExceptionKind LiteCGIRBuilder::GetCallExceptionKind(size_t index, OpCode op) const
1312{
1313    bool hasPcOffset = IsOptimizedJSFunction() &&
1314                       ((op == OpCode::NOGC_RUNTIME_CALL && (kungfu::RuntimeStubCSigns::IsAsmStub(index))) ||
1315                        (op == OpCode::CALL) || (op == OpCode::RUNTIME_CALL));
1316    return hasPcOffset ? CallExceptionKind::HAS_PC_OFFSET : CallExceptionKind::NO_PC_OFFSET;
1317}
1318
1319void LiteCGIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &inList)
1320{
1321    StubIdType stubId = RTSTUB_ID(CallRuntime);
1322    Expr glue = GetGlue(inList);
1323    int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
1324    Expr rtoffset = GetRTStubOffset(glue, stubIndex);
1325    Expr rtbaseOffset = lmirBuilder_->Add(glue.GetType(), glue, rtoffset);
1326    const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
1327
1328    CallExceptionKind kind = GetCallExceptionKind(stubIndex, OpCode::RUNTIME_CALL);
1329    bool hasPCOffset = (kind == CallExceptionKind::HAS_PC_OFFSET);
1330    size_t actualNumArgs = hasPCOffset ? (inList.size() - 2) : inList.size();  // 2: pcOffset and frameArgs
1331
1332    std::vector<Expr> params;
1333    params.push_back(glue);  // glue
1334
1335    const int index = static_cast<int>(acc_.GetConstantValue(inList[static_cast<int>(CallInputs::TARGET)]));
1336    Expr indexValue =
1337        lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->u64Type, static_cast<uint64_t>(index)));
1338    params.push_back(indexValue);  // target
1339
1340    const int64_t argc = actualNumArgs - static_cast<size_t>(CallInputs::FIRST_PARAMETER);
1341    Expr argcValue =
1342        lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->u64Type, static_cast<uint64_t>(argc)));
1343    params.push_back(argcValue);  // argc
1344
1345    for (size_t paraIdx = static_cast<size_t>(CallInputs::FIRST_PARAMETER); paraIdx < actualNumArgs; ++paraIdx) {
1346        GateRef gateTmp = inList[paraIdx];
1347        params.push_back(GetExprFromGate(gateTmp));
1348    }
1349
1350    std::string targetName = RuntimeStubCSigns::GetRTName(index);
1351    BB &bb = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
1352    std::string name = targetName.empty() ? signature->GetName() : targetName;
1353    Expr callee = GetFunction(bb, glue, signature, rtbaseOffset, name);
1354
1355    LiteCGType *returnType = ConvertLiteCGTypeFromVariableType(signature->GetReturnType());
1356    bool returnVoid = (returnType == lmirBuilder_->voidType);
1357    PregIdx returnPregIdx = returnVoid ? -1 : lmirBuilder_->CreatePreg(returnType);
1358    Stmt &callNode =
1359        returnVoid ? lmirBuilder_->ICall(callee, params) : lmirBuilder_->ICall(callee, params, returnPregIdx);
1360
1361    if (kind == CallExceptionKind::HAS_PC_OFFSET) {
1362        std::unordered_map<int, LiteCGValue> deoptBundleInfo;
1363        auto frameArgs = inList.at(actualNumArgs);
1364        Expr pcOffset = hasPCOffset ? (GetExprFromGate(inList[actualNumArgs + 1]))
1365                                    : lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i32Type, 0));
1366        CollectExraCallSiteInfo(deoptBundleInfo, pcOffset, frameArgs);
1367        lmirBuilder_->SetCallStmtDeoptBundleInfo(callNode, deoptBundleInfo);
1368    }
1369    lmirBuilder_->SetStmtCallConv(callNode, maple::litecg::Web_Kit_JS_Call);
1370    lmirBuilder_->AppendStmt(bb, callNode);
1371    if (!returnVoid) {
1372        SaveGate2Expr(gate, lmirBuilder_->Regread(returnPregIdx));
1373    }
1374}
1375
1376void LiteCGIRBuilder::HandleZExtInt(GateRef gate)
1377{
1378    std::vector<GateRef> ins;
1379    acc_.GetIns(gate, ins);
1380    VisitZExtInt(gate, ins[0]);
1381}
1382
1383void LiteCGIRBuilder::VisitZExtInt(GateRef gate, GateRef e1)
1384{
1385    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) <=
1386           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
1387    LiteCGType *fromType = ConvertLiteCGTypeFromGate(e1);
1388    LiteCGType *toType = ConvertLiteCGTypeFromGate(gate, false);
1389    Expr result = lmirBuilder_->ZExt(fromType, toType, GetExprFromGate(e1));
1390    SaveGate2Expr(gate, result);
1391}
1392
1393void LiteCGIRBuilder::HandleIntDiv(GateRef gate)
1394{
1395    auto g0 = acc_.GetIn(gate, 0);
1396    auto g1 = acc_.GetIn(gate, 1);
1397    VisitIntDiv(gate, g0, g1);
1398}
1399
1400void LiteCGIRBuilder::VisitIntDiv(GateRef gate, GateRef e1, GateRef e2)
1401{
1402    Expr e1Value = GetExprFromGate(e1);
1403    Expr e2Value = GetExprFromGate(e2);
1404    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1405    Expr result = lmirBuilder_->SDiv(type, e1Value, e2Value);
1406    SaveGate2Expr(gate, result);
1407}
1408
1409Expr LiteCGIRBuilder::GetCallee(maple::litecg::BB &bb, const std::vector<GateRef> &inList,
1410                                const CallSignature *signature, const std::string &realName)
1411{
1412    LiteCGType *rtfuncType = GetFuncType(signature);
1413    LiteCGType *rtfuncTypePtr = lmirBuilder_->CreatePtrType(rtfuncType);
1414    LiteCGType *rtfuncTypePtrPtr = lmirBuilder_->CreatePtrType(rtfuncTypePtr);
1415    Expr code = GetExprFromGate(inList[static_cast<size_t>(CallInputs::TARGET)]);
1416    Expr callee = lmirBuilder_->Cvt(code.GetType(), rtfuncTypePtrPtr, code);
1417
1418    std::string name = realName.empty() ? signature->GetName() : realName;
1419    Stmt &comment = lmirBuilder_->Comment("function: " + name);
1420    lmirBuilder_->AppendStmt(bb, comment);
1421
1422    PregIdx funcPregIdx = lmirBuilder_->CreatePreg(callee.GetType());
1423    Stmt &funcAddrNode = lmirBuilder_->Regassign(callee, funcPregIdx);
1424    lmirBuilder_->AppendStmt(bb, funcAddrNode);
1425    return lmirBuilder_->Regread(funcPregIdx);
1426}
1427
1428void LiteCGIRBuilder::HandleRuntimeCallWithArgv(GateRef gate)
1429{
1430    std::vector<GateRef> ins;
1431    acc_.GetIns(gate, ins);
1432    VisitRuntimeCallWithArgv(gate, ins);
1433}
1434
1435void LiteCGIRBuilder::VisitRuntimeCallWithArgv(GateRef gate, const std::vector<GateRef> &inList)
1436{
1437    ASSERT(IsOptimized() == true);
1438    StubIdType stubId = RTSTUB_ID(CallRuntimeWithArgv);
1439    Expr glue = GetGlue(inList);
1440    int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
1441    Expr rtoffset = GetRTStubOffset(glue, stubIndex);
1442    Expr rtbaseoffset = lmirBuilder_->Add(glue.GetType(), glue, rtoffset);
1443    const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
1444
1445    std::vector<Expr> params;
1446    params.push_back(glue);  // glue
1447
1448    uint64_t index = acc_.GetConstantValue(inList[static_cast<size_t>(CallInputs::TARGET)]);
1449    auto targetId = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i64Type, index));
1450    params.push_back(targetId);  // target
1451    for (size_t paraIdx = static_cast<size_t>(CallInputs::FIRST_PARAMETER); paraIdx < inList.size(); ++paraIdx) {
1452        GateRef gateTmp = inList[paraIdx];
1453        params.push_back(GetExprFromGate(gateTmp));
1454    }
1455
1456    BB &bb = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
1457    std::string targetName = RuntimeStubCSigns::GetRTName(index);
1458    std::string name = targetName.empty() ? signature->GetName() : targetName;
1459    Expr callee = GetFunction(bb, glue, signature, rtbaseoffset, name);
1460
1461    static uint32_t val = 0;
1462    std::string returnCallValName = name + "Ret" + std::to_string(val++);
1463    LiteCGType *returnType = ConvertLiteCGTypeFromVariableType(signature->GetReturnType());
1464    Var *returnVar = (returnType == lmirBuilder_->voidType)
1465                         ? nullptr
1466                         : &(lmirBuilder_->CreateLocalVar(returnType, returnCallValName));
1467    Stmt &callNode = lmirBuilder_->ICall(callee, params, returnVar);
1468    lmirBuilder_->AppendStmt(bb, callNode);
1469    if (returnVar != nullptr) {
1470        SaveGate2Expr(gate, lmirBuilder_->Dread(*returnVar));
1471    }
1472}
1473
1474void LiteCGIRBuilder::HandleCall(GateRef gate)
1475{
1476    std::vector<GateRef> ins;
1477    acc_.GetIns(gate, ins);
1478    OpCode callOp = acc_.GetOpCode(gate);
1479    if (callOp == OpCode::CALL || callOp == OpCode::NOGC_RUNTIME_CALL || callOp == OpCode::BUILTINS_CALL ||
1480        callOp == OpCode::BUILTINS_CALL_WITH_ARGV || callOp == OpCode::CALL_OPTIMIZED ||
1481        callOp == OpCode::FAST_CALL_OPTIMIZED || callOp == OpCode::BASELINE_CALL) {
1482        VisitCall(gate, ins, callOp);
1483    } else {
1484        LOG_ECMA(FATAL) << "this branch is unreachable";
1485        UNREACHABLE();
1486    }
1487}
1488
1489void LiteCGIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList, OpCode op)
1490{
1491    size_t targetIndex = static_cast<size_t>(CallInputs::TARGET);
1492    static_assert(static_cast<size_t>(CallInputs::FIRST_PARAMETER) == 3);
1493    const CallSignature *calleeDescriptor = nullptr;
1494    Expr glue = GetGlue(inList);
1495    Expr callee;
1496    CallExceptionKind kind = CallExceptionKind::NO_PC_OFFSET;
1497    BB &bb = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
1498    if (op == OpCode::CALL) {
1499        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
1500        calleeDescriptor = CommonStubCSigns::Get(index);
1501        Expr rtoffset = GetCoStubOffset(glue, index);
1502        Expr rtbaseoffset = lmirBuilder_->Add(glue.GetType(), glue, rtoffset);
1503        callee = GetFunction(bb, glue, calleeDescriptor, rtbaseoffset);
1504        kind = GetCallExceptionKind(index, op);
1505    } else if (op == OpCode::NOGC_RUNTIME_CALL) {
1506        UpdateLeaveFrame(glue);
1507        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
1508        calleeDescriptor = RuntimeStubCSigns::Get(index);
1509        Expr rtoffset = GetRTStubOffset(glue, index);
1510        Expr rtbaseoffset = lmirBuilder_->Add(glue.GetType(), glue, rtoffset);
1511        callee = GetFunction(bb, glue, calleeDescriptor, rtbaseoffset);
1512        kind = GetCallExceptionKind(index, op);
1513    } else if (op == OpCode::CALL_OPTIMIZED) {
1514        calleeDescriptor = RuntimeStubCSigns::GetOptimizedCallSign();
1515        callee = GetCallee(bb, inList, calleeDescriptor, calleeDescriptor->GetName());
1516        if (IsOptimizedJSFunction()) {
1517            kind = CallExceptionKind::HAS_PC_OFFSET;
1518        } else {
1519            kind = CallExceptionKind::NO_PC_OFFSET;
1520        }
1521    } else if (op == OpCode::FAST_CALL_OPTIMIZED) {
1522        calleeDescriptor = RuntimeStubCSigns::GetOptimizedFastCallSign();
1523        callee = GetCallee(bb, inList, calleeDescriptor, calleeDescriptor->GetName());
1524        if (IsOptimizedJSFunction()) {
1525            kind = CallExceptionKind::HAS_PC_OFFSET;
1526        } else {
1527            kind = CallExceptionKind::NO_PC_OFFSET;
1528        }
1529    } else if (op == OpCode::BASELINE_CALL) {
1530        const size_t index = acc_.GetConstantValue(inList[targetIndex]);
1531        calleeDescriptor = BaselineStubCSigns::Get(index);
1532        Expr rtoffset = GetBaselineStubOffset(glue, index);
1533        Expr rtbaseoffset = lmirBuilder_->Add(glue.GetType(), glue, rtoffset);
1534        callee = GetFunction(bb, glue, calleeDescriptor, rtbaseoffset);
1535        kind = GetCallExceptionKind(index, op);
1536    } else {
1537        ASSERT(op == OpCode::BUILTINS_CALL || op == OpCode::BUILTINS_CALL_WITH_ARGV);
1538        Expr opcodeOffset = GetExprFromGate(inList[targetIndex]);
1539        Expr rtoffset = GetBuiltinsStubOffset(glue);
1540        Expr offset = lmirBuilder_->Add(rtoffset.GetType(), rtoffset, opcodeOffset);
1541        Expr rtbaseoffset = lmirBuilder_->Add(glue.GetType(), glue, offset);
1542        if (op == OpCode::BUILTINS_CALL) {
1543            calleeDescriptor = BuiltinsStubCSigns::BuiltinsCSign();
1544        } else {
1545            calleeDescriptor = BuiltinsStubCSigns::BuiltinsWithArgvCSign();
1546        }
1547        callee = GetFunction(bb, glue, calleeDescriptor, rtbaseoffset);
1548    }
1549
1550    std::vector<Expr> params;
1551    const size_t firstArg = static_cast<size_t>(CallInputs::FIRST_PARAMETER);
1552    GateRef glueGate = inList[firstArg];
1553    params.push_back(GetExprFromGate(glueGate));
1554
1555    LiteCGType *calleeFuncType = lmirBuilder_->LiteCGGetPointedType(callee.GetType());
1556    std::vector<LiteCGType *> paramTypes = lmirBuilder_->LiteCGGetFuncParamTypes(calleeFuncType);
1557
1558    bool hasPCOffset = (kind == CallExceptionKind::HAS_PC_OFFSET);
1559    size_t actualNumArgs = hasPCOffset ? (inList.size() - 2) : inList.size();  // 2: pcOffset and frameArgs
1560
1561    // then push the actual parameter for js function call
1562    for (size_t paraIdx = firstArg + 1; paraIdx < actualNumArgs; ++paraIdx) {
1563        GateRef gateTmp = inList[paraIdx];
1564        Expr gateExpr = GetExprFromGate(gateTmp);
1565        const auto gateTmpType = gateExpr.GetType();
1566        if (params.size() < paramTypes.size()) {  // this condition will be false for variadic arguments
1567            const auto paramType = paramTypes.at(params.size());
1568            // match parameter types and function signature types
1569            if (lmirBuilder_->IsHeapPointerType(paramType) && !lmirBuilder_->IsHeapPointerType(gateTmpType)) {
1570                Expr cvtI64Expr = lmirBuilder_->Cvt(gateTmpType, lmirBuilder_->i64Type, gateExpr);
1571                params.push_back(lmirBuilder_->Cvt(lmirBuilder_->i64Type, paramType, cvtI64Expr));
1572            } else {
1573                params.push_back(lmirBuilder_->Cvt(gateTmpType, paramType, gateExpr));
1574            }
1575        } else {
1576            params.push_back(gateExpr);
1577        }
1578    }
1579
1580    LiteCGType *returnType = lmirBuilder_->LiteCGGetFuncReturnType(calleeFuncType);
1581    bool returnVoid = (returnType == lmirBuilder_->voidType);
1582    PregIdx returnPregIdx = returnVoid ? -1 : lmirBuilder_->CreatePreg(returnType);
1583    Stmt &callNode =
1584        returnVoid ? lmirBuilder_->ICall(callee, params) : lmirBuilder_->ICall(callee, params, returnPregIdx);
1585    if (kind == CallExceptionKind::HAS_PC_OFFSET) {
1586        std::unordered_map<int, LiteCGValue> deoptBundleInfo;
1587        auto frameArgs = inList.at(actualNumArgs);
1588        Expr pcOffset = hasPCOffset ? (GetExprFromGate(inList[actualNumArgs + 1]))
1589                                    : lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i32Type, 0));
1590        CollectExraCallSiteInfo(deoptBundleInfo, pcOffset, frameArgs);
1591        lmirBuilder_->SetCallStmtDeoptBundleInfo(callNode, deoptBundleInfo);
1592    }
1593    lmirBuilder_->SetStmtCallConv(callNode, ConvertCallAttr(calleeDescriptor->GetCallConv()));
1594    lmirBuilder_->AppendStmt(bb, callNode);
1595    if (!returnVoid) {
1596        SaveGate2Expr(gate, lmirBuilder_->Regread(returnPregIdx));
1597    }
1598}
1599
1600void LiteCGIRBuilder::CollectExraCallSiteInfo(std::unordered_map<int, maple::litecg::LiteCGValue> &deoptBundleInfo,
1601                                              maple::litecg::Expr pcOffset, GateRef frameArgs)
1602{
1603    // pc offset
1604    auto pcIndex = static_cast<int>(SpecVregIndex::PC_OFFSET_INDEX);
1605    ASSERT(pcOffset.IsConstValue());
1606    deoptBundleInfo.insert(std::pair<int, LiteCGValue>(
1607        pcIndex, {LiteCGValueKind::kConstKind, lmirBuilder_->GetConstFromExpr(pcOffset)}));
1608
1609    if (!enableOptInlining_) {
1610        return;
1611    }
1612
1613    if (frameArgs == Circuit::NullGate()) {
1614        return;
1615    }
1616    if (acc_.GetOpCode(frameArgs) != OpCode::FRAME_ARGS) {
1617        return;
1618    }
1619    uint32_t maxDepth = acc_.GetFrameDepth(frameArgs, OpCode::FRAME_ARGS);
1620    if (maxDepth == 0) {
1621        return;
1622    }
1623
1624    maxDepth = std::min(maxDepth, MAX_METHOD_OFFSET_NUM);
1625    size_t shift = Deoptimizier::ComputeShift(MAX_METHOD_OFFSET_NUM);
1626    ArgumentAccessor argAcc(const_cast<Circuit *>(circuit_));
1627    for (int32_t curDepth = static_cast<int32_t>(maxDepth - 1); curDepth >= 0; curDepth--) {
1628        ASSERT(acc_.GetOpCode(frameArgs) == OpCode::FRAME_ARGS);
1629        // method id
1630        uint32_t methodOffset = acc_.TryGetMethodOffset(frameArgs);
1631        frameArgs = acc_.GetFrameState(frameArgs);
1632        if (methodOffset == FrameStateOutput::INVALID_INDEX) {
1633            methodOffset = 0;
1634        }
1635        int32_t specCallTargetIndex = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) - curDepth;
1636        int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(specCallTargetIndex, curDepth, shift);
1637        auto constMethodOffset = lmirBuilder_->GetConstFromExpr(
1638            lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i32Type, methodOffset)));
1639        deoptBundleInfo.insert(
1640            std::pair<int, LiteCGValue>(encodeIndex, {LiteCGValueKind::kConstKind, constMethodOffset}));
1641    }
1642}
1643
1644maple::litecg::ConvAttr LiteCGIRBuilder::ConvertCallAttr(const CallSignature::CallConv callConv)
1645{
1646    switch (callConv) {
1647        case CallSignature::CallConv::GHCCallConv: {
1648            return maple::litecg::GHC_Call;
1649        }
1650        case CallSignature::CallConv::WebKitJSCallConv: {
1651            return maple::litecg::Web_Kit_JS_Call;
1652        }
1653        default: {
1654            return maple::litecg::CCall;
1655        }
1656    }
1657}
1658
1659Expr LiteCGIRBuilder::GetBuiltinsStubOffset(Expr glue)
1660{
1661    Const &constVal = lmirBuilder_->CreateIntConst(
1662        glue.GetType(), JSThread::GlueData::GetBuiltinsStubEntriesOffset(compCfg_->Is32Bit()));
1663    return lmirBuilder_->ConstVal(constVal);
1664}
1665
1666void LiteCGIRBuilder::UpdateLeaveFrame(Expr glue)
1667{
1668    Expr leaveFrameOffset = GetLeaveFrameOffset(glue);
1669    Expr leaveFrameValue = lmirBuilder_->Add(glue.GetType(), glue, leaveFrameOffset);
1670    LiteCGType *glueType = glue.GetType();
1671    LiteCGType *glueTypePtr = lmirBuilder_->CreatePtrType(glueType);
1672    Expr leaveFrameAddr = lmirBuilder_->Cvt(leaveFrameValue.GetType(), glueTypePtr, leaveFrameValue);
1673    Expr fpAddr = CallingFp(true);
1674    Expr fp = lmirBuilder_->Cvt(fpAddr.GetType(), lmirBuilder_->i64Type, fpAddr);
1675
1676    lmirBuilder_->Iassign(fp, leaveFrameAddr, fp.GetType());
1677}
1678
1679bool LiteCGIRBuilder::IsInterpreted() const
1680{
1681    return circuit_->GetFrameType() == FrameType::ASM_INTERPRETER_FRAME;
1682}
1683
1684bool LiteCGIRBuilder::IsBaselineBuiltin() const
1685{
1686    return circuit_->GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME;
1687}
1688
1689Expr LiteCGIRBuilder::CallingFp(bool /*isCaller*/)
1690{
1691    ASSERT(!IsInterpreted() && !IsBaselineBuiltin());
1692    /* 0:calling 1:its caller */
1693    Function &func = lmirBuilder_->GetCurFunction();
1694    return lmirBuilder_->LiteCGGetPregFP(func);
1695}
1696
1697Expr LiteCGIRBuilder::GetLeaveFrameOffset(Expr glue)
1698{
1699    size_t slotOffset = JSThread::GlueData::GetLeaveFrameOffset(compCfg_->Is32Bit());
1700    Const &constVal = lmirBuilder_->CreateIntConst(glue.GetType(), static_cast<int>(slotOffset));
1701    return lmirBuilder_->ConstVal(constVal);
1702}
1703
1704void LiteCGIRBuilder::HandleUDiv(GateRef gate)
1705{
1706    auto g0 = acc_.GetIn(gate, 0);
1707    auto g1 = acc_.GetIn(gate, 1);
1708    VisitUDiv(gate, g0, g1);
1709}
1710
1711void LiteCGIRBuilder::VisitUDiv(GateRef gate, GateRef e1, GateRef e2)
1712{
1713    Expr e1Value = GetExprFromGate(e1);
1714    Expr e2Value = GetExprFromGate(e2);
1715    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1716    Expr result = lmirBuilder_->UDiv(type, e1Value, e2Value);
1717    SaveGate2Expr(gate, result);
1718}
1719
1720void LiteCGIRBuilder::HandleIntAnd(GateRef gate)
1721{
1722    auto g0 = acc_.GetIn(gate, 0);
1723    auto g1 = acc_.GetIn(gate, 1);
1724    VisitIntAnd(gate, g0, g1);
1725}
1726
1727void LiteCGIRBuilder::VisitIntAnd(GateRef gate, GateRef e1, GateRef e2)
1728{
1729    Expr e1Value = GetExprFromGate(e1);
1730    Expr e2Value = GetExprFromGate(e2);
1731    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1732    Expr result = lmirBuilder_->And(type, e1Value, e2Value);
1733    SaveGate2Expr(gate, result);
1734}
1735
1736void LiteCGIRBuilder::HandleIntOr(GateRef gate)
1737{
1738    auto g0 = acc_.GetIn(gate, 0);
1739    auto g1 = acc_.GetIn(gate, 1);
1740    VisitIntOr(gate, g0, g1);
1741}
1742
1743void LiteCGIRBuilder::VisitIntOr(GateRef gate, GateRef e1, GateRef e2)
1744{
1745    Expr e1Value = GetExprFromGate(e1);
1746    Expr e2Value = GetExprFromGate(e2);
1747    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1748    Expr result = lmirBuilder_->Or(type, e1Value, e2Value);
1749    SaveGate2Expr(gate, result);
1750}
1751
1752void LiteCGIRBuilder::HandleIntXor(GateRef gate)
1753{
1754    auto g0 = acc_.GetIn(gate, 0);
1755    auto g1 = acc_.GetIn(gate, 1);
1756    VisitIntXor(gate, g0, g1);
1757}
1758
1759void LiteCGIRBuilder::VisitIntXor(GateRef gate, GateRef e1, GateRef e2)
1760{
1761    Expr e1Value = GetExprFromGate(e1);
1762    Expr e2Value = GetExprFromGate(e2);
1763    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1764    Expr result = lmirBuilder_->Xor(type, e1Value, e2Value);
1765    SaveGate2Expr(gate, result);
1766}
1767
1768void LiteCGIRBuilder::HandleIntLsr(GateRef gate)
1769{
1770    auto g0 = acc_.GetIn(gate, 0);
1771    auto g1 = acc_.GetIn(gate, 1);
1772    VisitIntLsr(gate, g0, g1);
1773}
1774
1775void LiteCGIRBuilder::VisitIntLsr(GateRef gate, GateRef e1, GateRef e2)
1776{
1777    Expr e1Value = GetExprFromGate(e1);
1778    Expr e2Value = GetExprFromGate(e2);
1779    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1780    Expr result = lmirBuilder_->LShr(type, e1Value, e2Value);
1781    SaveGate2Expr(gate, result);
1782}
1783
1784void LiteCGIRBuilder::HandleIntAsr(GateRef gate)
1785{
1786    auto g0 = acc_.GetIn(gate, 0);
1787    auto g1 = acc_.GetIn(gate, 1);
1788    VisitIntAsr(gate, g0, g1);
1789}
1790
1791void LiteCGIRBuilder::VisitIntAsr(GateRef gate, GateRef e1, GateRef e2)
1792{
1793    Expr e1Value = GetExprFromGate(e1);
1794    Expr e2Value = GetExprFromGate(e2);
1795    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1796    Expr result = lmirBuilder_->AShr(type, e1Value, e2Value);
1797    SaveGate2Expr(gate, result);
1798}
1799
1800void LiteCGIRBuilder::HandleBitCast(GateRef gate)
1801{
1802    VisitBitCast(gate, acc_.GetIn(gate, 0));
1803}
1804
1805void LiteCGIRBuilder::VisitBitCast(GateRef gate, GateRef e1)
1806{
1807    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(gate)) ==
1808           GetBitWidthFromMachineType(acc_.GetMachineType(e1)));
1809    LiteCGType *fromType = ConvertLiteCGTypeFromGate(e1);
1810    LiteCGType *toType = ConvertLiteCGTypeFromGate(gate);
1811    Expr e1Value = GetExprFromGate(e1);
1812    Expr result = lmirBuilder_->BitCast(fromType, toType, e1Value);
1813    SaveGate2Expr(gate, result);
1814}
1815
1816void LiteCGIRBuilder::HandleIntLsl(GateRef gate)
1817{
1818    auto g0 = acc_.GetIn(gate, 0);
1819    auto g1 = acc_.GetIn(gate, 1);
1820    VisitIntLsl(gate, g0, g1);
1821}
1822
1823void LiteCGIRBuilder::VisitIntLsl(GateRef gate, GateRef e1, GateRef e2)
1824{
1825    Expr e1Value = GetExprFromGate(e1);
1826    Expr e2Value = GetExprFromGate(e2);
1827    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1828    Expr result = lmirBuilder_->Shl(type, e1Value, e2Value);
1829    SaveGate2Expr(gate, result);
1830}
1831
1832void LiteCGIRBuilder::HandleMod(GateRef gate)
1833{
1834    auto g0 = acc_.GetIn(gate, 0);
1835    auto g1 = acc_.GetIn(gate, 1);
1836    VisitMod(gate, g0, g1);
1837}
1838
1839void LiteCGIRBuilder::VisitMod(GateRef gate, GateRef e1, GateRef e2)
1840{
1841    Expr e1Value = GetExprFromGate(e1);
1842    Expr e2Value = GetExprFromGate(e2);
1843    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1844    ASSERT(type == ConvertLiteCGTypeFromGate(e1));
1845    ASSERT(type == ConvertLiteCGTypeFromGate(e2));
1846    auto machineType = acc_.GetMachineType(gate);
1847    Expr result;
1848    if (machineType == MachineType::I32) {
1849        result = lmirBuilder_->SRem(type, e1Value, e2Value);
1850    } else if (machineType != MachineType::F64) {
1851        LOG_ECMA(FATAL) << "this branch is unreachable";
1852        UNREACHABLE();
1853    }
1854    SaveGate2Expr(gate, result);
1855}
1856
1857void LiteCGIRBuilder::HandleFinishAllocate(GateRef gate)
1858{
1859    GateRef g0 = acc_.GetValueIn(gate, 0);
1860    VisitFinishAllocate(gate, g0);
1861}
1862
1863void LiteCGIRBuilder::VisitFinishAllocate(GateRef gate, GateRef e1)
1864{
1865    Expr result = GetExprFromGate(e1);
1866    SaveGate2Expr(gate, result);
1867}
1868
1869void LiteCGIRBuilder::HandleCastIntXToIntY(GateRef gate)
1870{
1871    VisitCastIntXToIntY(gate, acc_.GetIn(gate, 0));
1872}
1873
1874void LiteCGIRBuilder::VisitCastIntXToIntY(GateRef gate, GateRef e1)
1875{
1876    Expr e1Value = GetExprFromGate(e1);
1877    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) >=
1878           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
1879    auto e1Type = ConvertLiteCGTypeFromGate(e1);
1880    Expr result = lmirBuilder_->Cvt(e1Type, ConvertLiteCGTypeFromGate(gate), e1Value);
1881    SaveGate2Expr(gate, result);
1882}
1883
1884void LiteCGIRBuilder::HandleChangeInt32ToDouble(GateRef gate)
1885{
1886    VisitChangeInt32ToDouble(gate, acc_.GetIn(gate, 0));
1887}
1888
1889void LiteCGIRBuilder::VisitChangeInt32ToDouble(GateRef gate, GateRef e1)
1890{
1891    Expr e1Value = GetExprFromGate(e1);
1892    auto e1Type = ConvertLiteCGTypeFromGate(e1);
1893    Expr result = lmirBuilder_->Cvt(e1Type, ConvertLiteCGTypeFromGate(gate), e1Value);
1894    SaveGate2Expr(gate, result);
1895}
1896
1897void LiteCGIRBuilder::HandleChangeUInt32ToDouble(GateRef gate)
1898{
1899    VisitChangeUInt32ToDouble(gate, acc_.GetIn(gate, 0));
1900}
1901
1902void LiteCGIRBuilder::VisitChangeUInt32ToDouble(GateRef gate, GateRef e1)
1903{
1904    Expr e1Value = GetExprFromGate(e1);
1905    auto e1Type = ConvertLiteCGTypeFromGate(e1);
1906    if (e1Type != lmirBuilder_->u32Type) {
1907        e1Value = lmirBuilder_->Cvt(e1Type, lmirBuilder_->u32Type, e1Value);
1908    }
1909    Expr result = lmirBuilder_->Cvt(lmirBuilder_->u32Type, ConvertLiteCGTypeFromGate(gate), e1Value);
1910    SaveGate2Expr(gate, result);
1911}
1912
1913void LiteCGIRBuilder::HandleChangeDoubleToInt32(GateRef gate)
1914{
1915    VisitChangeDoubleToInt32(gate, acc_.GetIn(gate, 0));
1916}
1917
1918void LiteCGIRBuilder::VisitChangeDoubleToInt32(GateRef gate, GateRef e1)
1919{
1920    Expr e1Value = GetExprFromGate(e1);
1921    auto e1Type = ConvertLiteCGTypeFromGate(e1);
1922    Expr result = lmirBuilder_->Cvt(e1Type, ConvertLiteCGTypeFromGate(gate), e1Value);
1923    SaveGate2Expr(gate, result);
1924}
1925
1926void LiteCGIRBuilder::HandleChangeTaggedPointerToInt64(GateRef gate)
1927{
1928    VisitChangeTaggedPointerToInt64(gate, acc_.GetIn(gate, 0));
1929}
1930
1931void LiteCGIRBuilder::VisitChangeTaggedPointerToInt64(GateRef gate, GateRef e1)
1932{
1933    Expr result = CanonicalizeToInt(e1);
1934    SaveGate2Expr(gate, result);
1935}
1936
1937Expr LiteCGIRBuilder::CanonicalizeToInt(GateRef gate)
1938{
1939    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1940    Expr opnd = GetExprFromGate(gate);
1941    if (lmirBuilder_->LiteCGGetTypeKind(type) == maple::litecg::kLiteCGTypePointer) {
1942        return lmirBuilder_->Cvt(type, lmirBuilder_->i64Type, opnd);
1943    } else if (lmirBuilder_->LiteCGGetTypeKind(type) == maple::litecg::kLiteCGTypeScalar) {
1944        return opnd;
1945    } else {
1946        LOG_COMPILER(FATAL) << "can't Canonicalize to Int64: ";
1947        UNREACHABLE();
1948    }
1949}
1950
1951void LiteCGIRBuilder::HandleChangeInt64ToTagged(GateRef gate)
1952{
1953    VisitChangeInt64ToTagged(gate, acc_.GetIn(gate, 0));
1954}
1955
1956void LiteCGIRBuilder::VisitChangeInt64ToTagged(GateRef gate, GateRef e1)
1957{
1958    Expr e1Value = GetExprFromGate(e1);
1959    ASSERT(lmirBuilder_->LiteCGGetTypeKind(ConvertLiteCGTypeFromGate(e1)) == maple::litecg::kLiteCGTypeScalar);
1960    Expr result = lmirBuilder_->Cvt(lmirBuilder_->i64Type, lmirBuilder_->i64RefType, e1Value);
1961    SaveGate2Expr(gate, result);
1962}
1963
1964void LiteCGIRBuilder::HandleDoubleTrunc(GateRef gate)
1965{
1966    GateRef param = acc_.GetIn(gate, 0);
1967    VisitDoubleTrunc(gate, param);
1968}
1969
1970void LiteCGIRBuilder::VisitDoubleTrunc(GateRef gate, GateRef e1)
1971{
1972    Expr e1Value = GetExprFromGate(e1);
1973    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
1974    ASSERT(acc_.GetMachineType(e1) == acc_.GetMachineType(gate));
1975    Expr result = lmirBuilder_->Trunc(type, type, e1Value);
1976    SaveGate2Expr(gate, result);
1977}
1978
1979void LiteCGIRBuilder::HandleSub(GateRef gate)
1980{
1981    auto g0 = acc_.GetIn(gate, 0);
1982    auto g1 = acc_.GetIn(gate, 1);
1983    VisitSub(gate, g0, g1);
1984}
1985
1986void LiteCGIRBuilder::VisitSub(GateRef gate, GateRef e1, GateRef e2)
1987{
1988    Expr e1Value = GetExprFromGate(e1);
1989    Expr e2Value = GetExprFromGate(e2);
1990    Expr result;
1991    LiteCGType *returnType = ConvertLiteCGTypeFromGate(gate);
1992    auto machineType = acc_.GetMachineType(gate);
1993    if (machineType == MachineType::I16 || machineType == MachineType::I32 || machineType == MachineType::I64 ||
1994        machineType == MachineType::ARCH || machineType == MachineType::F64) {
1995        result = lmirBuilder_->Sub(returnType, e1Value, e2Value);
1996    } else {
1997        LOG_ECMA(FATAL) << "this branch is unreachable";
1998        UNREACHABLE();
1999    }
2000    SaveGate2Expr(gate, result);
2001}
2002
2003void LiteCGIRBuilder::HandleMul(GateRef gate)
2004{
2005    auto g0 = acc_.GetIn(gate, 0);
2006    auto g1 = acc_.GetIn(gate, 1);
2007    VisitMul(gate, g0, g1);
2008}
2009
2010void LiteCGIRBuilder::VisitMul(GateRef gate, GateRef e1, GateRef e2)
2011{
2012    Expr e1Value = GetExprFromGate(e1);
2013    Expr e2Value = GetExprFromGate(e2);
2014    Expr result;
2015    LiteCGType *returnType = ConvertLiteCGTypeFromGate(gate);
2016    auto machineType = acc_.GetMachineType(gate);
2017    if (IsMulIntergerType(machineType)) {
2018        result = lmirBuilder_->Mul(returnType, e1Value, e2Value);
2019    } else if (machineType == MachineType::F64) {
2020        result = lmirBuilder_->Mul(returnType, e1Value, e2Value);
2021    } else {
2022        LOG_ECMA(FATAL) << "this branch is unreachable";
2023        UNREACHABLE();
2024    }
2025    SaveGate2Expr(gate, result);
2026}
2027
2028void LiteCGIRBuilder::HandleIntRev(GateRef gate)
2029{
2030    std::vector<GateRef> ins;
2031    acc_.GetIns(gate, ins);
2032    VisitIntRev(gate, ins[0]);
2033}
2034
2035void LiteCGIRBuilder::VisitIntRev(GateRef gate, GateRef e1)
2036{
2037    Expr e1Value = GetExprFromGate(e1);
2038    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
2039    ASSERT(type == ConvertLiteCGTypeFromGate(e1));
2040    Expr result;
2041    auto machineType = acc_.GetMachineType(gate);
2042    if (machineType <= MachineType::I64 && machineType >= MachineType::I1) {
2043        if (machineType == MachineType::I1) {
2044            result = lmirBuilder_->Lnot(type, e1Value);
2045        } else {
2046            result = lmirBuilder_->Bnot(type, e1Value);
2047        }
2048    } else {
2049        LOG_ECMA(FATAL) << "this branch is unreachable";
2050        UNREACHABLE();
2051    }
2052    SaveGate2Expr(gate, result);
2053}
2054
2055void LiteCGIRBuilder::HandleFloatDiv(GateRef gate)
2056{
2057    auto g0 = acc_.GetIn(gate, 0);
2058    auto g1 = acc_.GetIn(gate, 1);
2059    VisitFloatDiv(gate, g0, g1);
2060}
2061
2062void LiteCGIRBuilder::VisitFloatDiv(GateRef gate, GateRef e1, GateRef e2)
2063{
2064    Expr e1Value = GetExprFromGate(e1);
2065    Expr e2Value = GetExprFromGate(e2);
2066    Expr result = lmirBuilder_->SDiv(ConvertLiteCGTypeFromGate(gate), e1Value, e2Value);
2067    SaveGate2Expr(gate, result);
2068}
2069
2070void LiteCGIRBuilder::HandleTruncFloatToInt(GateRef gate)
2071{
2072    auto g0 = acc_.GetIn(gate, 0);
2073    VisitTruncFloatToInt(gate, g0);
2074}
2075
2076void LiteCGIRBuilder::VisitTruncFloatToInt(GateRef gate, GateRef e1)
2077{
2078    Expr e1Value = GetExprFromGate(e1);
2079    auto machineType = acc_.GetMachineType(e1);
2080    Expr result;
2081    if (machineType <= MachineType::F64 && machineType >= MachineType::F32) {
2082        result = lmirBuilder_->Trunc(ConvertLiteCGTypeFromGate(e1), lmirBuilder_->i64Type, e1Value);
2083    } else {
2084        LOG_ECMA(FATAL) << "this branch is unreachable";
2085        UNREACHABLE();
2086    }
2087    SaveGate2Expr(gate, result);
2088}
2089
2090void LiteCGIRBuilder::HandleAddWithOverflow(GateRef gate)
2091{
2092    auto in0 = acc_.GetIn(gate, 0);
2093    auto in1 = acc_.GetIn(gate, 1);
2094    ASSERT(acc_.GetMachineType(in0) == MachineType::I32);
2095    ASSERT(acc_.GetMachineType(in1) == MachineType::I32);
2096    VisitAddWithOverflow(gate, in0, in1);
2097}
2098
2099void LiteCGIRBuilder::VisitAddWithOverflow(GateRef gate, GateRef e1, GateRef e2)
2100{
2101    VisitBinaryOpWithOverflow(gate, e1, e2, IntrinsicId::INTRN_ADD_WITH_OVERFLOW);
2102}
2103
2104void LiteCGIRBuilder::HandleSubWithOverflow(GateRef gate)
2105{
2106    auto in0 = acc_.GetIn(gate, 0);
2107    auto in1 = acc_.GetIn(gate, 1);
2108    ASSERT(acc_.GetMachineType(in0) == MachineType::I32);
2109    ASSERT(acc_.GetMachineType(in1) == MachineType::I32);
2110    VisitSubWithOverflow(gate, in0, in1);
2111}
2112
2113void LiteCGIRBuilder::VisitSubWithOverflow(GateRef gate, GateRef e1, GateRef e2)
2114{
2115    VisitBinaryOpWithOverflow(gate, e1, e2, IntrinsicId::INTRN_SUB_WITH_OVERFLOW);
2116}
2117
2118void LiteCGIRBuilder::HandleMulWithOverflow(GateRef gate)
2119{
2120    auto in0 = acc_.GetIn(gate, 0);
2121    auto in1 = acc_.GetIn(gate, 1);
2122    ASSERT(acc_.GetMachineType(in0) == MachineType::I32);
2123    ASSERT(acc_.GetMachineType(in1) == MachineType::I32);
2124    VisitMulWithOverflow(gate, in0, in1);
2125}
2126
2127void LiteCGIRBuilder::VisitMulWithOverflow(GateRef gate, GateRef e1, GateRef e2)
2128{
2129    VisitBinaryOpWithOverflow(gate, e1, e2, IntrinsicId::INTRN_MUL_WITH_OVERFLOW);
2130}
2131
2132void LiteCGIRBuilder::VisitBinaryOpWithOverflow(GateRef gate, GateRef e1, GateRef e2, IntrinsicId intrinsicId)
2133{
2134    PregIdx preg1 = lmirBuilder_->CreatePreg(lmirBuilder_->i32Type);
2135    PregIdx preg2 = lmirBuilder_->CreatePreg(lmirBuilder_->u1Type);
2136
2137    // generate function call
2138    Expr e1Value = GetExprFromGate(e1);
2139    Expr e2Value = GetExprFromGate(e2);
2140    std::vector<Expr> args = {e1Value, e2Value};
2141    auto &call = lmirBuilder_->IntrinsicCall(intrinsicId, args, preg1, preg2);
2142    SaveGate2Expr(gate, preg1, preg2);
2143    lmirBuilder_->AppendStmt(GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]), call);
2144}
2145
2146void LiteCGIRBuilder::HandleSExtInt(GateRef gate)
2147{
2148    std::vector<GateRef> ins;
2149    acc_.GetIns(gate, ins);
2150    VisitSExtInt(gate, ins[0]);
2151}
2152
2153void LiteCGIRBuilder::VisitSExtInt(GateRef gate, GateRef e1)
2154{
2155    Expr e1Value = GetExprFromGate(e1);
2156    LiteCGType *fromType = ConvertLiteCGTypeFromGate(e1);
2157    LiteCGType *toType = ConvertLiteCGTypeFromGate(gate);
2158    Expr result = lmirBuilder_->SExt(fromType, toType, e1Value);
2159    SaveGate2Expr(gate, result);
2160}
2161
2162void LiteCGIRBuilder::HandleSqrt(GateRef gate)
2163{
2164    GateRef param = acc_.GetIn(gate, 0);
2165    VisitSqrt(gate, param);
2166}
2167
2168void LiteCGIRBuilder::VisitSqrt(GateRef gate, GateRef e1)
2169{
2170    Expr e1Value = GetExprFromGate(e1);
2171    LiteCGType *type = ConvertLiteCGTypeFromGate(e1);
2172    Expr result;
2173    if (type == lmirBuilder_->f32Type || type == lmirBuilder_->f64Type) {
2174        result = lmirBuilder_->Sqrt(type, e1Value);
2175    } else {
2176        result = lmirBuilder_->Sqrt(lmirBuilder_->f64Type, lmirBuilder_->Cvt(type, lmirBuilder_->f64Type, e1Value));
2177    }
2178    SaveGate2Expr(gate, result);
2179}
2180
2181void LiteCGIRBuilder::HandleExp(GateRef gate)
2182{
2183    (void)gate;
2184    CHECK_FATAL(false, "not support exp !");
2185}
2186
2187void LiteCGIRBuilder::HandleCeil(GateRef gate)
2188{
2189    VisitCeil(gate, acc_.GetIn(gate, 0));
2190}
2191
2192void LiteCGIRBuilder::VisitCeil(GateRef gate, GateRef e1)
2193{
2194    Expr e1Value = GetExprFromGate(e1);
2195    LiteCGType *type = ConvertLiteCGTypeFromGate(e1);
2196    Expr result = lmirBuilder_->Ceil(type, type, e1Value);
2197    SaveGate2Expr(gate, result);
2198}
2199
2200void LiteCGIRBuilder::HandleAbs(GateRef gate)
2201{
2202    VisitAbs(gate, acc_.GetIn(gate, 0));
2203}
2204
2205void LiteCGIRBuilder::VisitAbs(GateRef gate, GateRef e1)
2206{
2207    auto machineType = acc_.GetMachineType(gate);
2208    ASSERT(acc_.GetMachineType(e1) == machineType);
2209    Expr result;
2210    LiteCGType *type = ConvertLiteCGTypeFromGate(e1);
2211    Expr e1Value = GetExprFromGate(e1);
2212    if (machineType == MachineType::I32 || machineType == MachineType::F64) {
2213        result = lmirBuilder_->Abs(type, e1Value);
2214    } else {
2215        LOG_ECMA(FATAL) << "`Abs` type should be untagged double or signed int";
2216        UNREACHABLE();
2217    }
2218    SaveGate2Expr(gate, result);
2219    return;
2220}
2221
2222void LiteCGIRBuilder::HandleMin(GateRef gate)
2223{
2224    VisitMin(gate, acc_.GetIn(gate, 0), acc_.GetIn(gate, 1U));
2225}
2226
2227void LiteCGIRBuilder::VisitMin(GateRef gate, GateRef e1, GateRef e2)
2228{
2229    auto machineType = acc_.GetMachineType(gate);
2230    ASSERT(acc_.GetMachineType(e1) == machineType);
2231    ASSERT(acc_.GetMachineType(e2) == machineType);
2232    Expr result;
2233    LiteCGType *type = ConvertLiteCGTypeFromGate(e1);
2234    Expr e1Value = GetExprFromGate(e1);
2235    Expr e2Value = GetExprFromGate(e2);
2236    if (machineType == MachineType::I32 || machineType == MachineType::F64) {
2237        result = lmirBuilder_->Min(type, e1Value, e2Value);
2238    } else {
2239        LOG_ECMA(FATAL) << "`Min` type should be untagged double or signed int";
2240        UNREACHABLE();
2241    }
2242    SaveGate2Expr(gate, result);
2243    return;
2244}
2245
2246void LiteCGIRBuilder::HandleMax(GateRef gate)
2247{
2248    VisitMax(gate, acc_.GetIn(gate, 0), acc_.GetIn(gate, 1U));
2249}
2250
2251void LiteCGIRBuilder::VisitMax(GateRef gate, GateRef e1, GateRef e2)
2252{
2253    auto machineType = acc_.GetMachineType(gate);
2254    ASSERT(acc_.GetMachineType(e1) == machineType);
2255    ASSERT(acc_.GetMachineType(e2) == machineType);
2256    Expr result;
2257    LiteCGType *type = ConvertLiteCGTypeFromGate(e1);
2258    Expr e1Value = GetExprFromGate(e1);
2259    Expr e2Value = GetExprFromGate(e2);
2260    if (machineType == MachineType::I32 || machineType == MachineType::F64) {
2261        result = lmirBuilder_->Max(type, e1Value, e2Value);
2262    } else {
2263        LOG_ECMA(FATAL) << "`Max` type should be untagged double or signed int";
2264        UNREACHABLE();
2265    }
2266    SaveGate2Expr(gate, result);
2267    return;
2268}
2269
2270void LiteCGIRBuilder::HandleFloor(GateRef gate)
2271{
2272    VisitFloor(gate, acc_.GetIn(gate, 0));
2273}
2274
2275void LiteCGIRBuilder::VisitFloor(GateRef gate, GateRef e1)
2276{
2277    Expr e1Value = GetExprFromGate(e1);
2278    LiteCGType *type = ConvertLiteCGTypeFromGate(e1);
2279    Expr result = lmirBuilder_->Floor(type, type, e1Value);
2280    SaveGate2Expr(gate, result);
2281}
2282
2283void LiteCGIRBuilder::HandleClz32(GateRef gate)
2284{
2285    VisitClz32(gate, acc_.GetIn(gate, 0));
2286}
2287
2288void LiteCGIRBuilder::VisitClz32(GateRef gate,  GateRef param)
2289{
2290    std::vector<Expr> params;
2291    params.push_back(GetExprFromGate(param));
2292    LiteCGType *type = ConvertLiteCGTypeFromGate(param);
2293    Expr result = lmirBuilder_->IntrinsicOp(IntrinsicId::INTRN_C_clz32, type, params);
2294    SaveGate2Expr(gate, result);
2295}
2296
2297
2298void LiteCGIRBuilder::HandleReadSp(GateRef gate)
2299{
2300    ASSERT(acc_.GetOpCode(gate) == OpCode::READSP);
2301    VisitReadSp(gate);
2302}
2303
2304void LiteCGIRBuilder::VisitReadSp(GateRef gate)
2305{
2306    Expr result = lmirBuilder_->LiteCGGetPregSP();
2307    SaveGate2Expr(gate, result);
2308}
2309
2310void LiteCGIRBuilder::HandleInitVreg(GateRef gate)
2311{
2312    ASSERT(acc_.GetOpCode(gate) == OpCode::INITVREG);
2313    VisitInitVreg(gate);
2314}
2315
2316void LiteCGIRBuilder::VisitInitVreg(GateRef gate)
2317{
2318    size_t vregNumber = acc_.GetInitOffset(gate);
2319    BB &bb = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]);
2320    LiteCGType *i64 = lmirBuilder_->i64Type;
2321    LiteCGType *i64Ptr = lmirBuilder_->i64PtrType;
2322    LiteCGType *i64Ref = lmirBuilder_->i64RefType;
2323    LiteCGType *i32 = lmirBuilder_->i32Type;
2324    switch (vregNumber) {
2325        case INIT_VRGE_GLUE: {
2326            // init glue
2327            Expr glue = lmirBuilder_->GenExprFromVar(
2328                lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 0));  // 0 : osr first param - glue
2329            SaveGate2Expr(gate, glue);
2330            return;
2331        }
2332        case INIT_VRGE_ARGS: {
2333            // init argc
2334            SaveGate2Expr(gate, lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, 0)));
2335            return;
2336        }
2337        case INIT_VRGE_FUNCTION: {
2338            // init func
2339            PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref);
2340            // load from frame
2341            Expr sp = lmirBuilder_->GenExprFromVar(
2342                lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1));  // 1 : osr second param - sp
2343            Expr offsetFrame = lmirBuilder_->ConstVal(
2344                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64())));
2345            Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame);
2346            Expr offsetFunc = lmirBuilder_->ConstVal(
2347                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetFunctionOffset(!circuit_->IsArch64())));
2348            Expr addrFunc = lmirBuilder_->Add(i64Ptr, frame, offsetFunc);
2349            Expr ldrFunc = lmirBuilder_->Iread(i64Ref, addrFunc, lmirBuilder_->CreatePtrType(i64Ptr));
2350            lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrFunc, vreg));
2351            if (IsOptimizedJSFunction()) {
2352                // reset jsfunc on OptJSFuncFrame
2353                Expr fpAddr = CallingFp(false);
2354                Expr frameAddr = lmirBuilder_->Cvt(fpAddr.GetType(), lmirBuilder_->i64Type, fpAddr);
2355                size_t reservedOffset = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
2356                Expr frameJSFuncSlotAddr =
2357                    lmirBuilder_->Sub(frameAddr.GetType(), frameAddr,
2358                                      lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, reservedOffset)));
2359                Expr jsFuncAddr = lmirBuilder_->Cvt(frameJSFuncSlotAddr.GetType(),
2360                                                    lmirBuilder_->CreatePtrType(slotType_), frameJSFuncSlotAddr);
2361                Expr jsFuncValue = lmirBuilder_->Cvt(lmirBuilder_->i64PtrType, slotType_, lmirBuilder_->Regread(vreg));
2362                auto &stmt = lmirBuilder_->Iassign(jsFuncValue, jsFuncAddr, jsFuncAddr.GetType());
2363                lmirBuilder_->AppendStmt(bb, stmt);
2364            }
2365            SaveGate2Expr(gate, lmirBuilder_->Regread(vreg));
2366            return;
2367        }
2368        case INIT_VRGE_NEW_TARGET: {
2369            // init new_target
2370            PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref);
2371            // load func from interpreter sp
2372            Expr sp = lmirBuilder_->GenExprFromVar(
2373                lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1));  // 1 : osr second param - sp
2374            Expr offsetFrame = lmirBuilder_->ConstVal(
2375                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64())));
2376            Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame);
2377            Expr offsetFunc = lmirBuilder_->ConstVal(
2378                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetFunctionOffset(!circuit_->IsArch64())));
2379            Expr addrFunc = lmirBuilder_->Add(i64Ptr, frame, offsetFunc);
2380            Expr func = lmirBuilder_->Iread(i64Ref, addrFunc, lmirBuilder_->CreatePtrType(i64Ptr));
2381            // load method from func
2382            Expr offsetMethod = lmirBuilder_->ConstVal(
2383                lmirBuilder_->CreateIntConst(lmirBuilder_->i64PtrType, JSFunctionBase::METHOD_OFFSET));
2384            Expr addrMethod = lmirBuilder_->Add(i64Ptr, func, offsetMethod);
2385            Expr method = lmirBuilder_->Iread(i64Ptr, addrMethod, lmirBuilder_->CreatePtrType(i64Ptr));
2386            // load callField from method
2387            Expr offsetCF = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64Ptr, Method::CALL_FIELD_OFFSET));
2388            Expr addrCF = lmirBuilder_->Add(i64Ptr, method, offsetCF);
2389            Expr cf = lmirBuilder_->Iread(i64, addrCF, lmirBuilder_->CreatePtrType(i64));
2390            // cal new target offset from callField
2391            Expr offsetNVSB =
2392                lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, MethodLiteral::NumVregsBits::START_BIT));
2393            Expr offsetNVSZ = lmirBuilder_->ConstVal(
2394                lmirBuilder_->CreateIntConst(i64, (1LLU << MethodLiteral::NumVregsBits::SIZE) - 1));
2395            Expr offsetHFSB =
2396                lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, MethodLiteral::HaveFuncBit::START_BIT));
2397            Expr offsetHFSZ = lmirBuilder_->ConstVal(
2398                lmirBuilder_->CreateIntConst(i64, (1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1));
2399            Expr const0 = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, 0));
2400            Expr numVregs = lmirBuilder_->Cvt(
2401                i64, i32, lmirBuilder_->And(i64, lmirBuilder_->LShr(i64, cf, offsetNVSB), offsetNVSZ));
2402            Expr haveFunc = lmirBuilder_->Cvt(
2403                i64, i32,
2404                lmirBuilder_->ICmp(i64, lmirBuilder_->And(i64, lmirBuilder_->LShr(i64, cf, offsetHFSB), offsetHFSZ),
2405                                   const0, IntCmpCondition::kNE));
2406            Expr size = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64Ptr, JSTaggedValue::TaggedTypeSize()));
2407            Expr offsetNewTarget = lmirBuilder_->Mul(
2408                i64Ptr, lmirBuilder_->ZExt(i32, i64Ptr, lmirBuilder_->Add(i32, numVregs, haveFunc)), size);
2409            // load new target from sp
2410            Expr addrNewTarget = lmirBuilder_->Add(i64Ptr, sp, offsetNewTarget);
2411            Expr ldrNewTarget = lmirBuilder_->Iread(i64Ref, addrNewTarget, lmirBuilder_->CreatePtrType(i64Ptr));
2412            lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrNewTarget, vreg));
2413            SaveGate2Expr(gate, lmirBuilder_->Regread(vreg));
2414            return;
2415        }
2416        case INIT_VRGE_THIS_OBJECT: {
2417            // init this
2418            PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref);
2419            // load from frame
2420            Expr sp = lmirBuilder_->GenExprFromVar(
2421                lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1));  // 1 : osr second param - sp
2422            Expr offsetFrame = lmirBuilder_->ConstVal(
2423                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64())));
2424            Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame);
2425            Expr offsetThis = lmirBuilder_->ConstVal(
2426                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetThisOffset(!circuit_->IsArch64())));
2427            Expr addrThis = lmirBuilder_->Add(i64Ptr, frame, offsetThis);
2428            Expr ldrThis = lmirBuilder_->Iread(i64Ref, addrThis, lmirBuilder_->CreatePtrType(i64Ptr));
2429            lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrThis, vreg));
2430            SaveGate2Expr(gate, lmirBuilder_->Regread(vreg));
2431            return;
2432        }
2433        case INIT_VRGE_NUM_ARGS: {
2434            // init numargs
2435            SaveGate2Expr(gate, lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, 0)));
2436            return;
2437        }
2438        case INIT_VRGE_ENV: {
2439            // init env
2440            PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref);
2441            // load from frame
2442            Expr sp = lmirBuilder_->GenExprFromVar(
2443                lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1));  // 1 : osr second param - sp
2444            Expr offsetFrame = lmirBuilder_->ConstVal(
2445                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64())));
2446            Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame);
2447            Expr offsetEnv = lmirBuilder_->ConstVal(
2448                lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetEnvOffset(!circuit_->IsArch64())));
2449            Expr addrEnv = lmirBuilder_->Add(i64Ptr, frame, offsetEnv);
2450            Expr ldrEnv = lmirBuilder_->Iread(i64Ref, addrEnv, lmirBuilder_->CreatePtrType(i64Ptr));
2451            lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrEnv, vreg));
2452            SaveGate2Expr(gate, lmirBuilder_->Regread(vreg));
2453            return;
2454        }
2455        default: {
2456            // init vregs
2457            PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref);
2458            // load from sp
2459            Expr sp = lmirBuilder_->GenExprFromVar(
2460                lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1));  // 1 : osr second param - sp
2461            Expr offset =
2462                lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64Ptr, vregNumber * sizeof(JSTaggedType)));
2463            Expr addr = lmirBuilder_->Add(i64Ptr, sp, offset);
2464            Expr ldrVreg = lmirBuilder_->Iread(i64Ref, addr, lmirBuilder_->CreatePtrType(i64Ptr));
2465            lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrVreg, vreg));
2466            SaveGate2Expr(gate, lmirBuilder_->Regread(vreg));
2467            return;
2468        }
2469    }
2470}
2471
2472void LiteCGIRBuilder::HandleFPTrunc(GateRef gate)
2473{
2474    VisitFPTrunc(gate, acc_.GetIn(gate, 0));
2475}
2476
2477void LiteCGIRBuilder::VisitFPTrunc(GateRef gate, GateRef e1)
2478{
2479    Expr e1Value = GetExprFromGate(e1);
2480    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) >=
2481           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
2482    Expr result = lmirBuilder_->Cvt(ConvertLiteCGTypeFromGate(e1), ConvertLiteCGTypeFromGate(gate), e1Value);
2483    SaveGate2Expr(gate, result);
2484}
2485
2486void LiteCGIRBuilder::HandleFPExt(GateRef gate)
2487{
2488    VisitFPExt(gate, acc_.GetIn(gate, 0));
2489}
2490
2491void LiteCGIRBuilder::VisitFPExt(GateRef gate, GateRef e1)
2492{
2493    Expr e1Value = GetExprFromGate(e1);
2494    ASSERT(GetBitWidthFromMachineType(acc_.GetMachineType(e1)) <=
2495           GetBitWidthFromMachineType(acc_.GetMachineType(gate)));
2496    Expr result = lmirBuilder_->Cvt(ConvertLiteCGTypeFromGate(e1), ConvertLiteCGTypeFromGate(gate), e1Value);
2497    SaveGate2Expr(gate, result);
2498}
2499
2500void LiteCGIRBuilder::HandleExtractValue(GateRef gate)
2501{
2502    GateRef pointer = acc_.GetIn(gate, 0);
2503    GateRef index = acc_.GetIn(gate, 1);
2504    VisitExtractValue(gate, pointer, index);
2505}
2506
2507void LiteCGIRBuilder::VisitExtractValue(GateRef gate, GateRef e1, GateRef e2)
2508{
2509    ASSERT((acc_.GetOpCode(e2) == OpCode::CONSTANT) && acc_.GetMachineType(e2) == MachineType::I32);
2510    uint32_t index = static_cast<uint32_t>(acc_.GetConstantValue(e2));
2511    Expr expr = GetExprFromGate(e1, index);
2512    PregIdx pregIdx = lmirBuilder_->GetPregIdxFromExpr(expr);
2513    SaveGate2Expr(gate, lmirBuilder_->Regread(pregIdx));
2514}
2515
2516void LiteCGIRBuilder::HandleStore(GateRef gate)
2517{
2518    GateRef addr = acc_.GetValueIn(gate, 0);
2519    GateRef value = acc_.GetValueIn(gate, 1);
2520    VisitStore(gate, addr, value);
2521}
2522
2523void LiteCGIRBuilder::VisitStore(GateRef gate, GateRef base, GateRef value)
2524{
2525    Expr baseAddr = GetExprFromGate(base);
2526    Expr data = GetExprFromGate(value);
2527
2528    LiteCGType *returnType = ConvertLiteCGTypeFromGate(value);
2529    LiteCGType *memType = (lmirBuilder_->IsHeapPointerType(baseAddr.GetType()))
2530                              ? lmirBuilder_->CreateRefType(returnType)
2531                              : lmirBuilder_->CreatePtrType(returnType);
2532    baseAddr = CanonicalizeToPtr(baseAddr, memType);
2533
2534    Stmt &store = lmirBuilder_->Iassign(data, baseAddr, memType);
2535    lmirBuilder_->AppendStmt(GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]), store);
2536}
2537
2538void LiteCGIRBuilder::HandlePhi(GateRef gate)
2539{
2540    std::vector<GateRef> ins;
2541    acc_.GetIns(gate, ins);
2542    VisitPhi(gate, ins);
2543}
2544
2545void LiteCGIRBuilder::AddPhiDesc(int bbID, PhiDesc &desc, std::map<int, std::vector<PhiDesc>> &bbID2Phis)
2546{
2547    auto it = bbID2Phis.find(bbID);
2548    if (it == bbID2Phis.end()) {
2549        std::vector<PhiDesc> vec;
2550        vec.push_back(std::move(desc));
2551        bbID2Phis.insert(std::make_pair(bbID, vec));
2552    } else {
2553        it->second.push_back(std::move(desc));
2554    }
2555}
2556
2557LiteCGIRBuilder::DerivedStatus LiteCGIRBuilder::CheckDerivedPhi(GateRef gate, std::set<GateRef> &vis)
2558{
2559    // if the gate status is cached with derived or base, doesn't need to go forward
2560    if (derivedGateCache_.find(gate) != derivedGateCache_.end()) {
2561        if (derivedGateCache_[gate]) {
2562            return DerivedStatus::IS_DERIVED;
2563        } else {
2564            return DerivedStatus::IS_BASE;
2565        }
2566    }
2567    // for the visited gate in the dfs, if not cached, its status is unknow
2568    if (vis.find(gate) != vis.end()) {
2569        return DerivedStatus::UNKNOW;
2570    }
2571    // cached gate doesn't need insert to visited set
2572    vis.insert(gate);
2573    DerivedStatus derivedStatus = DerivedStatus::IS_BASE;
2574    std::vector<GateRef> phiIns;
2575    acc_.GetIns(gate, phiIns);
2576    std::vector<GateRef> phiStates;
2577    acc_.GetIns(phiIns[0], phiStates);
2578    ASSERT(phiStates.size() + 1 == phiIns.size());
2579    for (int i = 1; i < static_cast<int>(phiIns.size()); i++) {
2580        auto op = acc_.GetOpCode(phiIns[i]);
2581        if (op == OpCode::ADD) {
2582            derivedStatus = DerivedStatus::IS_DERIVED;
2583            break;
2584        } else if (op == OpCode::VALUE_SELECTOR) {
2585            DerivedStatus status = CheckDerivedPhi(phiIns[i], vis);
2586            if (status == DerivedStatus::IS_DERIVED) {
2587                derivedStatus = DerivedStatus::IS_DERIVED;
2588                break;
2589            }
2590            if (status == DerivedStatus::UNKNOW) {
2591                derivedStatus = DerivedStatus::UNKNOW;
2592            }
2593        }
2594    }
2595    if (derivedStatus == DerivedStatus::IS_DERIVED) {
2596        derivedGateCache_[gate] = true;
2597    } else if (derivedStatus == DerivedStatus::IS_BASE) {
2598        derivedGateCache_[gate] = false;
2599    }
2600
2601    return derivedStatus;
2602}
2603
2604void LiteCGIRBuilder::FindBaseRefForPhi(GateRef gate, const std::vector<GateRef> &phiIns)
2605{
2606    int curBBId = instID2bbID_[acc_.GetId(gate)];
2607    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
2608    PregIdx basePregIdx = 0;
2609    bool isDerived = false;
2610    std::set<GateRef> baseIns;
2611    std::vector<PhiDesc> phiDescs;
2612    std::vector<GateRef> phiStates;
2613    acc_.GetIns(phiIns[0], phiStates);
2614    ASSERT(phiStates.size() + 1 == phiIns.size());
2615    for (int i = 1; i < static_cast<int>(phiIns.size()); i++) {
2616        int preBBId = LookupPredBB(phiStates[i - 1], curBBId);
2617        if (bbID2BB_.count(preBBId) != 0) {
2618            BB *preBB = bbID2BB_[preBBId];
2619            if (preBB == nullptr) {
2620                OPTIONAL_LOG_COMPILER(ERROR) << "FindBaseRef failed BasicBlock nullptr";
2621                return;
2622            }
2623        }
2624        auto op = acc_.GetOpCode(phiIns[i]);
2625        if (op == OpCode::ADD) {
2626            auto g0 = acc_.GetIn(phiIns[i], 0);
2627            baseIns.insert(g0);
2628            PhiDesc desc = {preBBId, g0, basePregIdx};
2629            phiDescs.push_back(desc);
2630            isDerived = true;
2631            ASSERT(ConvertLiteCGTypeFromGate(g0) == lmirBuilder_->i64RefType);
2632        } else if (op == OpCode::VALUE_SELECTOR) {
2633            std::set<GateRef> vis;
2634            if (CheckDerivedPhi(phiIns[i], vis) == DerivedStatus::IS_DERIVED) {
2635                isDerived = true;
2636            }
2637            baseIns.insert(phiIns[i]);
2638            PhiDesc desc = {preBBId, phiIns[i], basePregIdx};
2639            phiDescs.push_back(desc);
2640            ASSERT(ConvertLiteCGTypeFromGate(phiIns[i]) == lmirBuilder_->i64RefType);
2641        } else {
2642            baseIns.insert(phiIns[i]);
2643            PhiDesc desc = {preBBId, phiIns[i], basePregIdx};
2644            phiDescs.push_back(desc);
2645            ASSERT(ConvertLiteCGTypeFromGate(phiIns[i]) == lmirBuilder_->i64RefType);
2646        }
2647    }
2648
2649    // use to catch the situation that the phi is derived
2650    if (isDerived) {
2651        LOG_COMPILER(FATAL) << "catch derived case!" << phiDescs.size() << std::endl;
2652        UNREACHABLE();
2653    }
2654
2655    derivedGateCache_[gate] = isDerived;
2656
2657    if (!isDerived) {
2658        return;
2659    }
2660
2661    if (baseIns.size() == 1) {
2662        // only one base gate for the derived phi reference, doesn't need to insert a new phi
2663        derivedGate2BaseGate_[gate] = *baseIns.begin();
2664    } else {
2665        basePregIdx = lmirBuilder_->CreatePreg(type);
2666        derivedPhiGate2BasePhiPreg_[gate] = basePregIdx;
2667        for (PhiDesc desc : phiDescs) {
2668            desc.phi = basePregIdx;
2669            AddPhiDesc(curBBId, desc, bbID2basePhis_);
2670        }
2671    }
2672}
2673
2674void LiteCGIRBuilder::VisitPhi(GateRef gate, const std::vector<GateRef> &phiIns)
2675{
2676    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
2677    PregIdx phiPregIdx = lmirBuilder_->CreatePreg(type);
2678
2679    if (phiIns.size() > 1) {
2680        SaveGate2Expr(gate, lmirBuilder_->Regread(phiPregIdx));
2681    }
2682    // Collect the states merges of this phi and note the 1-in is the merged states.
2683    std::vector<GateRef> phiStates;
2684    acc_.GetIns(phiIns[0], phiStates);
2685    ASSERT(phiStates.size() + 1 == phiIns.size());
2686    int curBBId = instID2bbID_[acc_.GetId(gate)];
2687    for (int i = 1; i < static_cast<int>(phiIns.size()); i++) {
2688        int preBBId = LookupPredBB(phiStates[i - 1], curBBId);
2689        // if bbID2BB_.count(preBBId) = 0 means bb with current bbIdx hasn't been created
2690        if (bbID2BB_.count(preBBId) != 0) {
2691            BB *preBB = bbID2BB_[preBBId];
2692            if (preBB == nullptr) {
2693                OPTIONAL_LOG_COMPILER(ERROR) << "VisitPhi failed BasicBlock nullptr";
2694                return;
2695            }
2696            PhiDesc desc = {preBBId, phiIns[i], phiPregIdx};
2697            AddPhiDesc(curBBId, desc, bbID2unmergedPhis_);
2698        } else {
2699            PhiDesc desc = {preBBId, phiIns[i], phiPregIdx};
2700            AddPhiDesc(curBBId, desc, bbID2unmergedPhis_);
2701        }
2702    }
2703
2704    if (type == lmirBuilder_->i64RefType) {
2705        FindBaseRefForPhi(gate, phiIns);
2706    }
2707}
2708
2709void LiteCGIRBuilder::HandleSwitch(GateRef gate)
2710{
2711    std::vector<GateRef> ins;
2712    acc_.GetIns(gate, ins);
2713    std::vector<GateRef> outs;
2714    acc_.GetOutStates(gate, outs);
2715    VisitSwitch(gate, ins[1], outs);
2716}
2717
2718void LiteCGIRBuilder::VisitSwitch(GateRef gate, GateRef input, const std::vector<GateRef> &outList)
2719{
2720    Expr cond = GetExprFromGate(input);
2721    int caseNum = static_cast<int>(outList.size());
2722    BB *defaultOutBB = nullptr;
2723    for (int i = 0; i < caseNum; i++) {
2724        if (acc_.GetOpCode(outList[i]) == OpCode::DEFAULT_CASE) {
2725            defaultOutBB = &GetOrCreateBB(instID2bbID_[acc_.GetId(outList[i])]);
2726        }
2727    }
2728
2729    LiteCGType *type = ConvertLiteCGTypeFromGate(gate);
2730    CHECK_NULL_FATAL(defaultOutBB);
2731    SwitchBuilder builder = lmirBuilder_->Switch(type, cond, *defaultOutBB);
2732    for (int i = 0; i < caseNum; i++) {
2733        if (acc_.GetOpCode(outList[i]) == OpCode::DEFAULT_CASE) {
2734            continue;
2735        }
2736        BB &curOutBB = GetOrCreateBB(instID2bbID_[acc_.GetId(outList[i])]);
2737        builder.Case(acc_.TryGetValue(outList[i]), curOutBB);
2738    }
2739    Stmt &switchStmt = builder.Done();
2740    lmirBuilder_->AppendStmt(GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]), switchStmt);
2741    lmirBuilder_->AppendBB(GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]));
2742}
2743
2744void LiteCGIRBuilder::HandleDeoptCheck(GateRef gate)
2745{
2746    int block = instID2bbID_[acc_.GetId(gate)];
2747    std::vector<GateRef> outs;
2748    acc_.GetOutStates(gate, outs);
2749    int bbOut = instID2bbID_[acc_.GetId(outs[0])];  // 0: output
2750
2751    BB &trueBB = GetOrCreateBB(bbOut);
2752    BB &falseBB = lmirBuilder_->CreateBB();
2753    GateRef cmp = acc_.GetValueIn(gate, 0);  // 0: cond
2754    Expr cond = GetExprFromGate(cmp);
2755    BB &curBB = GetOrCreateBB(block);
2756    lmirBuilder_->AppendStmt(curBB, lmirBuilder_->CondGoto(cond, falseBB, false));
2757    lmirBuilder_->AppendStmt(curBB, lmirBuilder_->Goto(trueBB));
2758    lmirBuilder_->AppendBB(curBB);
2759    // deopt branch is not expected to be token as often,
2760    // just put them to the end of the function
2761    lmirBuilder_->AppendToLast(falseBB);
2762
2763    VisitDeoptCheck(gate);
2764    Expr returnValue = GetExprFromGate(gate);
2765    lmirBuilder_->AppendStmt(falseBB, lmirBuilder_->Return(returnValue));
2766}
2767
2768LiteCGType *LiteCGIRBuilder::GetExperimentalDeoptTy()
2769{
2770    std::vector<LiteCGType *> paramTys = {lmirBuilder_->i64Type, lmirBuilder_->i64RefType, lmirBuilder_->i64RefType};
2771    LiteCGType *functionType = lmirBuilder_->CreateFuncType(paramTys, lmirBuilder_->i64RefType, false);
2772    return functionType;
2773}
2774
2775void LiteCGIRBuilder::SaveFrameTypeOnFrame(BB &bb, FrameType frameType)
2776{
2777    Expr llvmFpAddr = CallingFp(false);
2778    Expr frameAddr = lmirBuilder_->Cvt(llvmFpAddr.GetType(), slotType_, llvmFpAddr);
2779    Expr frameTypeSlotAddr = lmirBuilder_->Sub(
2780        slotType_, frameAddr, lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, slotSize_)));
2781    LiteCGType *slotTypePtr = lmirBuilder_->CreatePtrType(slotType_);
2782    Expr addr = lmirBuilder_->Cvt(frameTypeSlotAddr.GetType(), slotTypePtr, frameTypeSlotAddr);
2783    Expr llvmFrameType =
2784        lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, static_cast<uintptr_t>(frameType)));
2785    Stmt &stmt = lmirBuilder_->Iassign(llvmFrameType, addr, slotTypePtr);
2786    lmirBuilder_->AppendStmt(bb, stmt);
2787}
2788
2789void LiteCGIRBuilder::GenDeoptEntry(std::string funcName)
2790{
2791    BB &bb = CreateBB();
2792    auto reservedSlotsSize = OptimizedFrame::ComputeReservedSize(slotSize_);
2793    lmirBuilder_->SetFuncFrameResverdSlot(reservedSlotsSize);
2794    SaveFrameTypeOnFrame(bb, FrameType::OPTIMIZED_FRAME);
2795    Function &func = lmirBuilder_->GetCurFunction();
2796    lmirModule_->SetFunction(LMIRModule::kDeoptEntryOffset, funcName, false);
2797
2798    Expr glue = lmirBuilder_->Dread(lmirBuilder_->GetParam(func, 0));
2799    Expr check = lmirBuilder_->Dread(lmirBuilder_->GetParam(func, 1));
2800    Expr depth = lmirBuilder_->Dread(lmirBuilder_->GetParam(func, 2));
2801
2802    StubIdType stubId = RTSTUB_ID(DeoptHandlerAsm);
2803    int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
2804    Expr rtoffset = lmirBuilder_->Add(glue.GetType(), glue, GetRTStubOffset(glue, stubIndex));
2805    Expr patchAddr = lmirBuilder_->Cvt(glue.GetType(), lmirBuilder_->i64PtrType, rtoffset);
2806    Expr funcAddr = lmirBuilder_->Iread(rtoffset.GetType(), patchAddr, lmirBuilder_->i64PtrType);
2807
2808    LiteCGType *funcType = GetExperimentalDeoptTy();
2809    LiteCGType *funcTypePtr = lmirBuilder_->CreatePtrType(funcType);
2810    LiteCGType *funcTypePtrPtr = lmirBuilder_->CreatePtrType(funcTypePtr);
2811    Expr callee = lmirBuilder_->Cvt(glue.GetType(), funcTypePtrPtr, funcAddr);
2812
2813    Var &funcVar = lmirBuilder_->CreateLocalVar(callee.GetType(), "DeoptimizeSubFunc");
2814    Stmt &funcAddrNode = lmirBuilder_->Dassign(callee, funcVar);
2815    lmirBuilder_->AppendStmt(bb, funcAddrNode);
2816
2817    LiteCGType *returnType = lmirBuilder_->LiteCGGetFuncReturnType(funcType);
2818    PregIdx pregIdx = lmirBuilder_->CreatePreg(returnType);
2819    std::vector<Expr> params = {glue, check, depth};
2820    Stmt &callNode = lmirBuilder_->ICall(lmirBuilder_->Dread(funcVar), params, pregIdx);
2821    lmirBuilder_->AppendStmt(bb, callNode);
2822    lmirBuilder_->AppendStmt(bb, lmirBuilder_->Return(lmirBuilder_->Regread(pregIdx)));
2823    lmirBuilder_->AppendBB(bb);
2824}
2825
2826Function *LiteCGIRBuilder::GetExperimentalDeopt()
2827{
2828    /* 0:calling 1:its caller */
2829    std::string funcName = "litecg.experimental.deoptimize.p1i64";
2830    auto fn = lmirBuilder_->GetFunc(funcName);
2831    if (!fn) {
2832        // save previous func for restore env
2833        Function &preFunc = lmirBuilder_->GetCurFunction();
2834        auto fnTy = GetExperimentalDeoptTy();
2835        FunctionBuilder funcBuilder = lmirBuilder_->DefineFunction(funcName);
2836        // glue type depth
2837        funcBuilder.Param(lmirBuilder_->i64Type, "glue")
2838            .Param(lmirBuilder_->i64RefType, "deopt_type")
2839            .Param(lmirBuilder_->i64RefType, "max_depth");
2840        Function &curFunc = funcBuilder.Return(lmirBuilder_->LiteCGGetFuncReturnType(fnTy)).Done();
2841        funcBuilder.CallConvAttribute(maple::litecg::CCall);
2842        lmirBuilder_->SetCurFunc(curFunc);
2843        GenDeoptEntry(funcName);
2844        fn = &curFunc;
2845
2846        lmirBuilder_->SetCurFunc(preFunc);
2847    }
2848    return fn;
2849}
2850
2851Expr LiteCGIRBuilder::ConvertToTagged(GateRef gate)
2852{
2853    auto machineType = acc_.GetMachineType(gate);
2854    switch (machineType) {
2855        case MachineType::I1:
2856            return ConvertBoolToTaggedBoolean(gate);
2857        case MachineType::I32:
2858            return ConvertInt32ToTaggedInt(GetExprFromGate(gate));
2859        case MachineType::F64:
2860            return ConvertFloat64ToTaggedDouble(gate);
2861        case MachineType::I64:
2862            break;
2863        default:
2864            LOG_COMPILER(FATAL) << "unexpected machineType!";
2865            UNREACHABLE();
2866            break;
2867    }
2868    return GetExprFromGate(gate);
2869}
2870
2871Expr LiteCGIRBuilder::ConvertInt32ToTaggedInt(Expr value)
2872{
2873    Expr e1Value = lmirBuilder_->SExt(value.GetType(), lmirBuilder_->i64Type, value);
2874    Expr tagMask = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i64Type, JSTaggedValue::TAG_INT));
2875    Expr result = lmirBuilder_->Or(lmirBuilder_->i64Type, e1Value, tagMask);
2876    return lmirBuilder_->Cvt(lmirBuilder_->i64Type, lmirBuilder_->i64RefType, result);
2877}
2878
2879Expr LiteCGIRBuilder::ConvertBoolToTaggedBoolean(GateRef gate)
2880{
2881    Expr value = GetExprFromGate(gate);
2882    Expr e1Value = lmirBuilder_->ZExt(value.GetType(), lmirBuilder_->u64Type, value);
2883    Expr tagMask =
2884        lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->i64Type, JSTaggedValue::TAG_BOOLEAN_MASK));
2885    Expr result = lmirBuilder_->Or(lmirBuilder_->u64Type, e1Value, tagMask);
2886    return lmirBuilder_->Cvt(lmirBuilder_->u64Type, lmirBuilder_->i64RefType, result);
2887}
2888
2889Expr LiteCGIRBuilder::ConvertFloat64ToTaggedDouble(GateRef gate)
2890{
2891    Expr value = GetExprFromGate(gate);
2892    Expr e1Value = lmirBuilder_->BitCast(value.GetType(), lmirBuilder_->i64Type, value);
2893    Expr offset = lmirBuilder_->ConstVal(
2894        lmirBuilder_->CreateIntConst(lmirBuilder_->i64Type, JSTaggedValue::DOUBLE_ENCODE_OFFSET));
2895    Expr result = lmirBuilder_->Add(lmirBuilder_->i64Type, e1Value, offset);
2896    return lmirBuilder_->Cvt(lmirBuilder_->i64Type, lmirBuilder_->i64RefType, result);
2897}
2898
2899void LiteCGIRBuilder::SaveDeoptVregInfo(std::unordered_map<int, LiteCGValue> &deoptBundleInfo, BB &bb, int32_t index,
2900                                        size_t curDepth, size_t shift, GateRef gate)
2901{
2902    int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(index, curDepth, shift);
2903    Expr value = ConvertToTagged(gate);
2904    PregIdx pregIdx = lmirBuilder_->CreatePreg(value.GetType());
2905    lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(value, pregIdx));
2906    deoptBundleInfo.insert(std::pair<int, LiteCGValue>(encodeIndex, {LiteCGValueKind::kPregKind, pregIdx}));
2907}
2908
2909void LiteCGIRBuilder::SaveDeoptVregInfoWithI64(std::unordered_map<int, LiteCGValue> &deoptBundleInfo, BB &bb,
2910                                               int32_t index, size_t curDepth, size_t shift, GateRef gate)
2911{
2912    int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(index, curDepth, shift);
2913    Expr expr = GetExprFromGate(gate);
2914    Expr value = ConvertInt32ToTaggedInt(lmirBuilder_->Cvt(expr.GetType(), lmirBuilder_->i32Type, expr));
2915    PregIdx pregIdx = lmirBuilder_->CreatePreg(value.GetType());
2916    lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(value, pregIdx));
2917    deoptBundleInfo.insert(std::pair<int, LiteCGValue>(encodeIndex, {LiteCGValueKind::kPregKind, pregIdx}));
2918}
2919
2920void LiteCGIRBuilder::VisitDeoptCheck(GateRef gate)
2921{
2922    BB &bb = lmirBuilder_->GetLastAppendedBB();  // falseBB of deopt check
2923    Expr glue = GetExprFromGate(acc_.GetGlueFromArgList());
2924    GateRef deoptFrameState = acc_.GetValueIn(gate, 1);  // 1: frame state
2925    ASSERT(acc_.GetOpCode(deoptFrameState) == OpCode::FRAME_STATE);
2926    std::vector<Expr> params;
2927    params.push_back(glue);                        // glue
2928    GateRef deoptType = acc_.GetValueIn(gate, 2);  // 2: deopt type
2929    uint64_t v = acc_.GetConstantValue(deoptType);
2930    Expr constV = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->u32Type, static_cast<uint32_t>(v)));
2931    params.push_back(ConvertInt32ToTaggedInt(constV));  // deoptType
2932    Function *callee = GetExperimentalDeopt();
2933    LiteCGType *funcType = GetExperimentalDeoptTy();
2934
2935    std::unordered_map<int, LiteCGValue> deoptBundleInfo;
2936    size_t maxDepth = 0;
2937    GateRef frameState = acc_.GetFrameState(deoptFrameState);
2938    while ((acc_.GetOpCode(frameState) == OpCode::FRAME_STATE)) {
2939        maxDepth++;
2940        frameState = acc_.GetFrameState(frameState);
2941    }
2942    Expr constMaxDepth =
2943        lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(lmirBuilder_->u32Type, static_cast<uint32_t>(maxDepth)));
2944    params.push_back(ConvertInt32ToTaggedInt(constMaxDepth));
2945    size_t shift = Deoptimizier::ComputeShift(maxDepth);
2946    frameState = deoptFrameState;
2947    ArgumentAccessor argAcc(const_cast<Circuit *>(circuit_));
2948    for (int32_t curDepth = static_cast<int32_t>(maxDepth); curDepth >= 0; curDepth--) {
2949        ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE);
2950        GateRef frameValues = acc_.GetValueIn(frameState, 1);  // 1: frame values
2951        const size_t numValueIn = acc_.GetNumValueIn(frameValues);
2952        const size_t envIndex = numValueIn - 2;  // 2: env valueIn index
2953        CHECK_FATAL(numValueIn > 0, "must not be zero");
2954        const size_t accIndex = numValueIn - 1;  // 1: acc valueIn index
2955        GateRef env = acc_.GetValueIn(frameValues, envIndex);
2956        GateRef acc = acc_.GetValueIn(frameValues, accIndex);
2957        auto pc = acc_.TryGetPcOffset(frameState);
2958        GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
2959        GateRef newTarget = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::NEW_TARGET);
2960        GateRef thisObj = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::THIS_OBJECT);
2961        GateRef actualArgc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::ACTUAL_ARGC);
2962        // vreg
2963        for (size_t i = 0; i < envIndex; i++) {
2964            GateRef vregValue = acc_.GetValueIn(frameValues, i);
2965            if (acc_.IsConstantTaggedValue(vregValue, JSTaggedValue::VALUE_OPTIMIZED_OUT)) {
2966                continue;
2967            }
2968            SaveDeoptVregInfo(deoptBundleInfo, bb, i, curDepth, shift, vregValue);
2969        }
2970        // env
2971        if (!acc_.IsConstantTaggedValue(env, JSTaggedValue::VALUE_OPTIMIZED_OUT)) {
2972            int32_t specEnvVregIndex = static_cast<int32_t>(SpecVregIndex::ENV_INDEX);
2973            SaveDeoptVregInfo(deoptBundleInfo, bb, specEnvVregIndex, curDepth, shift, env);
2974        }
2975        // acc
2976        if (!acc_.IsConstantTaggedValue(acc, JSTaggedValue::VALUE_OPTIMIZED_OUT)) {
2977            int32_t specAccVregIndex = static_cast<int32_t>(SpecVregIndex::ACC_INDEX);
2978            SaveDeoptVregInfo(deoptBundleInfo, bb, specAccVregIndex, curDepth, shift, acc);
2979        }
2980        // pc offset
2981        int32_t specPcOffsetIndex = static_cast<int32_t>(SpecVregIndex::PC_OFFSET_INDEX);
2982        int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(specPcOffsetIndex, curDepth, shift);
2983        Const &pcConst = lmirBuilder_->CreateIntConst(lmirBuilder_->u32Type, pc);
2984        deoptBundleInfo.insert(std::pair<int, LiteCGValue>(encodeIndex, {LiteCGValueKind::kConstKind, &pcConst}));
2985
2986        // func
2987        int32_t specCallTargetIndex = static_cast<int32_t>(SpecVregIndex::FUNC_INDEX);
2988        SaveDeoptVregInfo(deoptBundleInfo, bb, specCallTargetIndex, curDepth, shift, jsFunc);
2989        // newTarget
2990        int32_t specNewTargetIndex = static_cast<int32_t>(SpecVregIndex::NEWTARGET_INDEX);
2991        SaveDeoptVregInfo(deoptBundleInfo, bb, specNewTargetIndex, curDepth, shift, newTarget);
2992        // this object
2993        int32_t specThisIndex = static_cast<int32_t>(SpecVregIndex::THIS_OBJECT_INDEX);
2994        SaveDeoptVregInfo(deoptBundleInfo, bb, specThisIndex, curDepth, shift, thisObj);
2995        int32_t specArgcIndex = static_cast<int32_t>(SpecVregIndex::ACTUAL_ARGC_INDEX);
2996        SaveDeoptVregInfoWithI64(deoptBundleInfo, bb, specArgcIndex, curDepth, shift, actualArgc);
2997        frameState = acc_.GetFrameState(frameState);
2998    }
2999    LiteCGType *returnType = lmirBuilder_->LiteCGGetFuncReturnType(funcType);
3000
3001    bool returnVoid = (returnType == lmirBuilder_->voidType);
3002    PregIdx returnPregIdx = returnVoid ? -1 : lmirBuilder_->CreatePreg(returnType);
3003
3004    Stmt &callNode = lmirBuilder_->Call(*callee, params, returnPregIdx);
3005    lmirBuilder_->SetCallStmtDeoptBundleInfo(callNode, deoptBundleInfo);
3006
3007    lmirBuilder_->AppendStmt(bb, callNode);
3008    if (!returnVoid) {
3009        SaveGate2Expr(gate, lmirBuilder_->Regread(returnPregIdx));
3010    }
3011}
3012
3013int64_t LiteCGIRBuilder::GetBitWidthFromMachineType(MachineType machineType) const
3014{
3015    switch (machineType) {
3016        case NOVALUE:
3017            return 0;
3018        case ARCH:
3019            return 48;  // 48: Pointer representation in different architectures
3020        case I1:
3021            return 1;
3022        case I8:
3023            return 8;  // 8: bit width
3024        case I16:
3025            return 16;  // 16: bit width
3026        case I32:
3027            return 32;  // 32: bit width
3028        case I64:
3029            return 64;  // 64: bit width
3030        case F32:
3031            return 32;  // 32: bit width
3032        case F64:
3033            return 64;  // 64: bit width
3034        case FLEX:
3035        case ANYVALUE:
3036            LOG_ECMA(FATAL) << "this branch is unreachable";
3037            UNREACHABLE();
3038        default:
3039            LOG_ECMA(FATAL) << "this branch is unreachable";
3040            UNREACHABLE();
3041    }
3042}
3043
3044int LiteCGIRBuilder::LookupPredBB(GateRef start, int bbID)
3045{
3046    GateId gateId = acc_.GetId(start);
3047    int owner = instID2bbID_[gateId];
3048    if (owner != bbID) {
3049        return owner;
3050    }
3051    GateRef pred = start;
3052    while (owner == bbID) {
3053        pred = acc_.GetState(pred);
3054        auto id = acc_.GetId(pred);
3055        owner = instID2bbID_[id];
3056    }
3057    return owner;
3058}
3059
3060}  // namespace panda::ecmascript::kungfu
3061