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#include <elf.h>
17b1994897Sopenharmony_ci#include "unit_test.h"
18b1994897Sopenharmony_ci#include "aot/aot_manager.h"
19b1994897Sopenharmony_ci#include "aot/aot_builder/aot_builder.h"
20b1994897Sopenharmony_ci#include "aot/compiled_method.h"
21b1994897Sopenharmony_ci#include "compiler/code_info/code_info_builder.h"
22b1994897Sopenharmony_ci#include "os/exec.h"
23b1994897Sopenharmony_ci#include "assembly-parser.h"
24b1994897Sopenharmony_ci#include "utils/string_helpers.h"
25b1994897Sopenharmony_ci#include "events/events.h"
26b1994897Sopenharmony_ci#include "mem/gc/gc_types.h"
27b1994897Sopenharmony_ci#include "runtime/include/file_manager.h"
28b1994897Sopenharmony_ci
29b1994897Sopenharmony_ci#include <regex>
30b1994897Sopenharmony_ci
31b1994897Sopenharmony_ciusing panda::panda_file::File;
32b1994897Sopenharmony_ci
33b1994897Sopenharmony_cinamespace panda::compiler {
34b1994897Sopenharmony_ciclass AotTest : public AsmTest {
35b1994897Sopenharmony_cipublic:
36b1994897Sopenharmony_ci    AotTest()
37b1994897Sopenharmony_ci    {
38b1994897Sopenharmony_ci        std::string exe_path = GetExecPath();
39b1994897Sopenharmony_ci        auto pos = exe_path.rfind('/');
40b1994897Sopenharmony_ci        paoc_path_ = exe_path.substr(0, pos) + "/../bin/ark_aot";
41b1994897Sopenharmony_ci        aotdump_path_ = exe_path.substr(0, pos) + "/../bin/ark_aotdump";
42b1994897Sopenharmony_ci    }
43b1994897Sopenharmony_ci
44b1994897Sopenharmony_ci    std::string GetPaocDirectory() const
45b1994897Sopenharmony_ci    {
46b1994897Sopenharmony_ci        auto pos = paoc_path_.rfind('/');
47b1994897Sopenharmony_ci        return paoc_path_.substr(0, pos);
48b1994897Sopenharmony_ci    }
49b1994897Sopenharmony_ci
50b1994897Sopenharmony_ci    const char *GetArchAsArgString() const
51b1994897Sopenharmony_ci    {
52b1994897Sopenharmony_ci        switch (target_arch) {
53b1994897Sopenharmony_ci            case Arch::AARCH32:
54b1994897Sopenharmony_ci                return "arm";
55b1994897Sopenharmony_ci            case Arch::AARCH64:
56b1994897Sopenharmony_ci                return "arm64";
57b1994897Sopenharmony_ci            case Arch::X86:
58b1994897Sopenharmony_ci                return "x86";
59b1994897Sopenharmony_ci            case Arch::X86_64:
60b1994897Sopenharmony_ci                return "x86_64";
61b1994897Sopenharmony_ci            default:
62b1994897Sopenharmony_ci                UNREACHABLE();
63b1994897Sopenharmony_ci        }
64b1994897Sopenharmony_ci    }
65b1994897Sopenharmony_ci
66b1994897Sopenharmony_ci    void RunAotdump(const std::string &aot_filename)
67b1994897Sopenharmony_ci    {
68b1994897Sopenharmony_ci        TmpFile tmpfile("aotdump.tmp");
69b1994897Sopenharmony_ci
70b1994897Sopenharmony_ci        auto res = os::exec::Exec(aotdump_path_.c_str(), "--show-code=disasm", "--output-file", tmpfile.GetFileName(),
71b1994897Sopenharmony_ci                                  aot_filename.c_str());
72b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "aotdump failed with error: " << res.Error().ToString();
73b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0) << "aotdump return error code: " << res.Value();
74b1994897Sopenharmony_ci    }
75b1994897Sopenharmony_ci
76b1994897Sopenharmony_ci    std::string paoc_path_;
77b1994897Sopenharmony_ci    std::string aotdump_path_;
78b1994897Sopenharmony_ciprotected:
79b1994897Sopenharmony_ci    Arch target_arch = Arch::AARCH64;
80b1994897Sopenharmony_ci};
81b1994897Sopenharmony_ci
82b1994897Sopenharmony_ci#ifdef PANDA_COMPILER_TARGET_AARCH64
83b1994897Sopenharmony_ciTEST_F(AotTest, PaocBootPandaFiles)
84b1994897Sopenharmony_ci{
85b1994897Sopenharmony_ci    // Test basic functionality only in host mode.
86b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
87b1994897Sopenharmony_ci        return;
88b1994897Sopenharmony_ci    }
89b1994897Sopenharmony_ci    TmpFile panda_fname("test.pf");
90b1994897Sopenharmony_ci    TmpFile aot_fname("./test.an");
91b1994897Sopenharmony_ci    static const std::string location = "/data/local/tmp";
92b1994897Sopenharmony_ci    static const std::string panda_file_path = location + "/" + panda_fname.GetFileName();
93b1994897Sopenharmony_ci
94b1994897Sopenharmony_ci    auto source = R"(
95b1994897Sopenharmony_ci        .function void dummy() {
96b1994897Sopenharmony_ci            return.void
97b1994897Sopenharmony_ci        }
98b1994897Sopenharmony_ci    )";
99b1994897Sopenharmony_ci
100b1994897Sopenharmony_ci    {
101b1994897Sopenharmony_ci        pandasm::Parser parser;
102b1994897Sopenharmony_ci        auto res = parser.Parse(source);
103b1994897Sopenharmony_ci        ASSERT_TRUE(res);
104b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
105b1994897Sopenharmony_ci    }
106b1994897Sopenharmony_ci
107b1994897Sopenharmony_ci    // Correct path to arkstdlib.abc
108b1994897Sopenharmony_ci    {
109b1994897Sopenharmony_ci        auto pandastdlib_path = GetPaocDirectory() + "/../pandastdlib/arkstdlib.abc";
110b1994897Sopenharmony_ci        auto res = os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-output",
111b1994897Sopenharmony_ci                                  aot_fname.GetFileName(), "--paoc-location", location.c_str(), "--paoc-arch",
112b1994897Sopenharmony_ci                                  GetArchAsArgString(), "--boot-panda-files", pandastdlib_path.c_str());
113b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
114b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0) << "Aot compiler failed with code " << res.Value();
115b1994897Sopenharmony_ci        RunAotdump(aot_fname.GetFileName());
116b1994897Sopenharmony_ci    }
117b1994897Sopenharmony_ci}
118b1994897Sopenharmony_ci
119b1994897Sopenharmony_ciTEST_F(AotTest, PaocLocation)
120b1994897Sopenharmony_ci{
121b1994897Sopenharmony_ci    // Test basic functionality only in host mode.
122b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
123b1994897Sopenharmony_ci        return;
124b1994897Sopenharmony_ci    }
125b1994897Sopenharmony_ci    TmpFile panda_fname("test.pf");
126b1994897Sopenharmony_ci    TmpFile aot_fname("./test.an");
127b1994897Sopenharmony_ci    static const std::string location = "/data/local/tmp";
128b1994897Sopenharmony_ci    static const std::string panda_file_path = location + "/" + panda_fname.GetFileName();
129b1994897Sopenharmony_ci
130b1994897Sopenharmony_ci    auto source = R"(
131b1994897Sopenharmony_ci        .function u32 add(u64 a0, u64 a1) {
132b1994897Sopenharmony_ci            add a0, a1
133b1994897Sopenharmony_ci            return
134b1994897Sopenharmony_ci        }
135b1994897Sopenharmony_ci    )";
136b1994897Sopenharmony_ci
137b1994897Sopenharmony_ci    {
138b1994897Sopenharmony_ci        pandasm::Parser parser;
139b1994897Sopenharmony_ci        auto res = parser.Parse(source);
140b1994897Sopenharmony_ci        ASSERT_TRUE(res);
141b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
142b1994897Sopenharmony_ci    }
143b1994897Sopenharmony_ci
144b1994897Sopenharmony_ci    {
145b1994897Sopenharmony_ci        auto pandastdlib_path = GetPaocDirectory() + "/../pandastdlib/arkstdlib.abc";
146b1994897Sopenharmony_ci        auto res = os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-output",
147b1994897Sopenharmony_ci                                  aot_fname.GetFileName(), "--paoc-location", location.c_str(), "--paoc-arch=x86_64",
148b1994897Sopenharmony_ci                                  "--gc-type=epsilon", "--paoc-use-cha=false");
149b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
150b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0) << "Aot compiler failed with code " << res.Value();
151b1994897Sopenharmony_ci    }
152b1994897Sopenharmony_ci
153b1994897Sopenharmony_ci    AotManager aot_manager;
154b1994897Sopenharmony_ci    {
155b1994897Sopenharmony_ci        auto res =
156b1994897Sopenharmony_ci            aot_manager.AddFile(aot_fname.GetFileName(), nullptr, static_cast<uint32_t>(mem::GCType::EPSILON_GC));
157b1994897Sopenharmony_ci        ASSERT_TRUE(res) << res.Error();
158b1994897Sopenharmony_ci    }
159b1994897Sopenharmony_ci
160b1994897Sopenharmony_ci    auto aot_file = aot_manager.GetFile(aot_fname.GetFileName());
161b1994897Sopenharmony_ci    ASSERT_TRUE(aot_file);
162b1994897Sopenharmony_ci    ASSERT_EQ(aot_file->GetFilesCount(), 1);
163b1994897Sopenharmony_ci    ASSERT_TRUE(aot_file->FindPandaFile(panda_file_path));
164b1994897Sopenharmony_ci}
165b1994897Sopenharmony_ci#endif  // PANDA_COMPILER_TARGET_AARCH64
166b1994897Sopenharmony_ci
167b1994897Sopenharmony_ciTEST_F(AotTest, BuildAndLoad)
168b1994897Sopenharmony_ci{
169b1994897Sopenharmony_ci    if (RUNTIME_ARCH == Arch::AARCH32) {
170b1994897Sopenharmony_ci        // TODO(msherstennikov): for some reason dlopen cannot open aot file in qemu-arm
171b1994897Sopenharmony_ci        return;
172b1994897Sopenharmony_ci    }
173b1994897Sopenharmony_ci    uint32_t tid = os::thread::GetCurrentThreadId();
174b1994897Sopenharmony_ci    std::string tmpfile = helpers::string::Format("/tmp/tmpfile_%04x.pn", tid);
175b1994897Sopenharmony_ci    static constexpr const char *tmpfile_pf = "test.pf";
176b1994897Sopenharmony_ci    static constexpr const char *cmdline = "cmdline";
177b1994897Sopenharmony_ci    static constexpr uint32_t method1_id = 42;
178b1994897Sopenharmony_ci    static constexpr uint32_t method2_id = 43;
179b1994897Sopenharmony_ci    const std::string class_name("Foo");
180b1994897Sopenharmony_ci    std::string method_name(class_name + "::method");
181b1994897Sopenharmony_ci    std::array<uint8_t, 4> x86_add = {
182b1994897Sopenharmony_ci        0x8d, 0x04, 0x37,  // lea    eax,[rdi+rdi*1]
183b1994897Sopenharmony_ci        0xc3               // ret
184b1994897Sopenharmony_ci    };
185b1994897Sopenharmony_ci
186b1994897Sopenharmony_ci    AotBuilder aot_builder;
187b1994897Sopenharmony_ci    aot_builder.SetArch(RUNTIME_ARCH);
188b1994897Sopenharmony_ci    aot_builder.SetGcType(2);
189b1994897Sopenharmony_ci    RuntimeInterfaceMock iruntime;
190b1994897Sopenharmony_ci    aot_builder.SetRuntime(&iruntime);
191b1994897Sopenharmony_ci
192b1994897Sopenharmony_ci    aot_builder.StartFile(tmpfile_pf, 0x12345678);
193b1994897Sopenharmony_ci
194b1994897Sopenharmony_ci    auto thread = MTManagedThread::GetCurrent();
195b1994897Sopenharmony_ci    if (thread != nullptr) {
196b1994897Sopenharmony_ci        thread->ManagedCodeBegin();
197b1994897Sopenharmony_ci    }
198b1994897Sopenharmony_ci    auto runtime = Runtime::GetCurrent();
199b1994897Sopenharmony_ci    auto etx = runtime->GetClassLinker()->GetExtension(runtime->GetLanguageContext(runtime->GetRuntimeType()));
200b1994897Sopenharmony_ci    auto klass = etx->CreateClass(reinterpret_cast<const uint8_t *>(class_name.data()), 0, 0,
201b1994897Sopenharmony_ci                                  AlignUp(sizeof(Class), OBJECT_POINTER_SIZE));
202b1994897Sopenharmony_ci    if (thread != nullptr) {
203b1994897Sopenharmony_ci        thread->ManagedCodeEnd();
204b1994897Sopenharmony_ci    }
205b1994897Sopenharmony_ci
206b1994897Sopenharmony_ci    klass->SetFileId(panda_file::File::EntityId(13));
207b1994897Sopenharmony_ci    aot_builder.StartClass(*klass);
208b1994897Sopenharmony_ci
209b1994897Sopenharmony_ci    Method method1(klass, nullptr, File::EntityId(method1_id), File::EntityId(), 0, 1, nullptr);
210b1994897Sopenharmony_ci    {
211b1994897Sopenharmony_ci        CodeInfoBuilder code_builder(RUNTIME_ARCH, GetAllocator());
212b1994897Sopenharmony_ci        ArenaVector<uint8_t> data(GetAllocator()->Adapter());
213b1994897Sopenharmony_ci        code_builder.Encode(&data);
214b1994897Sopenharmony_ci        CompiledMethod compiled_method1(RUNTIME_ARCH, &method1);
215b1994897Sopenharmony_ci        compiled_method1.SetCode(Span(reinterpret_cast<const uint8_t *>(method_name.data()), method_name.size() + 1));
216b1994897Sopenharmony_ci        compiled_method1.SetCodeInfo(Span(data).ToConst());
217b1994897Sopenharmony_ci        aot_builder.AddMethod(compiled_method1, 0);
218b1994897Sopenharmony_ci    }
219b1994897Sopenharmony_ci
220b1994897Sopenharmony_ci    Method method2(klass, nullptr, File::EntityId(method2_id), File::EntityId(), 0, 1, nullptr);
221b1994897Sopenharmony_ci    {
222b1994897Sopenharmony_ci        CodeInfoBuilder code_builder(RUNTIME_ARCH, GetAllocator());
223b1994897Sopenharmony_ci        ArenaVector<uint8_t> data(GetAllocator()->Adapter());
224b1994897Sopenharmony_ci        code_builder.Encode(&data);
225b1994897Sopenharmony_ci        CompiledMethod compiled_method2(RUNTIME_ARCH, &method2);
226b1994897Sopenharmony_ci        compiled_method2.SetCode(Span(reinterpret_cast<const uint8_t *>(x86_add.data()), x86_add.size()));
227b1994897Sopenharmony_ci        compiled_method2.SetCodeInfo(Span(data).ToConst());
228b1994897Sopenharmony_ci        aot_builder.AddMethod(compiled_method2, 1);
229b1994897Sopenharmony_ci    }
230b1994897Sopenharmony_ci
231b1994897Sopenharmony_ci    aot_builder.EndClass();
232b1994897Sopenharmony_ci    uint32_t hash = GetHash32String(reinterpret_cast<const uint8_t *>(class_name.data()));
233b1994897Sopenharmony_ci    aot_builder.InsertEntityPairHeader(hash, 13);
234b1994897Sopenharmony_ci    aot_builder.InsertClassHashTableSize(1);
235b1994897Sopenharmony_ci    aot_builder.EndFile();
236b1994897Sopenharmony_ci
237b1994897Sopenharmony_ci    aot_builder.Write(cmdline, tmpfile.c_str());
238b1994897Sopenharmony_ci
239b1994897Sopenharmony_ci    AotManager aot_manager;
240b1994897Sopenharmony_ci    auto res = aot_manager.AddFile(tmpfile.c_str(), nullptr, static_cast<uint32_t>(mem::GCType::STW_GC));
241b1994897Sopenharmony_ci    ASSERT_TRUE(res) << res.Error();
242b1994897Sopenharmony_ci
243b1994897Sopenharmony_ci    auto aot_file = aot_manager.GetFile(tmpfile.c_str());
244b1994897Sopenharmony_ci    ASSERT_TRUE(aot_file);
245b1994897Sopenharmony_ci    ASSERT_TRUE(strcmp(cmdline, aot_file->GetCommandLine()) == 0U);
246b1994897Sopenharmony_ci    ASSERT_TRUE(strcmp(tmpfile.c_str(), aot_file->GetFileName()) == 0U);
247b1994897Sopenharmony_ci    ASSERT_EQ(aot_file->GetFilesCount(), 1U);
248b1994897Sopenharmony_ci
249b1994897Sopenharmony_ci    auto pfile = aot_manager.FindPandaFile(tmpfile_pf);
250b1994897Sopenharmony_ci    ASSERT_NE(pfile, nullptr);
251b1994897Sopenharmony_ci    auto cls = pfile->GetClass(13);
252b1994897Sopenharmony_ci    ASSERT_TRUE(cls.IsValid());
253b1994897Sopenharmony_ci
254b1994897Sopenharmony_ci    {
255b1994897Sopenharmony_ci        auto code = cls.FindMethodCodeEntry(0);
256b1994897Sopenharmony_ci        ASSERT_FALSE(code == nullptr);
257b1994897Sopenharmony_ci        ASSERT_EQ(method_name, reinterpret_cast<const char *>(code));
258b1994897Sopenharmony_ci    }
259b1994897Sopenharmony_ci
260b1994897Sopenharmony_ci    {
261b1994897Sopenharmony_ci        auto code = cls.FindMethodCodeEntry(1);
262b1994897Sopenharmony_ci        ASSERT_FALSE(code == nullptr);
263b1994897Sopenharmony_ci        ASSERT_EQ(std::memcmp(x86_add.data(), code, x86_add.size()), 0);
264b1994897Sopenharmony_ci#ifdef PANDA_TARGET_AMD64
265b1994897Sopenharmony_ci        auto func_add = (int (*)(int, int))code;
266b1994897Sopenharmony_ci        ASSERT_EQ(func_add(2, 3), 5);
267b1994897Sopenharmony_ci#endif
268b1994897Sopenharmony_ci    }
269b1994897Sopenharmony_ci}
270b1994897Sopenharmony_ci
271b1994897Sopenharmony_ciTEST_F(AotTest, PaocSpecifyMethods)
272b1994897Sopenharmony_ci{
273b1994897Sopenharmony_ci#ifndef PANDA_EVENTS_ENABLED
274b1994897Sopenharmony_ci    GTEST_SKIP();
275b1994897Sopenharmony_ci#endif
276b1994897Sopenharmony_ci
277b1994897Sopenharmony_ci    // Test basic functionality only in host mode.
278b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
279b1994897Sopenharmony_ci        return;
280b1994897Sopenharmony_ci    }
281b1994897Sopenharmony_ci    TmpFile panda_fname("test.pf");
282b1994897Sopenharmony_ci    TmpFile paoc_output_name("events-out.csv");
283b1994897Sopenharmony_ci
284b1994897Sopenharmony_ci    static const std::string location = "/data/local/tmp";
285b1994897Sopenharmony_ci    static const std::string panda_file_path = location + "/" + panda_fname.GetFileName();
286b1994897Sopenharmony_ci
287b1994897Sopenharmony_ci    auto source = R"(
288b1994897Sopenharmony_ci        .record A {}
289b1994897Sopenharmony_ci        .record B {}
290b1994897Sopenharmony_ci
291b1994897Sopenharmony_ci        .function i32 A.f1() {
292b1994897Sopenharmony_ci            ldai 10
293b1994897Sopenharmony_ci            return
294b1994897Sopenharmony_ci        }
295b1994897Sopenharmony_ci
296b1994897Sopenharmony_ci        .function i32 B.f1() {
297b1994897Sopenharmony_ci            ldai 20
298b1994897Sopenharmony_ci            return
299b1994897Sopenharmony_ci        }
300b1994897Sopenharmony_ci
301b1994897Sopenharmony_ci        .function i32 A.f2() {
302b1994897Sopenharmony_ci            ldai 10
303b1994897Sopenharmony_ci            return
304b1994897Sopenharmony_ci        }
305b1994897Sopenharmony_ci
306b1994897Sopenharmony_ci        .function i32 B.f2() {
307b1994897Sopenharmony_ci            ldai 20
308b1994897Sopenharmony_ci            return
309b1994897Sopenharmony_ci        }
310b1994897Sopenharmony_ci
311b1994897Sopenharmony_ci        .function i32 main() {
312b1994897Sopenharmony_ci            ldai 0
313b1994897Sopenharmony_ci            return
314b1994897Sopenharmony_ci        }
315b1994897Sopenharmony_ci    )";
316b1994897Sopenharmony_ci
317b1994897Sopenharmony_ci    {
318b1994897Sopenharmony_ci        pandasm::Parser parser;
319b1994897Sopenharmony_ci        auto res = parser.Parse(source);
320b1994897Sopenharmony_ci        ASSERT_TRUE(res);
321b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
322b1994897Sopenharmony_ci    }
323b1994897Sopenharmony_ci
324b1994897Sopenharmony_ci    {
325b1994897Sopenharmony_ci        // paoc will try compiling all the methods from the panda-file that matches `--compiler-regex`
326b1994897Sopenharmony_ci        auto res =
327b1994897Sopenharmony_ci            os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname.GetFileName(),
328b1994897Sopenharmony_ci                           "--compiler-regex", "B::f1",
329b1994897Sopenharmony_ci                           "--paoc-mode=jit", "--events-output=csv",
330b1994897Sopenharmony_ci                           "--events-file", paoc_output_name.GetFileName());
331b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
332b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0);
333b1994897Sopenharmony_ci
334b1994897Sopenharmony_ci        std::ifstream infile(paoc_output_name.GetFileName());
335b1994897Sopenharmony_ci        std::regex rgx("Compilation,B::f1.*,COMPILED");
336b1994897Sopenharmony_ci        for (std::string line; std::getline(infile, line);) {
337b1994897Sopenharmony_ci            if (line.rfind("Compilation", 0) == 0) {
338b1994897Sopenharmony_ci                ASSERT_TRUE(std::regex_match(line, rgx));
339b1994897Sopenharmony_ci            }
340b1994897Sopenharmony_ci        }
341b1994897Sopenharmony_ci    }
342b1994897Sopenharmony_ci}
343b1994897Sopenharmony_ci
344b1994897Sopenharmony_ciTEST_F(AotTest, PaocMultipleFiles)
345b1994897Sopenharmony_ci{
346b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
347b1994897Sopenharmony_ci        GTEST_SKIP();
348b1994897Sopenharmony_ci    }
349b1994897Sopenharmony_ci
350b1994897Sopenharmony_ci    TmpFile aot_fname("./test.an");
351b1994897Sopenharmony_ci    TmpFile panda_fname1("test1.pf");
352b1994897Sopenharmony_ci    TmpFile panda_fname2("test2.pf");
353b1994897Sopenharmony_ci
354b1994897Sopenharmony_ci    {
355b1994897Sopenharmony_ci        auto source = R"(
356b1994897Sopenharmony_ci            .function f64 main() {
357b1994897Sopenharmony_ci                fldai.64 3.1415926
358b1994897Sopenharmony_ci                return.64
359b1994897Sopenharmony_ci            }
360b1994897Sopenharmony_ci        )";
361b1994897Sopenharmony_ci
362b1994897Sopenharmony_ci        pandasm::Parser parser;
363b1994897Sopenharmony_ci        auto res = parser.Parse(source);
364b1994897Sopenharmony_ci        ASSERT_TRUE(res);
365b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname1.GetFileName(), res.Value()));
366b1994897Sopenharmony_ci    }
367b1994897Sopenharmony_ci
368b1994897Sopenharmony_ci    {
369b1994897Sopenharmony_ci        auto source = R"(
370b1994897Sopenharmony_ci            .record MyMath {
371b1994897Sopenharmony_ci            }
372b1994897Sopenharmony_ci
373b1994897Sopenharmony_ci            .function f64 MyMath.getPi() <static> {
374b1994897Sopenharmony_ci                fldai.64 3.1415926
375b1994897Sopenharmony_ci                return.64
376b1994897Sopenharmony_ci            }
377b1994897Sopenharmony_ci        )";
378b1994897Sopenharmony_ci
379b1994897Sopenharmony_ci        pandasm::Parser parser;
380b1994897Sopenharmony_ci        auto res = parser.Parse(source);
381b1994897Sopenharmony_ci        ASSERT_TRUE(res);
382b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname2.GetFileName(), res.Value()));
383b1994897Sopenharmony_ci    }
384b1994897Sopenharmony_ci
385b1994897Sopenharmony_ci    {
386b1994897Sopenharmony_ci        std::stringstream panda_files;
387b1994897Sopenharmony_ci        panda_files << panda_fname1.GetFileName() << ',' << panda_fname2.GetFileName();
388b1994897Sopenharmony_ci        auto res = os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_files.str().c_str(), "--paoc-output",
389b1994897Sopenharmony_ci                                  aot_fname.GetFileName(), "--gc-type=epsilon", "--paoc-use-cha=false");
390b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
391b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0);
392b1994897Sopenharmony_ci    }
393b1994897Sopenharmony_ci
394b1994897Sopenharmony_ci    {
395b1994897Sopenharmony_ci        AotManager aot_manager;
396b1994897Sopenharmony_ci        auto res =
397b1994897Sopenharmony_ci            aot_manager.AddFile(aot_fname.GetFileName(), nullptr, static_cast<uint32_t>(mem::GCType::EPSILON_GC));
398b1994897Sopenharmony_ci        ASSERT_TRUE(res) << res.Error();
399b1994897Sopenharmony_ci
400b1994897Sopenharmony_ci        auto aot_file = aot_manager.GetFile(aot_fname.GetFileName());
401b1994897Sopenharmony_ci        ASSERT_TRUE(aot_file);
402b1994897Sopenharmony_ci        ASSERT_EQ(aot_file->GetFilesCount(), 2U);
403b1994897Sopenharmony_ci    }
404b1994897Sopenharmony_ci    RunAotdump(aot_fname.GetFileName());
405b1994897Sopenharmony_ci}
406b1994897Sopenharmony_ci
407b1994897Sopenharmony_ciTEST_F(AotTest, PaocGcType)
408b1994897Sopenharmony_ci{
409b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
410b1994897Sopenharmony_ci        GTEST_SKIP();
411b1994897Sopenharmony_ci    }
412b1994897Sopenharmony_ci
413b1994897Sopenharmony_ci    TmpFile aot_fname("./test.pn");
414b1994897Sopenharmony_ci    TmpFile panda_fname("test.pf");
415b1994897Sopenharmony_ci
416b1994897Sopenharmony_ci    {
417b1994897Sopenharmony_ci        auto source = R"(
418b1994897Sopenharmony_ci            .function f64 main() {
419b1994897Sopenharmony_ci                fldai.64 3.1415926
420b1994897Sopenharmony_ci                return.64
421b1994897Sopenharmony_ci            }
422b1994897Sopenharmony_ci        )";
423b1994897Sopenharmony_ci
424b1994897Sopenharmony_ci        pandasm::Parser parser;
425b1994897Sopenharmony_ci        auto res = parser.Parse(source);
426b1994897Sopenharmony_ci        ASSERT_TRUE(res);
427b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
428b1994897Sopenharmony_ci    }
429b1994897Sopenharmony_ci
430b1994897Sopenharmony_ci    {
431b1994897Sopenharmony_ci        auto res = os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-output",
432b1994897Sopenharmony_ci                                  aot_fname.GetFileName(), "--gc-type=epsilon", "--paoc-use-cha=false");
433b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
434b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0);
435b1994897Sopenharmony_ci    }
436b1994897Sopenharmony_ci
437b1994897Sopenharmony_ci    {
438b1994897Sopenharmony_ci        // Wrong gc-type
439b1994897Sopenharmony_ci        AotManager aot_manager;
440b1994897Sopenharmony_ci        auto res = aot_manager.AddFile(aot_fname.GetFileName(), nullptr, static_cast<uint32_t>(mem::GCType::STW_GC));
441b1994897Sopenharmony_ci        ASSERT_FALSE(res) << res.Error();
442b1994897Sopenharmony_ci        std::string expected_string = "Wrong AotHeader gc-type: epsilon vs stw";
443b1994897Sopenharmony_ci        ASSERT_NE(res.Error().find(expected_string), std::string::npos);
444b1994897Sopenharmony_ci    }
445b1994897Sopenharmony_ci
446b1994897Sopenharmony_ci    {
447b1994897Sopenharmony_ci        AotManager aot_manager;
448b1994897Sopenharmony_ci        auto res =
449b1994897Sopenharmony_ci            aot_manager.AddFile(aot_fname.GetFileName(), nullptr, static_cast<uint32_t>(mem::GCType::EPSILON_GC));
450b1994897Sopenharmony_ci        ASSERT_TRUE(res) << res.Error();
451b1994897Sopenharmony_ci
452b1994897Sopenharmony_ci        auto aot_file = aot_manager.GetFile(aot_fname.GetFileName());
453b1994897Sopenharmony_ci        ASSERT_TRUE(aot_file);
454b1994897Sopenharmony_ci        ASSERT_EQ(aot_file->GetFilesCount(), 1U);
455b1994897Sopenharmony_ci    }
456b1994897Sopenharmony_ci    RunAotdump(aot_fname.GetFileName());
457b1994897Sopenharmony_ci}
458b1994897Sopenharmony_ci
459b1994897Sopenharmony_ciTEST_F(AotTest, FileManagerLoadAbc)
460b1994897Sopenharmony_ci{
461b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
462b1994897Sopenharmony_ci        GTEST_SKIP();
463b1994897Sopenharmony_ci    }
464b1994897Sopenharmony_ci
465b1994897Sopenharmony_ci    TmpFile aot_fname("./test.an");
466b1994897Sopenharmony_ci    TmpFile panda_fname("./test.pf");
467b1994897Sopenharmony_ci
468b1994897Sopenharmony_ci    {
469b1994897Sopenharmony_ci        auto source = R"(
470b1994897Sopenharmony_ci            .function f64 main() {
471b1994897Sopenharmony_ci                fldai.64 3.1415926
472b1994897Sopenharmony_ci                return.64
473b1994897Sopenharmony_ci            }
474b1994897Sopenharmony_ci        )";
475b1994897Sopenharmony_ci
476b1994897Sopenharmony_ci        pandasm::Parser parser;
477b1994897Sopenharmony_ci        auto res = parser.Parse(source);
478b1994897Sopenharmony_ci        ASSERT_TRUE(res);
479b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
480b1994897Sopenharmony_ci    }
481b1994897Sopenharmony_ci
482b1994897Sopenharmony_ci    {
483b1994897Sopenharmony_ci        auto runtime = Runtime::GetCurrent();
484b1994897Sopenharmony_ci        auto gc_type_id = static_cast<uint32_t>(
485b1994897Sopenharmony_ci            Runtime::GetGCType(runtime->GetOptions(), plugins::RuntimeTypeToLang(runtime->GetRuntimeType())));
486b1994897Sopenharmony_ci        auto gc_type_name = "--gc-type=epsilon";
487b1994897Sopenharmony_ci        if (gc_type_id == 2) {
488b1994897Sopenharmony_ci            gc_type_name = "--gc-type=stw";
489b1994897Sopenharmony_ci        } else if (gc_type_id == 4) {
490b1994897Sopenharmony_ci            gc_type_name = "--gc-type=gen-gc";
491b1994897Sopenharmony_ci        } else {
492b1994897Sopenharmony_ci            ASSERT_EQ(gc_type_id, 1) << "Invalid GC type\n";
493b1994897Sopenharmony_ci        }
494b1994897Sopenharmony_ci        auto res = os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-output",
495b1994897Sopenharmony_ci                                  aot_fname.GetFileName(), gc_type_name, "--paoc-use-cha=false");
496b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
497b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0);
498b1994897Sopenharmony_ci    }
499b1994897Sopenharmony_ci
500b1994897Sopenharmony_ci    {
501b1994897Sopenharmony_ci        auto res = FileManager::LoadAbcFile(panda_fname.GetFileName(), panda_file::File::READ_ONLY);
502b1994897Sopenharmony_ci        ASSERT_TRUE(res);
503b1994897Sopenharmony_ci        auto aot_manager = Runtime::GetCurrent()->GetClassLinker()->GetAotManager();
504b1994897Sopenharmony_ci        auto aot_file = aot_manager->GetFile(aot_fname.GetFileName());
505b1994897Sopenharmony_ci        ASSERT_TRUE(aot_file);
506b1994897Sopenharmony_ci        ASSERT_EQ(aot_file->GetFilesCount(), 1);
507b1994897Sopenharmony_ci    }
508b1994897Sopenharmony_ci    RunAotdump(aot_fname.GetFileName());
509b1994897Sopenharmony_ci}
510b1994897Sopenharmony_ci
511b1994897Sopenharmony_ciTEST_F(AotTest, FileManagerLoadAn)
512b1994897Sopenharmony_ci{
513b1994897Sopenharmony_ci    if (RUNTIME_ARCH == Arch::AARCH32) {
514b1994897Sopenharmony_ci        // TODO(msherstennikov): for some reason dlopen cannot open aot file in qemu-arm
515b1994897Sopenharmony_ci        return;
516b1994897Sopenharmony_ci    }
517b1994897Sopenharmony_ci    uint32_t tid = os::thread::GetCurrentThreadId();
518b1994897Sopenharmony_ci    std::string tmpfile = helpers::string::Format("test.an", tid);
519b1994897Sopenharmony_ci    static constexpr const char *tmpfile_pf = "test.pf";
520b1994897Sopenharmony_ci    static constexpr const char *cmdline = "cmdline";
521b1994897Sopenharmony_ci    static constexpr uint32_t method1_id = 42;
522b1994897Sopenharmony_ci    static constexpr uint32_t method2_id = 43;
523b1994897Sopenharmony_ci    const std::string class_name("Foo");
524b1994897Sopenharmony_ci    std::string method_name(class_name + "::method");
525b1994897Sopenharmony_ci    std::array<uint8_t, 4> x86_add = {
526b1994897Sopenharmony_ci        0x8d, 0x04, 0x37,  // lea    eax,[rdi+rdi*1]
527b1994897Sopenharmony_ci        0xc3               // ret
528b1994897Sopenharmony_ci    };
529b1994897Sopenharmony_ci
530b1994897Sopenharmony_ci    AotBuilder aot_builder;
531b1994897Sopenharmony_ci    aot_builder.SetArch(RUNTIME_ARCH);
532b1994897Sopenharmony_ci    RuntimeInterfaceMock iruntime;
533b1994897Sopenharmony_ci    aot_builder.SetRuntime(&iruntime);
534b1994897Sopenharmony_ci    auto runtime = Runtime::GetCurrent();
535b1994897Sopenharmony_ci    auto gc_type = Runtime::GetGCType(runtime->GetOptions(), plugins::RuntimeTypeToLang(runtime->GetRuntimeType()));
536b1994897Sopenharmony_ci    aot_builder.SetGcType(static_cast<uint32_t>(gc_type));
537b1994897Sopenharmony_ci
538b1994897Sopenharmony_ci    aot_builder.StartFile(tmpfile_pf, 0x12345678);
539b1994897Sopenharmony_ci
540b1994897Sopenharmony_ci    auto thread = MTManagedThread::GetCurrent();
541b1994897Sopenharmony_ci    if (thread != nullptr) {
542b1994897Sopenharmony_ci        thread->ManagedCodeBegin();
543b1994897Sopenharmony_ci    }
544b1994897Sopenharmony_ci    auto etx = runtime->GetClassLinker()->GetExtension(runtime->GetLanguageContext(runtime->GetRuntimeType()));
545b1994897Sopenharmony_ci    auto klass = etx->CreateClass(reinterpret_cast<const uint8_t *>(class_name.data()), 0, 0,
546b1994897Sopenharmony_ci                                  AlignUp(sizeof(Class), OBJECT_POINTER_SIZE));
547b1994897Sopenharmony_ci    if (thread != nullptr) {
548b1994897Sopenharmony_ci        thread->ManagedCodeEnd();
549b1994897Sopenharmony_ci    }
550b1994897Sopenharmony_ci
551b1994897Sopenharmony_ci    klass->SetFileId(panda_file::File::EntityId(13));
552b1994897Sopenharmony_ci    aot_builder.StartClass(*klass);
553b1994897Sopenharmony_ci
554b1994897Sopenharmony_ci    Method method1(klass, nullptr, File::EntityId(method1_id), File::EntityId(), 0, 1, nullptr);
555b1994897Sopenharmony_ci    {
556b1994897Sopenharmony_ci        CodeInfoBuilder code_builder(RUNTIME_ARCH, GetAllocator());
557b1994897Sopenharmony_ci        ArenaVector<uint8_t> data(GetAllocator()->Adapter());
558b1994897Sopenharmony_ci        code_builder.Encode(&data);
559b1994897Sopenharmony_ci        CompiledMethod compiled_method1(RUNTIME_ARCH, &method1);
560b1994897Sopenharmony_ci        compiled_method1.SetCode(Span(reinterpret_cast<const uint8_t *>(method_name.data()), method_name.size() + 1));
561b1994897Sopenharmony_ci        compiled_method1.SetCodeInfo(Span(data).ToConst());
562b1994897Sopenharmony_ci        aot_builder.AddMethod(compiled_method1, 0);
563b1994897Sopenharmony_ci    }
564b1994897Sopenharmony_ci
565b1994897Sopenharmony_ci    Method method2(klass, nullptr, File::EntityId(method2_id), File::EntityId(), 0, 1, nullptr);
566b1994897Sopenharmony_ci    {
567b1994897Sopenharmony_ci        CodeInfoBuilder code_builder(RUNTIME_ARCH, GetAllocator());
568b1994897Sopenharmony_ci        ArenaVector<uint8_t> data(GetAllocator()->Adapter());
569b1994897Sopenharmony_ci        code_builder.Encode(&data);
570b1994897Sopenharmony_ci        CompiledMethod compiled_method2(RUNTIME_ARCH, &method2);
571b1994897Sopenharmony_ci        compiled_method2.SetCode(Span(reinterpret_cast<const uint8_t *>(x86_add.data()), x86_add.size()));
572b1994897Sopenharmony_ci        compiled_method2.SetCodeInfo(Span(data).ToConst());
573b1994897Sopenharmony_ci        aot_builder.AddMethod(compiled_method2, 1);
574b1994897Sopenharmony_ci    }
575b1994897Sopenharmony_ci
576b1994897Sopenharmony_ci    aot_builder.EndClass();
577b1994897Sopenharmony_ci    uint32_t hash = GetHash32String(reinterpret_cast<const uint8_t *>(class_name.data()));
578b1994897Sopenharmony_ci    aot_builder.InsertEntityPairHeader(hash, 13);
579b1994897Sopenharmony_ci    aot_builder.InsertClassHashTableSize(1);
580b1994897Sopenharmony_ci    aot_builder.EndFile();
581b1994897Sopenharmony_ci
582b1994897Sopenharmony_ci    aot_builder.Write(cmdline, tmpfile.c_str());
583b1994897Sopenharmony_ci    {
584b1994897Sopenharmony_ci        auto res = FileManager::LoadAnFile(tmpfile.c_str());
585b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "Fail to load an file";
586b1994897Sopenharmony_ci    }
587b1994897Sopenharmony_ci
588b1994897Sopenharmony_ci    auto aot_manager = Runtime::GetCurrent()->GetClassLinker()->GetAotManager();
589b1994897Sopenharmony_ci    auto aot_file = aot_manager->GetFile(tmpfile.c_str());
590b1994897Sopenharmony_ci    ASSERT_TRUE(aot_file);
591b1994897Sopenharmony_ci    ASSERT_TRUE(strcmp(cmdline, aot_file->GetCommandLine()) == 0U);
592b1994897Sopenharmony_ci    ASSERT_TRUE(strcmp(tmpfile.c_str(), aot_file->GetFileName()) == 0U);
593b1994897Sopenharmony_ci    ASSERT_EQ(aot_file->GetFilesCount(), 1U);
594b1994897Sopenharmony_ci
595b1994897Sopenharmony_ci    auto pfile = aot_manager->FindPandaFile(tmpfile_pf);
596b1994897Sopenharmony_ci    ASSERT_NE(pfile, nullptr);
597b1994897Sopenharmony_ci    auto cls = pfile->GetClass(13);
598b1994897Sopenharmony_ci    ASSERT_TRUE(cls.IsValid());
599b1994897Sopenharmony_ci
600b1994897Sopenharmony_ci    {
601b1994897Sopenharmony_ci        auto code = cls.FindMethodCodeEntry(0);
602b1994897Sopenharmony_ci        ASSERT_FALSE(code == nullptr);
603b1994897Sopenharmony_ci        ASSERT_EQ(method_name, reinterpret_cast<const char *>(code));
604b1994897Sopenharmony_ci    }
605b1994897Sopenharmony_ci
606b1994897Sopenharmony_ci    {
607b1994897Sopenharmony_ci        auto code = cls.FindMethodCodeEntry(1);
608b1994897Sopenharmony_ci        ASSERT_FALSE(code == nullptr);
609b1994897Sopenharmony_ci        ASSERT_EQ(std::memcmp(x86_add.data(), code, x86_add.size()), 0);
610b1994897Sopenharmony_ci#ifdef PANDA_TARGET_AMD64
611b1994897Sopenharmony_ci        auto func_add = (int (*)(int, int))code;
612b1994897Sopenharmony_ci        ASSERT_EQ(func_add(2, 3), 5);
613b1994897Sopenharmony_ci#endif
614b1994897Sopenharmony_ci    }
615b1994897Sopenharmony_ci}
616b1994897Sopenharmony_ci
617b1994897Sopenharmony_ciTEST_F(AotTest, PaocClusters)
618b1994897Sopenharmony_ci{
619b1994897Sopenharmony_ci    // Test basic functionality only in host mode.
620b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
621b1994897Sopenharmony_ci        return;
622b1994897Sopenharmony_ci    }
623b1994897Sopenharmony_ci
624b1994897Sopenharmony_ci    TmpFile paoc_clusters("clusters.json");
625b1994897Sopenharmony_ci    std::ofstream(paoc_clusters.GetFileName()) <<
626b1994897Sopenharmony_ci        R"(
627b1994897Sopenharmony_ci    {
628b1994897Sopenharmony_ci        "clusters_map" :
629b1994897Sopenharmony_ci        {
630b1994897Sopenharmony_ci            "A::count" : ["unroll_enable"],
631b1994897Sopenharmony_ci            "B::count2" : ["unroll_disable"],
632b1994897Sopenharmony_ci            "_GLOBAL::main" : ["inline_disable", 1]
633b1994897Sopenharmony_ci        },
634b1994897Sopenharmony_ci
635b1994897Sopenharmony_ci        "compiler_options" :
636b1994897Sopenharmony_ci        {
637b1994897Sopenharmony_ci            "unroll_disable" :
638b1994897Sopenharmony_ci            {
639b1994897Sopenharmony_ci                "compiler-loop-unroll" : "false"
640b1994897Sopenharmony_ci            },
641b1994897Sopenharmony_ci
642b1994897Sopenharmony_ci            "unroll_enable" :
643b1994897Sopenharmony_ci            {
644b1994897Sopenharmony_ci                "compiler-loop-unroll" : "true",
645b1994897Sopenharmony_ci                "compiler-loop-unroll-factor" : 42,
646b1994897Sopenharmony_ci                "compiler-loop-unroll-inst-limit" : 850
647b1994897Sopenharmony_ci            },
648b1994897Sopenharmony_ci
649b1994897Sopenharmony_ci            "inline_disable" :
650b1994897Sopenharmony_ci            {
651b1994897Sopenharmony_ci                "compiler-inlining" : "false"
652b1994897Sopenharmony_ci            }
653b1994897Sopenharmony_ci        }
654b1994897Sopenharmony_ci    }
655b1994897Sopenharmony_ci    )";
656b1994897Sopenharmony_ci
657b1994897Sopenharmony_ci    TmpFile panda_fname("test.pf");
658b1994897Sopenharmony_ci    auto source = R"(
659b1994897Sopenharmony_ci        .record A {}
660b1994897Sopenharmony_ci        .record B {}
661b1994897Sopenharmony_ci
662b1994897Sopenharmony_ci        .function i32 A.count() <static> {
663b1994897Sopenharmony_ci            movi v1, 5
664b1994897Sopenharmony_ci            ldai 0
665b1994897Sopenharmony_ci        main_loop:
666b1994897Sopenharmony_ci            jeq v1, main_ret
667b1994897Sopenharmony_ci            addi 1
668b1994897Sopenharmony_ci            jmp main_loop
669b1994897Sopenharmony_ci        main_ret:
670b1994897Sopenharmony_ci            return
671b1994897Sopenharmony_ci        }
672b1994897Sopenharmony_ci
673b1994897Sopenharmony_ci        .function i32 B.count() <static> {
674b1994897Sopenharmony_ci            movi v1, 5
675b1994897Sopenharmony_ci            ldai 0
676b1994897Sopenharmony_ci        main_loop:
677b1994897Sopenharmony_ci            jeq v1, main_ret
678b1994897Sopenharmony_ci            addi 1
679b1994897Sopenharmony_ci            jmp main_loop
680b1994897Sopenharmony_ci        main_ret:
681b1994897Sopenharmony_ci            return
682b1994897Sopenharmony_ci        }
683b1994897Sopenharmony_ci
684b1994897Sopenharmony_ci        .function i32 B.count2() <static> {
685b1994897Sopenharmony_ci            movi v1, 5
686b1994897Sopenharmony_ci            ldai 0
687b1994897Sopenharmony_ci        main_loop:
688b1994897Sopenharmony_ci            jeq v1, main_ret
689b1994897Sopenharmony_ci            addi 1
690b1994897Sopenharmony_ci            jmp main_loop
691b1994897Sopenharmony_ci        main_ret:
692b1994897Sopenharmony_ci            return
693b1994897Sopenharmony_ci        }
694b1994897Sopenharmony_ci
695b1994897Sopenharmony_ci        .function i32 main() {
696b1994897Sopenharmony_ci            call.short A.count
697b1994897Sopenharmony_ci            sta v0
698b1994897Sopenharmony_ci            call.short B.count
699b1994897Sopenharmony_ci            add2 v0
700b1994897Sopenharmony_ci            call.short B.count2
701b1994897Sopenharmony_ci            add2 v0
702b1994897Sopenharmony_ci            return
703b1994897Sopenharmony_ci        }
704b1994897Sopenharmony_ci    )";
705b1994897Sopenharmony_ci
706b1994897Sopenharmony_ci    {
707b1994897Sopenharmony_ci        pandasm::Parser parser;
708b1994897Sopenharmony_ci        auto res = parser.Parse(source);
709b1994897Sopenharmony_ci        ASSERT_TRUE(res);
710b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
711b1994897Sopenharmony_ci    }
712b1994897Sopenharmony_ci
713b1994897Sopenharmony_ci    {
714b1994897Sopenharmony_ci        TmpFile compiler_events("events.csv");
715b1994897Sopenharmony_ci        auto res =
716b1994897Sopenharmony_ci            os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-clusters",
717b1994897Sopenharmony_ci                           paoc_clusters.GetFileName(), "--compiler-loop-unroll-factor=7",
718b1994897Sopenharmony_ci                           "--compiler-enable-events=true", "--compiler-events-path", compiler_events.GetFileName());
719b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
720b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0);
721b1994897Sopenharmony_ci
722b1994897Sopenharmony_ci        bool first_found = false;
723b1994897Sopenharmony_ci        bool second_found = false;
724b1994897Sopenharmony_ci        std::ifstream events_file(compiler_events.GetFileName());
725b1994897Sopenharmony_ci
726b1994897Sopenharmony_ci        std::regex rgx_unroll_applied_cluster("A::count,loop-unroll,.*,unroll_factor:42,.*");
727b1994897Sopenharmony_ci        std::regex rgx_unroll_restored_default("B::count,loop-unroll,.*,unroll_factor:7,.*");
728b1994897Sopenharmony_ci
729b1994897Sopenharmony_ci        for (std::string line; std::getline(events_file, line);) {
730b1994897Sopenharmony_ci            if (line.rfind("loop-unroll") != std::string::npos) {
731b1994897Sopenharmony_ci                if (!first_found) {
732b1994897Sopenharmony_ci                    // Check that the cluster is applied:
733b1994897Sopenharmony_ci                    ASSERT_TRUE(std::regex_match(line, rgx_unroll_applied_cluster));
734b1994897Sopenharmony_ci                    first_found = true;
735b1994897Sopenharmony_ci                    continue;
736b1994897Sopenharmony_ci                }
737b1994897Sopenharmony_ci                ASSERT_FALSE(second_found);
738b1994897Sopenharmony_ci                // Check that the option is restored:
739b1994897Sopenharmony_ci                ASSERT_TRUE(std::regex_match(line, rgx_unroll_restored_default));
740b1994897Sopenharmony_ci                second_found = true;
741b1994897Sopenharmony_ci            }
742b1994897Sopenharmony_ci        }
743b1994897Sopenharmony_ci        ASSERT_TRUE(first_found && second_found);
744b1994897Sopenharmony_ci    }
745b1994897Sopenharmony_ci}
746b1994897Sopenharmony_ci
747b1994897Sopenharmony_ciTEST_F(AotTest, PandaFiles)
748b1994897Sopenharmony_ci{
749b1994897Sopenharmony_ci#ifndef PANDA_EVENTS_ENABLED
750b1994897Sopenharmony_ci    GTEST_SKIP();
751b1994897Sopenharmony_ci#endif
752b1994897Sopenharmony_ci
753b1994897Sopenharmony_ci    if (RUNTIME_ARCH != Arch::X86_64) {
754b1994897Sopenharmony_ci        GTEST_SKIP();
755b1994897Sopenharmony_ci    }
756b1994897Sopenharmony_ci
757b1994897Sopenharmony_ci    TmpFile aot_fname("./test.an");
758b1994897Sopenharmony_ci    TmpFile panda_fname1("test1.pf");
759b1994897Sopenharmony_ci    TmpFile panda_fname2("test2.pf");
760b1994897Sopenharmony_ci    TmpFile paoc_output_name("events-out.csv");
761b1994897Sopenharmony_ci
762b1994897Sopenharmony_ci    {
763b1994897Sopenharmony_ci        auto source = R"(
764b1994897Sopenharmony_ci            .record Z {}
765b1994897Sopenharmony_ci            .function i32 Z.zoo() <static> {
766b1994897Sopenharmony_ci                ldai 45
767b1994897Sopenharmony_ci                return
768b1994897Sopenharmony_ci            }
769b1994897Sopenharmony_ci        )";
770b1994897Sopenharmony_ci
771b1994897Sopenharmony_ci        pandasm::Parser parser;
772b1994897Sopenharmony_ci        auto res = parser.Parse(source);
773b1994897Sopenharmony_ci        ASSERT_TRUE(res);
774b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname1.GetFileName(), res.Value()));
775b1994897Sopenharmony_ci    }
776b1994897Sopenharmony_ci
777b1994897Sopenharmony_ci    {
778b1994897Sopenharmony_ci        auto source = R"(
779b1994897Sopenharmony_ci            .record Z <external>
780b1994897Sopenharmony_ci            .function i32 Z.zoo() <external, static>
781b1994897Sopenharmony_ci            .record X {}
782b1994897Sopenharmony_ci            .function i32 X.main() {
783b1994897Sopenharmony_ci                call.short Z.zoo
784b1994897Sopenharmony_ci                return
785b1994897Sopenharmony_ci            }
786b1994897Sopenharmony_ci        )";
787b1994897Sopenharmony_ci
788b1994897Sopenharmony_ci        pandasm::Parser parser;
789b1994897Sopenharmony_ci        auto res = parser.Parse(source);
790b1994897Sopenharmony_ci        ASSERT_TRUE(res);
791b1994897Sopenharmony_ci        ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname2.GetFileName(), res.Value()));
792b1994897Sopenharmony_ci    }
793b1994897Sopenharmony_ci
794b1994897Sopenharmony_ci    {
795b1994897Sopenharmony_ci        std::stringstream panda_files;
796b1994897Sopenharmony_ci        panda_files << panda_fname1.GetFileName() << ',' << panda_fname2.GetFileName();
797b1994897Sopenharmony_ci        auto res = os::exec::Exec(paoc_path_.c_str(), "--paoc-panda-files", panda_fname2.GetFileName(), "--panda-files",
798b1994897Sopenharmony_ci                                  panda_fname1.GetFileName(), "--events-output=csv", "--events-file",
799b1994897Sopenharmony_ci                                  paoc_output_name.GetFileName());
800b1994897Sopenharmony_ci        ASSERT_TRUE(res) << "paoc failed with error: " << res.Error().ToString();
801b1994897Sopenharmony_ci        ASSERT_EQ(res.Value(), 0);
802b1994897Sopenharmony_ci
803b1994897Sopenharmony_ci        std::ifstream infile(paoc_output_name.GetFileName());
804b1994897Sopenharmony_ci        // Inlining attempt proofs that Z::zoo was available to inline
805b1994897Sopenharmony_ci        std::regex rgx("Inline,.*Z::zoo.*");
806b1994897Sopenharmony_ci        bool inline_attempt = false;
807b1994897Sopenharmony_ci        for (std::string line; std::getline(infile, line);) {
808b1994897Sopenharmony_ci            inline_attempt |= std::regex_match(line, rgx);
809b1994897Sopenharmony_ci        }
810b1994897Sopenharmony_ci        ASSERT_TRUE(inline_attempt);
811b1994897Sopenharmony_ci    }
812b1994897Sopenharmony_ci}
813b1994897Sopenharmony_ci
814b1994897Sopenharmony_ci}  // namespace panda::compiler
815