• 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 COMPILER_TESTS_UNIT_TEST_H
17 #define COMPILER_TESTS_UNIT_TEST_H
18 
19 #include <numeric>
20 #include <unordered_map>
21 #include "gtest/gtest.h"
22 #include "optimizer/ir/ir_constructor.h"
23 #include "mem/arena_allocator.h"
24 #include "mem/pool_manager.h"
25 #include "compiler.h"
26 #include "compiler_logger.h"
27 #include "graph_comparator.h"
28 #include "include/runtime.h"
29 
30 namespace panda::compiler {
31 struct RuntimeInterfaceMock : public compiler::RuntimeInterface {
GetMethodReturnTypeRuntimeInterfaceMock32     DataType::Type GetMethodReturnType(MethodPtr /* unsuded */) const override
33     {
34         return return_type;
35     }
36 
GetMethodTotalArgumentTypeRuntimeInterfaceMock37     DataType::Type GetMethodTotalArgumentType(MethodPtr /* unused */, size_t index) const override
38     {
39         if (arg_types == nullptr || index >= arg_types->size()) {
40             return DataType::NO_TYPE;
41         }
42         return arg_types->at(index);
43     }
44 
GetMethodTotalArgumentsCountRuntimeInterfaceMock45     size_t GetMethodTotalArgumentsCount(MethodPtr /* unused */) const override
46     {
47         if (arg_types == nullptr) {
48             return args_count;
49         }
50         return arg_types->size();
51     }
GetMethodArgumentsCountRuntimeInterfaceMock52     size_t GetMethodArgumentsCount(MethodPtr /* unused */) const override
53     {
54         return args_count;
55     }
56 
GetMethodRegistersCountRuntimeInterfaceMock57     size_t GetMethodRegistersCount(MethodPtr /* unused */) const override
58     {
59         return vregs_count;
60     }
61 
62     size_t args_count {0};
63     size_t vregs_count {0};
64     DataType::Type return_type {DataType::NO_TYPE};
65     ArenaVector<DataType::Type> *arg_types {nullptr};
66 };
67 
68 class CommonTest : public ::testing::Test {
69 public:
CommonTest()70     CommonTest()
71     {
72 #if defined(PANDA_TARGET_ARM64) || defined(PANDA_TARGET_32)
73         // We have issue with QEMU - so reduce memory heap
74         panda::mem::MemConfig::Initialize(32_MB, 64_MB, 200_MB, 32_MB);
75 #else
76         panda::mem::MemConfig::Initialize(32_MB, 64_MB, 256_MB, 32_MB);
77 #endif
78         PoolManager::Initialize();
79         allocator_ = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
80         object_allocator_ = new ArenaAllocator(SpaceType::SPACE_TYPE_OBJECT);
81         local_allocator_ = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
82         builder_ = new IrConstructor();
83     }
84     ~CommonTest() override;
85 
GetAllocator()86     ArenaAllocator *GetAllocator() const
87     {
88         return allocator_;
89     }
90 
GetObjectAllocator()91     ArenaAllocator *GetObjectAllocator() const
92     {
93         return object_allocator_;
94     }
95 
GetLocalAllocator()96     ArenaAllocator *GetLocalAllocator() const
97     {
98         return local_allocator_;
99     }
100 
GetArch()101     Arch GetArch() const
102     {
103         return arch_;
104     }
105 
106     Graph *CreateEmptyGraph(bool is_osr = false) const
107     {
108         return GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_, is_osr);
109     }
110 
CreateEmptyGraph(Arch arch)111     Graph *CreateEmptyGraph(Arch arch) const
112     {
113         return GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch, false);
114     }
115 
116     Graph *CreateGraphStartEndBlocks(bool is_dynamic = false) const
117     {
118         auto graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_, is_dynamic, false);
119         graph->CreateStartBlock();
120         graph->CreateEndBlock();
121         return graph;
122     }
CreateDynEmptyGraph()123     Graph *CreateDynEmptyGraph() const
124     {
125         return GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_, true, false);
126     }
CreateEmptyBytecodeGraph()127     Graph *CreateEmptyBytecodeGraph() const
128     {
129         return GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), Arch::NONE, false, true);
130     }
CreateEmptyFastpathGraph(Arch arch)131     Graph *CreateEmptyFastpathGraph(Arch arch) const
132     {
133         auto graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch, false);
134         graph->SetMode(GraphMode::FastPath());
135         return graph;
136     }
137 
CreateEmptyBlock(Graph * graph)138     BasicBlock *CreateEmptyBlock(Graph *graph) const
139     {
140         auto block = graph->GetAllocator()->New<BasicBlock>(graph);
141         graph->AddBlock(block);
142         return block;
143     }
144 
GetBlocksById(Graph * graph,std::vector<size_t> && ids)145     ArenaVector<BasicBlock *> GetBlocksById(Graph *graph, std::vector<size_t> &&ids) const
146     {
147         ArenaVector<BasicBlock *> blocks(graph->GetAllocator()->Adapter());
148         for (auto id : ids) {
149             blocks.push_back(&BB(id));
150         }
151         return blocks;
152     }
153 
CheckInputs(Inst & inst,std::initializer_list<size_t> list)154     bool CheckInputs(Inst &inst, std::initializer_list<size_t> list) const
155     {
156         if (inst.GetInputs().Size() != list.size()) {
157             return false;
158         }
159         auto it2 = list.begin();
160         for (auto it = inst.GetInputs().begin(); it != inst.GetInputs().end(); ++it, ++it2) {
161             if (it->GetInst() != &INS(*it2)) {
162                 return false;
163             }
164         }
165         return true;
166     }
167 
CheckUsers(Inst & inst,std::initializer_list<int> list)168     bool CheckUsers(Inst &inst, std::initializer_list<int> list) const
169     {
170         std::unordered_map<int, size_t> users_map;
171         for (auto l : list)
172             ++users_map[l];
173         for (auto &user : inst.GetUsers()) {
174             EXPECT_EQ(user.GetInst()->GetInput(user.GetIndex()).GetInst(), &inst);
175             if (users_map[user.GetInst()->GetId()]-- == 0)
176                 return false;
177         }
178         auto rest = std::accumulate(users_map.begin(), users_map.end(), 0, [](int a, auto &x) { return a + x.second; });
179         EXPECT_EQ(rest, 0);
180         return (rest == 0) ? true : false;
181     }
182 
183 protected:
184     IrConstructor *builder_;
185 
186 private:
187     ArenaAllocator *allocator_;
188     ArenaAllocator *object_allocator_;
189     ArenaAllocator *local_allocator_;
190 #ifdef PANDA_TARGET_ARM32
191     Arch arch_ {Arch::AARCH32};
192 #else
193     Arch arch_ {Arch::AARCH64};
194 #endif
195 };
196 
197 class GraphTest : public CommonTest {
198 public:
GraphTest()199     GraphTest() : graph_(CreateEmptyGraph())
200     {
201         graph_->SetRuntime(&runtime_);
202     }
~GraphTest()203     ~GraphTest() override {}
204 
GetGraph()205     Graph *GetGraph() const
206     {
207         return graph_;
208     }
209 
ResetGraph()210     void ResetGraph()
211     {
212         graph_ = CreateEmptyGraph();
213         graph_->SetRuntime(&runtime_);
214     }
215 
SetNumVirtRegs(size_t num)216     void SetNumVirtRegs(size_t num)
217     {
218         runtime_.vregs_count = num;
219         graph_->SetVRegsCount(std::max(graph_->GetVRegsCount(), runtime_.vregs_count + runtime_.args_count + 1));
220     }
221 
SetNumArgs(size_t num)222     void SetNumArgs(size_t num)
223     {
224         runtime_.args_count = num;
225         graph_->SetVRegsCount(std::max(graph_->GetVRegsCount(), runtime_.vregs_count + runtime_.args_count + 1));
226     }
227 
228 protected:
229     RuntimeInterfaceMock runtime_;
230     Graph *graph_ {nullptr};
231 };
232 
233 class PandaRuntimeTest : public ::testing::Test, public PandaRuntimeInterface {
234 public:
235     PandaRuntimeTest();
236 
237     ~PandaRuntimeTest() override;
238 
239     static void Initialize(int argc, char **argv);
240 
CreateGraph()241     Graph *CreateGraph()
242     {
243         auto graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_);
244         graph->SetRuntime(this);
245         return graph;
246     }
247 
CreateGraphOsr()248     Graph *CreateGraphOsr()
249     {
250         Graph *graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_, true);
251         graph->SetRuntime(this);
252         return graph;
253     }
254 
255     // this method is needed to create a graph with a working dump
CreateGraphWithDefaultRuntime()256     Graph *CreateGraphWithDefaultRuntime()
257     {
258         auto *graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_);
259         graph->SetRuntime(GetDefaultRuntime());
260         return graph;
261     }
262 
CreateGraphDynWithDefaultRuntime()263     Graph *CreateGraphDynWithDefaultRuntime()
264     {
265         auto *graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_);
266         graph->SetRuntime(GetDefaultRuntime());
267         graph->SetDynamicMethod();
268         return graph;
269     }
270 
271     // this method is needed to create a graph with a working dump
CreateGraphOsrWithDefaultRuntime()272     Graph *CreateGraphOsrWithDefaultRuntime()
273     {
274         auto *graph = GetAllocator()->New<Graph>(GetAllocator(), GetLocalAllocator(), arch_, true);
275         graph->SetRuntime(GetDefaultRuntime());
276         return graph;
277     }
278 
GetAllocator()279     ArenaAllocator *GetAllocator()
280     {
281         return allocator_;
282     }
283 
GetLocalAllocator()284     ArenaAllocator *GetLocalAllocator()
285     {
286         return local_allocator_;
287     }
288 
GetGraph()289     virtual Graph *GetGraph()
290     {
291         return graph_;
292     }
293 
GetClassLinker()294     auto GetClassLinker()
295     {
296         return panda::Runtime::GetCurrent()->GetClassLinker();
297     }
298 
299     void EnableLogs(Logger::Level level = Logger::Level::DEBUG)
300     {
301         Logger::EnableComponent(Logger::Component::COMPILER);
302         Logger::SetLevel(level);
303     }
304 
GetExecPath()305     const char *GetExecPath() const
306     {
307         return exec_path_;
308     }
309 
310     static RuntimeInterface *GetDefaultRuntime();
311 
312 protected:
313     IrConstructor *builder_;
314 
315 private:
316     Graph *graph_ {nullptr};
317     ArenaAllocator *allocator_ {nullptr};
318     ArenaAllocator *local_allocator_ {nullptr};
319     static inline const char *exec_path_ {nullptr};
320     Arch arch_ {RUNTIME_ARCH};
321 };
322 
323 class AsmTest : public PandaRuntimeTest {
324 public:
325     std::unique_ptr<const panda_file::File> ParseToFile(const char *source, const char *file_name = "test.pb");
326     bool Parse(const char *source, const char *file_name = "test.pb");
327     Graph *BuildGraph(const char *method_name, Graph *graph = nullptr);
328     void CleanUp(Graph *graph);
329 
330     virtual ~AsmTest() = default;
331 
332     template <bool with_cleanup = false>
333     bool ParseToGraph(const char *source, const char *method_name, Graph *graph = nullptr)
334     {
335         if (!Parse(source)) {
336             return false;
337         }
338         if (graph == nullptr) {
339             graph = GetGraph();
340         }
341         if (BuildGraph(method_name, graph) == nullptr) {
342             return false;
343         }
344         if constexpr (with_cleanup) {
345             CleanUp(graph);
346         }
347         return true;
348     }
349 };
350 
351 struct TmpFile {
TmpFileTmpFile352     explicit TmpFile(const char *file_name) : file_name_(file_name) {}
~TmpFileTmpFile353     ~TmpFile()
354     {
355         ASSERT(file_name_ != nullptr);
356         remove(file_name_);
357     }
GetFileNameTmpFile358     const char *GetFileName() const
359     {
360         return file_name_;
361     }
362 
363 private:
364     const char *file_name_ {nullptr};
365 };
366 }  // namespace panda::compiler
367 
368 #endif  // COMPILER_TESTS_UNIT_TEST_H
369