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