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