1 /* 2 * Copyright (c) 2021-2022 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 PANDA_FUNCTION_H 17 #define PANDA_FUNCTION_H 18 19 #include "compiler/optimizer/ir/ir_constructor.h" 20 #include "compiler/optimizer/code_generator/relocations.h" 21 #include "utils/expected.h" 22 #include "source_languages.h" 23 #include "irtoc_options.h" 24 25 #ifdef PANDA_LLVM_IRTOC 26 #include "llvm_compiler_creator.h" 27 #include "llvm_options.h" 28 #endif // PANDA_LLVM_IRTOC 29 30 namespace panda::irtoc { 31 32 enum class CompilationResult { 33 INVALID, 34 // This unit was compiled by Ark's default compiler because it must be compiled by Ark, not by llvm. 35 // It happens for the following reasons: 36 // 1. PANDA_LLVM_BACKEND is disabled 37 // 2. Current function is an interpreter handler for Ark's compiler (no "_LLVM" suffix) 38 // 3. Current function is FastPath, but PANDA_LLVM_FASTPATH is disabled 39 // 4. Irtoc Unit tests are compiled 40 ARK, 41 // Successfully compiled by llvm 42 LLVM, 43 // llvm_compiler->CanCompile had returned false, and we fell back to Ark's default compiler 44 ARK_BECAUSE_FALLBACK, 45 // See SKIPPED_HANDLERS and SKIPPED_FASTPATHS 46 ARK_BECAUSE_SKIP 47 }; 48 49 #if USE_VIXL_ARM64 && !PANDA_MINIMAL_VIXL && PANDA_LLVM_INTERPRETER 50 #define LLVM_INTERPRETER_CHECK_REGS_MASK 51 #endif 52 53 #ifdef LLVM_INTERPRETER_CHECK_REGS_MASK 54 struct UsedRegisters { 55 // NOLINTBEGIN(misc-non-private-member-variables-in-classes) 56 RegMask gpr; 57 VRegMask fp; 58 // NOLINTEND(misc-non-private-member-variables-in-classes) 59 60 constexpr UsedRegisters &operator|=(UsedRegisters that) 61 { 62 gpr |= that.gpr; 63 fp |= that.fp; 64 return *this; 65 } 66 }; 67 #endif 68 69 class Function : public compiler::RelocationHandler { 70 public: 71 using Result = Expected<CompilationResult, const char *>; 72 73 #ifdef PANDA_LLVM_IRTOC Function()74 Function() : llvmCompiler_(nullptr) {} 75 #else 76 Function() = default; 77 #endif 78 NO_COPY_SEMANTIC(Function); 79 NO_MOVE_SEMANTIC(Function); 80 81 virtual ~Function() = default; 82 83 virtual void MakeGraphImpl() = 0; 84 virtual const char *GetName() const = 0; 85 86 Result Compile(Arch arch, ArenaAllocator *allocator, ArenaAllocator *localAllocator); 87 GetCode()88 auto GetCode() const 89 { 90 return Span(code_); 91 } 92 GetGraph()93 compiler::Graph *GetGraph() 94 { 95 return graph_; 96 } 97 GetGraph()98 const compiler::Graph *GetGraph() const 99 { 100 return graph_; 101 } 102 WordSize()103 size_t WordSize() const 104 { 105 return PointerSize(GetArch()); 106 } 107 108 void AddRelocation(const compiler::RelocationInfo &info) override; 109 GetRelocations()110 const auto &GetRelocations() const 111 { 112 return relocationEntries_; 113 } 114 GetExternalFunction(size_t index)115 const char *GetExternalFunction(size_t index) const 116 { 117 CHECK_LT(index, externalFunctions_.size()); 118 return externalFunctions_[index].c_str(); 119 } 120 GetLanguage()121 SourceLanguage GetLanguage() const 122 { 123 return lang_; 124 } 125 AddSourceDir(std::string_view dir)126 uint32_t AddSourceDir(std::string_view dir) 127 { 128 auto it = std::find(sourceDirs_.begin(), sourceDirs_.end(), dir); 129 if (it != sourceDirs_.end()) { 130 return std::distance(sourceDirs_.begin(), it); 131 } 132 sourceDirs_.emplace_back(dir); 133 return sourceDirs_.size() - 1; 134 } 135 AddSourceFile(std::string_view filename)136 uint32_t AddSourceFile(std::string_view filename) 137 { 138 auto it = std::find(sourceFiles_.begin(), sourceFiles_.end(), filename); 139 if (it != sourceFiles_.end()) { 140 return std::distance(sourceFiles_.begin(), it); 141 } 142 sourceFiles_.emplace_back(filename); 143 return sourceFiles_.size() - 1; 144 } 145 GetSourceFileIndex(const char * filename)146 uint32_t GetSourceFileIndex(const char *filename) const 147 { 148 auto it = std::find(sourceFiles_.begin(), sourceFiles_.end(), filename); 149 ASSERT(it != sourceFiles_.end()); 150 return std::distance(sourceFiles_.begin(), it); 151 } 152 GetSourceDirIndex(const char * dir)153 uint32_t GetSourceDirIndex(const char *dir) const 154 { 155 auto it = std::find(sourceDirs_.begin(), sourceDirs_.end(), dir); 156 ASSERT(it != sourceDirs_.end()); 157 return std::distance(sourceDirs_.begin(), it); 158 } 159 GetSourceFiles()160 Span<const std::string> GetSourceFiles() const 161 { 162 return Span<const std::string>(sourceFiles_); 163 } 164 GetSourceDirs()165 Span<const std::string> GetSourceDirs() const 166 { 167 return Span<const std::string>(sourceDirs_); 168 } 169 SetArgsCount(size_t argsCount)170 void SetArgsCount(size_t argsCount) 171 { 172 argsCount_ = argsCount; 173 } 174 GetArgsCount()175 size_t GetArgsCount() const 176 { 177 return GetArch() != Arch::AARCH32 ? argsCount_ : 0U; 178 } 179 180 #ifdef PANDA_LLVM_IRTOC 181 void ReportCompilationStatistic(std::ostream *out); 182 SetLLVMCompiler(std::shared_ptr<llvmbackend::CompilerInterface> compiler)183 void SetLLVMCompiler(std::shared_ptr<llvmbackend::CompilerInterface> compiler) 184 { 185 llvmCompiler_ = std::move(compiler); 186 } 187 188 #endif // PANDA_LLVM_IRTOC 189 IsCompiledByLlvm()190 bool IsCompiledByLlvm() const 191 { 192 return compilationResult_ == CompilationResult::LLVM; 193 } 194 GetCompilationResult()195 CompilationResult GetCompilationResult() 196 { 197 return compilationResult_; 198 } 199 GetCodeSize()200 size_t GetCodeSize() 201 { 202 return code_.size(); 203 } 204 205 void SetCode(Span<uint8_t> code); 206 207 protected: GetArch()208 Arch GetArch() const 209 { 210 return GetGraph()->GetArch(); 211 } 212 GetRuntime()213 compiler::RuntimeInterface *GetRuntime() 214 { 215 return GetGraph()->GetRuntime(); 216 } 217 SetExternalFunctions(std::initializer_list<std::string> funcs)218 void SetExternalFunctions(std::initializer_list<std::string> funcs) 219 { 220 externalFunctions_ = funcs; 221 } 222 SetLanguage(SourceLanguage lang)223 void SetLanguage(SourceLanguage lang) 224 { 225 lang_ = lang; 226 } 227 228 Result RunOptimizations(); 229 230 CompilationResult CompileByLLVM(); 231 232 #ifdef PANDA_LLVM_IRTOC 233 bool SkippedByLLVM(); 234 235 std::string_view GraphModeToString(); 236 237 std::string_view LLVMCompilationResultToString() const; 238 #endif // PANDA_LLVM_IRTOC 239 240 protected: 241 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) 242 std::unique_ptr<compiler::IrConstructor> builder_; 243 244 private: 245 /** 246 * Suffix for compilation unit names to compile by llvm. 247 * 248 * --interpreter-type option in Ark supports interpreters produced by stock irtoc and llvm irtoc. 249 * To support interpreter compiled by stock irtoc and llvm irtoc we: 250 * 1. Copy a graph for a handler with "_LLVM" suffix. For example, "ClassResolver" becomes "ClassResolver_LLVM" 251 * 2. Compile handlers with suffix by LLVMIrtocCompiler 252 * 3. Setup dispatch table to invoke handlers with "_LLVM" suffix at runtime in SetupLLVMDispatchTableImpl 253 */ 254 static constexpr std::string_view LLVM_SUFFIX = "_LLVM"; 255 256 compiler::Graph *graph_ {nullptr}; 257 SourceLanguage lang_ {SourceLanguage::PANDA_ASSEMBLY}; 258 std::vector<uint8_t> code_; 259 std::vector<std::string> externalFunctions_; 260 std::vector<std::string> sourceDirs_; 261 std::vector<std::string> sourceFiles_; 262 std::vector<compiler::RelocationInfo> relocationEntries_; 263 size_t argsCount_ {0U}; 264 CompilationResult compilationResult_ {CompilationResult::INVALID}; 265 #ifdef PANDA_LLVM_IRTOC 266 std::shared_ptr<llvmbackend::CompilerInterface> llvmCompiler_ {nullptr}; 267 #ifdef PANDA_LLVM_INTERPRETER 268 static constexpr std::array SKIPPED_HANDLERS = { 269 "ExecuteImplFast", 270 "ExecuteImplFastEH", 271 }; 272 #endif // PANDA_LLVM_INTERPRETER 273 #ifdef PANDA_LLVM_FASTPATH 274 static constexpr std::array SKIPPED_FASTPATHS = { 275 "IntfInlineCache", 276 "StringHashCode", // NOTE: To investigate if LLVM code is better (no MAdd) 277 "StringHashCodeCompressed", 278 }; 279 #endif // PANDA_LLVM_FASTPATH 280 #endif // PANDA_LLVM_IRTOC 281 }; 282 } // namespace panda::irtoc 283 284 #endif // PANDA_FUNCTION_H 285