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