• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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