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 44 namespace panda::ecmascript::kungfu { 45 class CompilerLog; 46 class MethodLogList; 47 class LLVMModule; 48 49 enum class FPFlag : uint32_t { 50 ELIM_FP = 0, 51 RESERVE_FP = 1 52 }; 53 54 struct 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 LOptionsLOptions59 LOptions() : optLevel(3), genFp(static_cast<uint32_t>(FPFlag::RESERVE_FP)), relocMode(2) {}; LOptionsLOptions60 LOptions(size_t level, FPFlag flag, size_t relocMode) 61 : optLevel(level), genFp(static_cast<uint32_t>(flag)), relocMode(relocMode) {}; 62 }; 63 64 class LLVMAssembler : public Assembler { 65 public: 66 explicit LLVMAssembler(LLVMModule *lm, LOptions option = LOptions()); 67 virtual ~LLVMAssembler(); 68 void Run(const CompilerLog &log, bool fastCompileMode) override; GetEngine()69 const LLVMExecutionEngineRef &GetEngine() 70 { 71 return engine_; 72 } 73 void Disassemble(const std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset, 74 const CompilerLog &log, const MethodLogList &logList, std::ostringstream &codeStream) const; 75 static void Disassemble(const std::map<uintptr_t, std::string> *addr2name, 76 const std::string& triple, uint8_t *buf, size_t size); 77 static int GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log); 78 static kungfu::CalleeRegAndOffsetVec GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log); 79 GetFuncPtrFromCompiledModule(LLVMValueRef function)80 void *GetFuncPtrFromCompiledModule(LLVMValueRef function) 81 { 82 return LLVMGetPointerToGlobal(engine_, function); 83 } 84 SetObjFile(const llvm::object::ObjectFile * obj)85 void SetObjFile(const llvm::object::ObjectFile *obj) 86 { 87 objFile_ = obj; 88 } 89 private: 90 class AOTEventListener : public llvm::JITEventListener { 91 public: AOTEventListener(LLVMAssembler * as)92 AOTEventListener(LLVMAssembler* as) : as_(as) 93 { 94 } notifyObjectLoaded(ObjectKey key,const llvm::object::ObjectFile & objFile,const llvm::RuntimeDyld::LoadedObjectInfo & objInfo)95 void notifyObjectLoaded([[maybe_unused]] ObjectKey key, const llvm::object::ObjectFile &objFile, 96 [[maybe_unused]] const llvm::RuntimeDyld::LoadedObjectInfo &objInfo) 97 { 98 as_->SetObjFile(&objFile); 99 } 100 private: GetAssembler()101 LLVMAssembler* GetAssembler() const 102 { 103 return as_; 104 } 105 106 LLVMAssembler* as_ {nullptr}; 107 }; 108 109 void UseRoundTripSectionMemoryManager(); 110 bool BuildMCJITEngine(); 111 void BuildAndRunPasses(); 112 void BuildAndRunPassesFastMode(); 113 void Initialize(LOptions option); 114 static void PrintInstAndStep(uint64_t &pc, uint8_t **byteSp, uintptr_t &numBytes, size_t instSize, 115 uint64_t textOffset, char *outString, std::ostringstream &codeStream, 116 bool logFlag = true); 117 uint64_t GetTextSectionIndex() const; 118 119 LLVMMCJITCompilerOptions options_ {}; 120 LLVMModule *llvmModule_ {nullptr}; 121 LLVMModuleRef module_ {nullptr}; 122 const llvm::object::ObjectFile* objFile_ {nullptr}; 123 LLVMExecutionEngineRef engine_ {nullptr}; 124 AOTEventListener listener_; 125 char *error_ {nullptr}; 126 }; 127 128 class LLVMIRGeneratorImpl : public CodeGeneratorImpl { 129 public: LLVMIRGeneratorImpl(LLVMModule * module,bool enableLog)130 LLVMIRGeneratorImpl(LLVMModule *module, bool enableLog) 131 : module_(module), enableLog_(enableLog) {} 132 ~LLVMIRGeneratorImpl() override = default; 133 void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index, 134 const CompilationConfig *cfg) override; 135 void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg, 136 const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const std::string &methodName, 137 bool enableOptInlining, bool enableBranchProfiling) override; 138 IsLogEnabled()139 bool IsLogEnabled() const 140 { 141 return enableLog_; 142 } 143 144 private: 145 LLVMModule *module_; 146 bool enableLog_ {false}; 147 }; 148 } // namespace panda::ecmascript::kungfu 149 #endif // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H 150