• 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_, bool isDirectCall) = 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 enableOptDirectCall, 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 GetOrDeclareFunction(const CallSignature *signature) const;
338     LLVMValueRef GetCallee(const std::vector<GateRef> &inList, const CallSignature *signature,
339                            const std::string &realName = "");
340     void CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset,
341                                  GateRef frameState);
342     LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature,
343                                             LLVMValueRef reloc) const;
344     bool IsInterpreted() const;
345     bool IsBaselineBuiltin() const;
346     bool IsOptimized() const;
347     bool IsOptimizedJSFunction() const;
348     void SetGCLeafFunction(LLVMValueRef call);
349     void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call);
350     bool IsHeapPointerType(LLVMTypeRef valueType);
351 
GetVoidT()352     LLVMTypeRef GetVoidT() const
353     {
354         return llvmModule_->GetVoidT();
355     }
356 
GetInt1T()357     LLVMTypeRef GetInt1T() const
358     {
359         return llvmModule_->GetInt1T();
360     }
361 
GetInt8T()362     LLVMTypeRef GetInt8T() const
363     {
364         return llvmModule_->GetInt8T();
365     }
366 
GetInt16T()367     LLVMTypeRef GetInt16T() const
368     {
369         return llvmModule_->GetInt16T();
370     }
371 
GetInt32T()372     LLVMTypeRef GetInt32T() const
373     {
374         return llvmModule_->GetInt32T();
375     }
376 
GetInt64T()377     LLVMTypeRef GetInt64T() const
378     {
379         return llvmModule_->GetInt64T();
380     }
381 
GetFloatT()382     LLVMTypeRef GetFloatT() const
383     {
384         return llvmModule_->GetFloatT();
385     }
386 
GetDoubleT()387     LLVMTypeRef GetDoubleT() const
388     {
389         return llvmModule_->GetDoubleT();
390     }
391 
GetTaggedPtrT()392     LLVMTypeRef GetTaggedPtrT() const
393     {
394         return llvmModule_->GetTaggedPtrT();
395     }
396 
GetTaggedHPtrT()397     LLVMTypeRef GetTaggedHPtrT() const
398     {
399         return llvmModule_->GetTaggedHPtrT();
400     }
401 
GetRawPtrT()402     LLVMTypeRef GetRawPtrT() const
403     {
404         return llvmModule_->GetRawPtrT();
405     }
406 
407 private:
GetDIBuilder()408     LLVMDIBuilderRef GetDIBuilder() const
409     {
410         return llvmModule_ == nullptr ? nullptr : llvmModule_->GetDIBuilder();
411     }
412 
413     unsigned GetPtrAddressSpace(LLVMValueRef v) const;
414     bool IsLInteger(LLVMValueRef v) const;
415     bool IsLPointer(LLVMValueRef v) const;
416     LLVMRealPredicate ConvertLLVMPredicateFromFCMP(FCmpCondition cond);
417     LLVMIntPredicate ConvertLLVMPredicateFromICMP(ICmpCondition cond);
418     LLVMValueRef GetGlue(const std::vector<GateRef> &inList);
419     LLVMValueRef GetLeaveFrameOffset(LLVMValueRef glue);
420     LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index);
421     LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index);
422     LLVMValueRef GetBaselineStubOffset(LLVMValueRef glue, int index);
423     LLVMValueRef GetBCStubOffset(LLVMValueRef glue);
424     LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue);
425     LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue);
426     LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue);
427     CallExceptionKind GetCallExceptionKind(OpCode op, size_t index = SIZE_MAX) const;
428     void ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs,
429                                     const std::vector<GateRef> &inList, CallExceptionKind kind);
430     void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value);
431     void SaveByteCodePcOnOptJSFuncFrame(LLVMValueRef value);
432     void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value);
433     void SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder);
434     void UpdateLeaveFrame(LLVMValueRef glue);
435     LLVMTypeRef GetExperimentalDeoptTy();
436     LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module);
437     void GenDeoptEntry(LLVMModuleRef &module);
438     LLVMMetadataRef GetFunctionTypeMD(LLVMMetadataRef dFile);
439     bool SetDebugInfo(GateRef g, LLVMValueRef r);
440     LLVMValueRef ConvertToTagged(GateRef gate);
441     LLVMValueRef ConvertBoolToTaggedBoolean(GateRef gate);
442     LLVMValueRef ConvertInt32ToTaggedInt(GateRef gate);
443     LLVMValueRef ConvertInt32ToTaggedInt(LLVMValueRef value);
444     LLVMValueRef ConvertFloat64ToTaggedDouble(GateRef gate);
445     void SaveDeoptVregInfo(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift,
446                            GateRef gate);
447     void SaveDeoptVregInfoWithI64(std::vector<LLVMValueRef> &values, int32_t index, size_t curDepth, size_t shift,
448                            GateRef gate);
449     int LookupPredBB(GateRef start, int bbID);
GetLValue(const GateRef g)450     LLVMValueRef GetLValue(const GateRef g)
451     {
452         return gate2LValue_[g];
453     }
Bind(const GateRef g,const LLVMValueRef lv)454     void Bind(const GateRef g, const LLVMValueRef lv)
455     {
456         gate2LValue_[g] = lv;
457     }
458     using TargetBuilderMap = std::unordered_map<std::string, std::function<LLVMTargetBuilder*()>>;
GlobalTargetBuilders()459     static TargetBuilderMap& GlobalTargetBuilders()
460     {
461         static TargetBuilderMap targetBuilderCreators;
462         return targetBuilderCreators;
463     }
464 
465     const CompilationConfig *compCfg_ {nullptr};
466     const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
467     Circuit *circuit_ {nullptr};
468     GateAccessor acc_;
469     BasicBlock *currentBb_ {nullptr};
470     int lineNumber_ {0};
471 
472     LLVMModuleRef module_ {nullptr};
473     LLVMContextRef context_ {nullptr};
474     LLVMValueRef function_ {nullptr};
475     LLVMBuilderRef builder_ {nullptr};
476     std::map<GateId, int> instID2bbID_;
477     BasicBlockMap bbID2BB_;
478 
479     std::vector<BasicBlock *> phiRebuildWorklist_;
480     LLVMModule *llvmModule_ {nullptr};
481     std::unordered_map<GateRef, LLVMValueRef> gate2LValue_;
482     std::unordered_map<OpCode, HandleType> opHandlers_;
483     std::set<OpCode> illegalOpHandlers_;
484     int slotSize_ {-1};
485     LLVMTypeRef slotType_ {nullptr};
486     CallSignature::CallConv callConv_ = CallSignature::CallConv::CCallConv;
487     bool enableLog_ {false};
488     bool isFastCallAot_ {false};
489     LLVMMetadataRef dFuncMD_ {nullptr};
490     bool enableOptDirectCall_ {false};
491     bool enableOptInlining_ {false};
492     bool enableOptBranchProfiling_ {true};
493     LLVMValueRef ASMBarrierCall_ {nullptr};
494     LLVMTargetBuilder* targetBuilder_ {nullptr};
495     static constexpr std::string_view COLD_ATTR = "cold";
496 };
497 }  // namespace panda::ecmascript::kungfu
498 #endif  // ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
499