• 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 #ifndef ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
17 #define ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
18 
19 #include <map>
20 #include <memory>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include "ecmascript/compiler/circuit.h"
25 #include "ecmascript/compiler/gate.h"
26 #include "ecmascript/compiler/stub_builder.h"
27 #include "ecmascript/compiler/call_signature.h"
28 #include "ecmascript/compiler/common_stub_csigns.h"
29 #include "ecmascript/compiler/interpreter_stub.h"
30 #include "ecmascript/compiler/rt_call_signature.h"
31 #include "ecmascript/compiler/ir_module.h"
32 #include "ecmascript/compiler/ir_builder.h"
33 #include "ecmascript/jspandafile/method_literal.h"
34 #include "llvm-c/DebugInfo.h"
35 #include "llvm-c/Core.h"
36 
37 namespace panda::ecmascript::kungfu {
38 class BasicBlock;
39 class DebugInfo;
40 using BasicBlockMap = std::map<int, std::unique_ptr<BasicBlock>>;
41 class LLVMIRBuilder;
42 using HandleType = void(LLVMIRBuilder::*)(GateRef gate);
43 
44 class BasicBlock {
45 public:
BasicBlock(int id)46     explicit BasicBlock(int id) : id_(id)
47     {
48         predecessors_ = {};
49         successors_ = {};
50         impl_ = nullptr;
51     }
52 
GetId()53     int GetId() const
54     {
55         return id_;
56     }
57 
58     template<class T>
GetImpl()59     inline T *GetImpl() const
60     {
61         return static_cast<T *>(impl_);
62     }
63 
SetImpl(void * impl)64     inline void SetImpl(void *impl)
65     {
66         impl_ = impl;
67     }
68 
69     template<class T>
ResetImpl()70     inline void ResetImpl()
71     {
72         if (impl_) {
73             delete GetImpl<T>();
74             impl_ = nullptr;
75         }
76     }
77     ~BasicBlock() = default;
78 
79 private:
80     std::vector<BasicBlock *> predecessors_ {};
81     std::vector<BasicBlock *> successors_ {};
82     int id_ {-1};
83     void *impl_ {nullptr};
84 };
85 
86 struct NotMergedPhiDesc {
87     int predBBId;
88     GateRef operand;
89     LLVMValueRef phi;
90 };
91 
92 struct BasicBlockImpl {
93     LLVMBasicBlockRef lBB_ = nullptr;
94     LLVMBasicBlockRef continuation = nullptr;
95     bool started = false;
96     bool ended = false;
97     std::vector<NotMergedPhiDesc> unmergedPhis_;
98 };
99 
100 class LLVMModule : public IRModule {
101 public:
102     LLVMModule(NativeAreaAllocator* allocator, const std::string &name, bool logDbg, const std::string &triple);
103     ~LLVMModule();
104     void SetUpForCommonStubs();
105     void SetUpForBytecodeHandlerStubs();
106     void SetUpForBuiltinsStubs();
107     void SetUpForBaselineStubs();
108 
109     LLVMValueRef AddFunc(const panda::ecmascript::MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile);
GetModule()110     LLVMModuleRef GetModule() const
111     {
112         return module_;
113     }
114     LLVMTypeRef GetFuncType(const CallSignature *stubDescriptor);
115 
116     LLVMTypeRef GenerateFuncType(const std::vector<LLVMValueRef> &params, const CallSignature *stubDescriptor);
117 
SetFunction(size_t index,LLVMValueRef func,bool isFastCall)118     void SetFunction(size_t index, LLVMValueRef func, bool isFastCall)
119     {
120         funcIndexMap_.emplace_back(std::make_tuple(index, func, isFastCall));
121     }
122 
GetModuleKind()123     ModuleKind GetModuleKind() const override
124     {
125         return MODULE_LLVM;
126     }
127 
GetFunction(size_t index)128     LLVMValueRef GetFunction(size_t index)
129     {
130         // next optimization can be performed
131         for (auto &it: funcIndexMap_) {
132             if (std::get<0>(it) == index) {
133                 return std::get<1>(it);
134             }
135         }
136         return nullptr;
137     }
138 
GetFuncCount()139     size_t GetFuncCount() const
140     {
141         return funcIndexMap_.size();
142     }
143 
144     template<class Callback>
IteratefuncIndexMap(const Callback & cb)145     void IteratefuncIndexMap(const Callback &cb) const
146     {
147         for (auto record : funcIndexMap_) {
148             // 2: 3nd param
149             cb(std::get<0>(record), std::get<1>(record), std::get<2>(record));
150         }
151     }
152 
GetCSign(size_t index)153     const CallSignature *GetCSign(size_t index) const
154     {
155         return callSigns_[index];
156     }
157 
GetCSigns()158     const std::vector<const CallSignature*> &GetCSigns() const
159     {
160         return callSigns_;
161     }
162 
GetContext()163     LLVMContextRef GetContext() const
164     {
165         return context_;
166     }
167 
GetDFileMD()168     LLVMMetadataRef GetDFileMD() const
169     {
170         return dFileMD_;
171     }
172 
GetDIBuilder()173     LLVMDIBuilderRef GetDIBuilder() const
174     {
175         return dBuilder_;
176     }
177 
178     LLVMValueRef GetDeoptFunction();
179 
180     static constexpr int kDeoptEntryOffset = 0;
181 
GetVoidT()182     LLVMTypeRef GetVoidT() const
183     {
184         return voidT_;
185     }
186 
GetInt1T()187     LLVMTypeRef GetInt1T() const
188     {
189         return int1T_;
190     }
191 
GetInt8T()192     LLVMTypeRef GetInt8T() const
193     {
194         return int8T_;
195     }
196 
GetInt16T()197     LLVMTypeRef GetInt16T() const
198     {
199         return int16T_;
200     }
201 
GetInt32T()202     LLVMTypeRef GetInt32T() const
203     {
204         return int32T_;
205     }
206 
GetInt64T()207     LLVMTypeRef GetInt64T() const
208     {
209         return int64T_;
210     }
211 
GetFloatT()212     LLVMTypeRef GetFloatT() const
213     {
214         return floatT_;
215     }
216 
GetDoubleT()217     LLVMTypeRef GetDoubleT() const
218     {
219         return doubleT_;
220     }
221 
GetTaggedPtrT()222     LLVMTypeRef GetTaggedPtrT() const
223     {
224         return taggedPtrT_;
225     }
226 
GetTaggedHPtrT()227     LLVMTypeRef GetTaggedHPtrT() const
228     {
229         return taggedHPtrT_;
230     }
231 
GetRawPtrT()232     LLVMTypeRef GetRawPtrT() const
233     {
234         return rawPtrT_;
235     }
236 
237     LLVMTypeRef ConvertLLVMTypeFromVariableType(VariableType type);
238 private:
239     LLVMValueRef AddAndGetFunc(const CallSignature *stubDescriptor);
240     void InitialLLVMFuncTypeAndFuncByModuleCSigns();
241     LLVMTypeRef NewLType(MachineType machineType, GateType gateType);
242     // index:
243     //     stub scenario - sequence of function adding to llvmModule
244     //     aot scenario - method Id of function generated by panda files
245     std::vector<std::tuple<size_t, LLVMValueRef, bool>> funcIndexMap_;
246     std::vector<const CallSignature *> callSigns_;
247     LLVMModuleRef module_ {nullptr};
248     LLVMContextRef context_ {nullptr};
249     LLVMMetadataRef dFileMD_ {nullptr};
250     LLVMMetadataRef dUnitMD_ {nullptr};
251     LLVMDIBuilderRef dBuilder_ {nullptr};
252 
253     LLVMTypeRef voidT_ {nullptr};
254     LLVMTypeRef int1T_ {nullptr};
255     LLVMTypeRef int8T_ {nullptr};
256     LLVMTypeRef int16T_ {nullptr};
257     LLVMTypeRef int32T_ {nullptr};
258     LLVMTypeRef int64T_ {nullptr};
259     LLVMTypeRef floatT_ {nullptr};
260     LLVMTypeRef doubleT_ {nullptr};
261     LLVMTypeRef taggedHPtrT_ {nullptr};
262     LLVMTypeRef taggedPtrT_ {nullptr};
263     LLVMTypeRef rawPtrT_ {nullptr};
264 };
265 
266 // runtime/common stub ID, opcodeOffset for bc stub
267 using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>;
268 
269 class LLVMTargetBuilder {
270 public:
271     virtual ~LLVMTargetBuilder() = default;
272     virtual LLVMValueRef GetASMBarrierCall(LLVMModule *llvmModule_) = 0;
273 };
274 
275 class LLVMIRBuilder {
276 public:
277     LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit,
278                   LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg,
279                   CallSignature::CallConv callConv, bool enableLog, bool isFastCallAot, const std::string &funcName,
280                   bool enableOptInlining = false, bool enableOptBranchProfiling = true);
281     ~LLVMIRBuilder();
282     void Build();
283 
RegisterTargetBuilder(const std::string & triple,const std::function<LLVMTargetBuilder * ()> & creator)284     static void RegisterTargetBuilder(const std::string& triple, const std::function<LLVMTargetBuilder*()>& creator)
285     {
286         GlobalTargetBuilders().emplace(triple, creator);
287     };
288 private:
289     #define DECLAREVISITOPCODE(name, signature) void Visit##name signature;
OPCODES(DECLAREVISITOPCODE)290         OPCODES(DECLAREVISITOPCODE)
291     #undef DECLAREVISITOPCODE
292     #define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(GateRef gate);
293         OPCODES(DECLAREHANDLEOPCODE)
294     #undef DECLAREHANDLEOPCODE
295 
296     bool IsPrologue(int bbId) const
297     {
298         return bbId == 0;
299     }
300     void LinkToLLVMCfg(int bbId, const OperandsVector &predecessors);
301     BasicBlock *EnsureBB(int id);
302     LLVMValueRef CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller);
303     LLVMValueRef GetCurrentSP();
304     LLVMValueRef ReadRegister(LLVMModuleRef &module, LLVMBuilderRef &builder, LLVMMetadataRef meta);
305     void GenPrologue();
306     void AssistGenPrologue(const size_t reservedSlotsSize, FrameType frameType);
307     LLVMBasicBlockRef EnsureLBB(BasicBlock *bb) const;
308     BasicBlockImpl *EnsureBBImpl(BasicBlock *bb) const;
309     void SetToCfg(BasicBlock *bb) const;
310 
311     LLVMTypeRef GetMachineRepType(MachineRep rep) const;
312     int FindBasicBlock(GateRef gate) const;
313     void EndCurrentBlock() const;
314     void Finish();
315 
316     void ProcessPhiWorkList();
317     void InitializeHandlers();
318     std::string LLVMValueToString(LLVMValueRef val) const;
319 
320     LLVMTypeRef ConvertLLVMTypeFromGate(GateRef gate) const;
321     int64_t GetBitWidthFromMachineType(MachineType machineType) const;
322     LLVMValueRef PointerAdd(LLVMValueRef baseAddr, LLVMValueRef offsetInByte, LLVMTypeRef rep);
323     LLVMValueRef CanonicalizeToInt(LLVMValueRef value) const;
324     LLVMValueRef CanonicalizeToPtr(LLVMValueRef value) const;
325     LLVMValueRef CanonicalizeToPtr(LLVMValueRef value, LLVMTypeRef ptrType) const;
326     LLVMValueRef GetCurrentFrameType(LLVMValueRef currentSpFrameAddr);
327     void SetFunctionCallConv();
328     template<typename... Ts>
329     void VisitIntrinsic(GateRef gate, unsigned llvmId, Ts... inputs);
330 
IsLogEnabled()331     bool IsLogEnabled() const
332     {
333         return enableLog_;
334     }
335     LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset,
336                              const std::string &realName = "") const;
337     LLVMValueRef GetCallee(const std::vector<GateRef> &inList, const CallSignature *signature,
338                            const std::string &realName = "");
339     void CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset,
340                                  GateRef frameState);
341     LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature,
342                                             LLVMValueRef reloc) const;
343     bool IsInterpreted() const;
344     bool IsBaselineBuiltin() const;
345     bool IsOptimized() const;
346     bool IsOptimizedJSFunction() const;
347     void SetGCLeafFunction(LLVMValueRef call);
348     void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call);
349     bool IsHeapPointerType(LLVMTypeRef valueType);
350 
GetVoidT()351     LLVMTypeRef GetVoidT() const
352     {
353         return llvmModule_->GetVoidT();
354     }
355 
GetInt1T()356     LLVMTypeRef GetInt1T() const
357     {
358         return llvmModule_->GetInt1T();
359     }
360 
GetInt8T()361     LLVMTypeRef GetInt8T() const
362     {
363         return llvmModule_->GetInt8T();
364     }
365 
GetInt16T()366     LLVMTypeRef GetInt16T() const
367     {
368         return llvmModule_->GetInt16T();
369     }
370 
GetInt32T()371     LLVMTypeRef GetInt32T() const
372     {
373         return llvmModule_->GetInt32T();
374     }
375 
GetInt64T()376     LLVMTypeRef GetInt64T() const
377     {
378         return llvmModule_->GetInt64T();
379     }
380 
GetFloatT()381     LLVMTypeRef GetFloatT() const
382     {
383         return llvmModule_->GetFloatT();
384     }
385 
GetDoubleT()386     LLVMTypeRef GetDoubleT() const
387     {
388         return llvmModule_->GetDoubleT();
389     }
390 
GetTaggedPtrT()391     LLVMTypeRef GetTaggedPtrT() const
392     {
393         return llvmModule_->GetTaggedPtrT();
394     }
395 
GetTaggedHPtrT()396     LLVMTypeRef GetTaggedHPtrT() const
397     {
398         return llvmModule_->GetTaggedHPtrT();
399     }
400 
GetRawPtrT()401     LLVMTypeRef GetRawPtrT() const
402     {
403         return llvmModule_->GetRawPtrT();
404     }
405 
406 private:
GetDIBuilder()407     LLVMDIBuilderRef GetDIBuilder() const
408     {
409         return llvmModule_ == nullptr ? nullptr : llvmModule_->GetDIBuilder();
410     }
411 
412     unsigned GetPtrAddressSpace(LLVMValueRef v) const;
413     bool IsLInteger(LLVMValueRef v) const;
414     bool IsLPointer(LLVMValueRef v) const;
415     LLVMRealPredicate ConvertLLVMPredicateFromFCMP(FCmpCondition cond);
416     LLVMIntPredicate ConvertLLVMPredicateFromICMP(ICmpCondition cond);
417     LLVMValueRef GetGlue(const std::vector<GateRef> &inList);
418     LLVMValueRef GetLeaveFrameOffset(LLVMValueRef glue);
419     LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index);
420     LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index);
421     LLVMValueRef GetBaselineStubOffset(LLVMValueRef glue, int index);
422     LLVMValueRef GetBCStubOffset(LLVMValueRef glue);
423     LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue);
424     LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue);
425     LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue);
426     CallExceptionKind GetCallExceptionKind(size_t index, OpCode op) const;
427     void ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs,
428                                     const std::vector<GateRef> &inList, CallExceptionKind kind);
429     void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value);
430     void SaveByteCodePcOnOptJSFuncFrame(LLVMValueRef value);
431     void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value);
432     void SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder);
433     void UpdateLeaveFrame(LLVMValueRef glue);
434     LLVMTypeRef GetExperimentalDeoptTy();
435     LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module);
436     void GenDeoptEntry(LLVMModuleRef &module);
437     LLVMMetadataRef GetFunctionTypeMD(LLVMMetadataRef dFile);
438     bool SetDebugInfo(GateRef g, LLVMValueRef r);
439     LLVMValueRef ConvertToTagged(GateRef gate);
440     LLVMValueRef ConvertBoolToTaggedBoolean(GateRef gate);
441     LLVMValueRef ConvertInt32ToTaggedInt(GateRef gate);
442     LLVMValueRef ConvertInt32ToTaggedInt(LLVMValueRef value);
443     LLVMValueRef ConvertFloat64ToTaggedDouble(GateRef gate);
444     void SaveDeoptVregInfo(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift,
445                            GateRef gate);
446     void SaveDeoptVregInfoWithI64(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift,
447                            GateRef gate);
448     int LookupPredBB(GateRef start, int bbID);
GetLValue(const GateRef g)449     LLVMValueRef GetLValue(const GateRef g)
450     {
451         return gate2LValue_[g];
452     }
Bind(const GateRef g,const LLVMValueRef lv)453     void Bind(const GateRef g, const LLVMValueRef lv)
454     {
455         gate2LValue_[g] = lv;
456     }
457     using TargetBuilderMap = std::unordered_map<std::string, std::function<LLVMTargetBuilder*()>>;
GlobalTargetBuilders()458     static TargetBuilderMap& GlobalTargetBuilders()
459     {
460         static TargetBuilderMap targetBuilderCreators;
461         return targetBuilderCreators;
462     }
463 
464     const CompilationConfig *compCfg_ {nullptr};
465     const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
466     Circuit *circuit_ {nullptr};
467     GateAccessor acc_;
468     BasicBlock *currentBb_ {nullptr};
469     int lineNumber_ {0};
470 
471     LLVMModuleRef module_ {nullptr};
472     LLVMContextRef context_ {nullptr};
473     LLVMValueRef function_ {nullptr};
474     LLVMBuilderRef builder_ {nullptr};
475     std::map<GateId, int> instID2bbID_;
476     BasicBlockMap bbID2BB_;
477 
478     std::vector<BasicBlock *> phiRebuildWorklist_;
479     LLVMModule *llvmModule_ {nullptr};
480     std::unordered_map<GateRef, LLVMValueRef> gate2LValue_;
481     std::unordered_map<OpCode, HandleType> opHandlers_;
482     std::set<OpCode> illegalOpHandlers_;
483     int slotSize_ {-1};
484     LLVMTypeRef slotType_ {nullptr};
485     CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv;
486     bool enableLog_ {false};
487     bool isFastCallAot_ {false};
488     LLVMMetadataRef dFuncMD_ {nullptr};
489     bool enableOptInlining_ {false};
490     bool enableOptBranchProfiling_ {true};
491     LLVMValueRef ASMBarrierCall_ {nullptr};
492     LLVMTargetBuilder* targetBuilder_ {nullptr};
493     static constexpr std::string_view COLD_ATTR = "cold";
494 };
495 }  // namespace panda::ecmascript::kungfu
496 #endif  // ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
497