1/*
2 * Copyright (c) 2021 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_CODEGEN_H
17#define ECMASCRIPT_COMPILER_LLVM_CODEGEN_H
18
19#include "ecmascript/compiler/binary_section.h"
20#include "ecmascript/compiler/code_generator.h"
21
22#if defined(__clang__)
23#pragma clang diagnostic push
24#pragma clang diagnostic ignored "-Wshadow"
25#pragma clang diagnostic ignored "-Wunused-parameter"
26#pragma clang diagnostic ignored "-Wdeprecated-declarations"
27#elif defined(__GNUC__)
28#pragma GCC diagnostic push
29#pragma GCC diagnostic ignored "-Wshadow"
30#pragma GCC diagnostic ignored "-Wunused-parameter"
31#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
32#endif
33
34#include "llvm-c/Core.h"
35#include "llvm-c/ExecutionEngine.h"
36#include "llvm/ExecutionEngine/JITEventListener.h"
37
38#if defined(__clang__)
39#pragma clang diagnostic pop
40#elif defined(__GNUC__)
41#pragma GCC diagnostic pop
42#endif
43
44namespace panda::ecmascript::kungfu {
45class CompilerLog;
46class MethodLogList;
47class LLVMModule;
48
49enum class FPFlag : uint32_t {
50    ELIM_FP = 0,
51    RESERVE_FP = 1
52};
53
54struct LOptions {
55    uint32_t optLevel : 2; // 2 bits for optimized level 0-4
56    uint32_t genFp : 1; // 1 bit for whether to generated frame pointer or not
57    uint32_t relocMode : 3; // 3 bits for relocation mode
58    // 3: default optLevel, 1: generating fp, 2: PIC mode
59    LOptions() : optLevel(3), genFp(static_cast<uint32_t>(FPFlag::RESERVE_FP)), relocMode(2) {};
60    LOptions(size_t level, FPFlag flag, size_t relocMode)
61        : optLevel(level), genFp(static_cast<uint32_t>(flag)), relocMode(relocMode) {};
62};
63
64class LLVMAssembler : public Assembler {
65public:
66    explicit LLVMAssembler(LLVMModule *lm, CodeInfo::CodeSpaceOnDemand &codeSpaceOnDemand,
67                           LOptions option = LOptions());
68    virtual ~LLVMAssembler();
69    void Run(const CompilerLog &log, bool fastCompileMode, bool isJit = false) override;
70    const LLVMExecutionEngineRef &GetEngine()
71    {
72        return engine_;
73    }
74    void Disassemble(const std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset,
75                     const CompilerLog &log, const MethodLogList &logList, std::ostringstream &codeStream) const;
76    static void Disassemble(const std::map<uintptr_t, std::string> *addr2name,
77                            const std::string& triple, uint8_t *buf, size_t size);
78    static int GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log);
79    static kungfu::CalleeRegAndOffsetVec GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log);
80
81    void *GetFuncPtrFromCompiledModule(LLVMValueRef function)
82    {
83        return LLVMGetPointerToGlobal(engine_, function);
84    }
85
86    void SetObjFile(const llvm::object::ObjectFile *obj)
87    {
88        objFile_ = obj;
89    }
90private:
91    class AOTEventListener : public llvm::JITEventListener {
92      public:
93        AOTEventListener(LLVMAssembler* as) : as_(as)
94        {
95        }
96        void notifyObjectLoaded([[maybe_unused]] ObjectKey key, const llvm::object::ObjectFile &objFile,
97                                [[maybe_unused]] const llvm::RuntimeDyld::LoadedObjectInfo &objInfo)
98        {
99            as_->SetObjFile(&objFile);
100        }
101      private:
102        LLVMAssembler* GetAssembler() const
103        {
104            return as_;
105        }
106
107        LLVMAssembler* as_ {nullptr};
108    };
109
110    void UseRoundTripSectionMemoryManager(bool isJit);
111    bool BuildMCJITEngine();
112    void BuildAndRunPasses();
113    void BuildAndRunPassesFastMode();
114    void Initialize(LOptions option);
115    static void PrintInstAndStep(uint64_t &pc, uint8_t **byteSp, uintptr_t &numBytes, size_t instSize,
116                                 uint64_t textOffset, char *outString, std::ostringstream &codeStream,
117                                 bool logFlag = true);
118    uint64_t GetTextSectionIndex() const;
119
120    LLVMMCJITCompilerOptions options_ {};
121    LLVMModule *llvmModule_ {nullptr};
122    LLVMModuleRef module_ {nullptr};
123    const llvm::object::ObjectFile* objFile_ {nullptr};
124    LLVMExecutionEngineRef engine_ {nullptr};
125    AOTEventListener listener_;
126    char *error_ {nullptr};
127};
128
129class LLVMIRGeneratorImpl : public CodeGeneratorImpl {
130public:
131    LLVMIRGeneratorImpl(LLVMModule *module, bool enableLog)
132        : module_(module), enableLog_(enableLog) {}
133    ~LLVMIRGeneratorImpl() override = default;
134    void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
135                             const CompilationConfig *cfg) override;
136    void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
137        const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const std::string &methodName,
138        const FrameType frameType, bool enableOptInlining, bool enableBranchProfiling) override;
139
140    bool IsLogEnabled() const
141    {
142        return enableLog_;
143    }
144
145private:
146    LLVMModule *module_;
147    bool enableLog_ {false};
148};
149}  // namespace panda::ecmascript::kungfu
150#endif  // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H
151