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
37namespace panda::ecmascript::kungfu {
38class BasicBlock;
39class DebugInfo;
40using BasicBlockMap = std::map<int, std::unique_ptr<BasicBlock>>;
41class LLVMIRBuilder;
42using HandleType = void(LLVMIRBuilder::*)(GateRef gate);
43
44class BasicBlock {
45public:
46    explicit BasicBlock(int id) : id_(id)
47    {
48        predecessors_ = {};
49        successors_ = {};
50        impl_ = nullptr;
51    }
52
53    int GetId() const
54    {
55        return id_;
56    }
57
58    template<class T>
59    inline T *GetImpl() const
60    {
61        return static_cast<T *>(impl_);
62    }
63
64    inline void SetImpl(void *impl)
65    {
66        impl_ = impl;
67    }
68
69    template<class T>
70    inline void ResetImpl()
71    {
72        if (impl_) {
73            delete GetImpl<T>();
74            impl_ = nullptr;
75        }
76    }
77    ~BasicBlock() = default;
78
79private:
80    std::vector<BasicBlock *> predecessors_ {};
81    std::vector<BasicBlock *> successors_ {};
82    int id_ {-1};
83    void *impl_ {nullptr};
84};
85
86struct NotMergedPhiDesc {
87    int predBBId;
88    GateRef operand;
89    LLVMValueRef phi;
90};
91
92struct BasicBlockImpl {
93    LLVMBasicBlockRef lBB_ = nullptr;
94    LLVMBasicBlockRef continuation = nullptr;
95    bool started = false;
96    bool ended = false;
97    std::vector<NotMergedPhiDesc> unmergedPhis_;
98};
99
100class LLVMModule : public IRModule {
101public:
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);
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
118    void SetFunction(size_t index, LLVMValueRef func, bool isFastCall)
119    {
120        funcIndexMap_.emplace_back(std::make_tuple(index, func, isFastCall));
121    }
122
123    ModuleKind GetModuleKind() const override
124    {
125        return MODULE_LLVM;
126    }
127
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
139    size_t GetFuncCount() const
140    {
141        return funcIndexMap_.size();
142    }
143
144    template<class Callback>
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
153    const CallSignature *GetCSign(size_t index) const
154    {
155        return callSigns_[index];
156    }
157
158    const std::vector<const CallSignature*> &GetCSigns() const
159    {
160        return callSigns_;
161    }
162
163    LLVMContextRef GetContext() const
164    {
165        return context_;
166    }
167
168    LLVMMetadataRef GetDFileMD() const
169    {
170        return dFileMD_;
171    }
172
173    LLVMDIBuilderRef GetDIBuilder() const
174    {
175        return dBuilder_;
176    }
177
178    LLVMValueRef GetDeoptFunction();
179
180    static constexpr int kDeoptEntryOffset = 0;
181
182    LLVMTypeRef GetVoidT() const
183    {
184        return voidT_;
185    }
186
187    LLVMTypeRef GetInt1T() const
188    {
189        return int1T_;
190    }
191
192    LLVMTypeRef GetInt8T() const
193    {
194        return int8T_;
195    }
196
197    LLVMTypeRef GetInt16T() const
198    {
199        return int16T_;
200    }
201
202    LLVMTypeRef GetInt32T() const
203    {
204        return int32T_;
205    }
206
207    LLVMTypeRef GetInt64T() const
208    {
209        return int64T_;
210    }
211
212    LLVMTypeRef GetFloatT() const
213    {
214        return floatT_;
215    }
216
217    LLVMTypeRef GetDoubleT() const
218    {
219        return doubleT_;
220    }
221
222    LLVMTypeRef GetTaggedPtrT() const
223    {
224        return taggedPtrT_;
225    }
226
227    LLVMTypeRef GetTaggedHPtrT() const
228    {
229        return taggedHPtrT_;
230    }
231
232    LLVMTypeRef GetRawPtrT() const
233    {
234        return rawPtrT_;
235    }
236
237    LLVMTypeRef ConvertLLVMTypeFromVariableType(VariableType type);
238private:
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
267using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>;
268
269class LLVMTargetBuilder {
270public:
271    virtual ~LLVMTargetBuilder() = default;
272    virtual LLVMValueRef GetASMBarrierCall(LLVMModule *llvmModule_) = 0;
273};
274
275class LLVMIRBuilder {
276public:
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
284    static void RegisterTargetBuilder(const std::string& triple, const std::function<LLVMTargetBuilder*()>& creator)
285    {
286        GlobalTargetBuilders().emplace(triple, creator);
287    };
288private:
289    #define DECLAREVISITOPCODE(name, signature) void Visit##name signature;
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
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
351    LLVMTypeRef GetVoidT() const
352    {
353        return llvmModule_->GetVoidT();
354    }
355
356    LLVMTypeRef GetInt1T() const
357    {
358        return llvmModule_->GetInt1T();
359    }
360
361    LLVMTypeRef GetInt8T() const
362    {
363        return llvmModule_->GetInt8T();
364    }
365
366    LLVMTypeRef GetInt16T() const
367    {
368        return llvmModule_->GetInt16T();
369    }
370
371    LLVMTypeRef GetInt32T() const
372    {
373        return llvmModule_->GetInt32T();
374    }
375
376    LLVMTypeRef GetInt64T() const
377    {
378        return llvmModule_->GetInt64T();
379    }
380
381    LLVMTypeRef GetFloatT() const
382    {
383        return llvmModule_->GetFloatT();
384    }
385
386    LLVMTypeRef GetDoubleT() const
387    {
388        return llvmModule_->GetDoubleT();
389    }
390
391    LLVMTypeRef GetTaggedPtrT() const
392    {
393        return llvmModule_->GetTaggedPtrT();
394    }
395
396    LLVMTypeRef GetTaggedHPtrT() const
397    {
398        return llvmModule_->GetTaggedHPtrT();
399    }
400
401    LLVMTypeRef GetRawPtrT() const
402    {
403        return llvmModule_->GetRawPtrT();
404    }
405
406private:
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);
449    LLVMValueRef GetLValue(const GateRef g)
450    {
451        return gate2LValue_[g];
452    }
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*()>>;
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