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 #include "gtest/gtest.h"
17
18 #include "asmjit/x86.h"
19
20 namespace panda::compiler {
21 using namespace asmjit;
22
23 class AsmJitTest : public ::testing::Test {
24 };
25
TEST_F(AsmJitTest,HelloWorld)26 TEST_F(AsmJitTest, HelloWorld)
27 {
28 // Runtime designed for JIT code execution.
29 JitRuntime rt;
30
31 // Holds code and relocation information.
32 CodeHolder code;
33 code.init(rt.environment());
34
35 x86::Assembler a(&code);
36 a.mov(x86::eax, 1);
37 a.ret();
38
39 // Signature of the generated function.
40 typedef int (*Func)(void);
41 Func fn {nullptr};
42
43 // Add the generated code to the runtime.
44 Error err = rt.add(&fn, &code);
45 ASSERT_FALSE(err);
46
47 int result {fn()};
48 ASSERT_EQ(1, result);
49 }
50
TEST_F(AsmJitTest,Add)51 TEST_F(AsmJitTest, Add)
52 {
53 // Runtime designed for JIT code execution.
54 JitRuntime rt;
55
56 // Holds code and relocation information.
57 CodeHolder code;
58 code.init(rt.environment());
59
60 // Generating code:
61 x86::Assembler a(&code);
62 x86::Gp lhs = a.zax();
63 x86::Gp rhs = a.zcx();
64
65 FuncDetail func;
66 func.init(FuncSignatureT<size_t, size_t, size_t>(CallConv::kIdHost), code.environment());
67
68 FuncFrame frame;
69 frame.init(func);
70 frame.addDirtyRegs(lhs, rhs);
71
72 FuncArgsAssignment args(&func);
73 args.assignAll(lhs, rhs);
74 args.updateFuncFrame(frame);
75 frame.finalize();
76
77 a.emitProlog(frame);
78 a.emitArgsAssignment(frame, args);
79 a.add(lhs, rhs);
80 a.emitEpilog(frame);
81
82 // Signature of the generated function.
83 typedef size_t (*Func)(size_t, size_t);
84 Func fn {nullptr};
85
86 // Add the generated code to the runtime.
87 Error err = rt.add(&fn, &code);
88 ASSERT_FALSE(err);
89
90 size_t result {fn(size_t(2), size_t(3))};
91 ASSERT_EQ(size_t(5), result);
92 }
93
TEST_F(AsmJitTest,AddExplicit)94 TEST_F(AsmJitTest, AddExplicit)
95 {
96 Environment env = hostEnvironment();
97 JitAllocator allocator;
98
99 CodeHolder code;
100 code.init(env);
101
102 // Generating code:
103 x86::Assembler a(&code);
104 x86::Gp lhs = a.zax();
105 x86::Gp rhs = a.zcx();
106
107 FuncDetail func;
108 func.init(FuncSignatureT<size_t, size_t, size_t>(CallConv::kIdHost), code.environment());
109
110 FuncFrame frame;
111 frame.init(func);
112 frame.addDirtyRegs(lhs, rhs);
113
114 FuncArgsAssignment args(&func);
115 args.assignAll(lhs, rhs);
116 args.updateFuncFrame(frame);
117 frame.finalize();
118
119 a.emitProlog(frame);
120 a.emitArgsAssignment(frame, args);
121 a.add(lhs, rhs);
122 a.emitEpilog(frame);
123
124 code.flatten();
125 code.resolveUnresolvedLinks();
126 size_t estimated_size = code.codeSize();
127
128 // Allocate memory for the function and relocate it there.
129 void *ro_ptr;
130 void *rw_ptr;
131 Error err = allocator.alloc(&ro_ptr, &rw_ptr, estimated_size);
132 ASSERT_FALSE(err);
133
134 // Relocate to the base-address of the allocated memory.
135 code.relocateToBase(reinterpret_cast<uintptr_t>(rw_ptr));
136 size_t code_size = code.codeSize();
137
138 code.copyFlattenedData(rw_ptr, code_size, CodeHolder::kCopyPadSectionBuffer);
139
140 // Execute the function and test whether it works.
141 typedef size_t (*Func)(size_t lhs, size_t rhs);
142 Func fn = (Func)ro_ptr;
143
144 size_t result {fn(size_t(2), size_t(3))};
145 ASSERT_EQ(size_t(5), result);
146
147 err = allocator.release(ro_ptr);
148 ASSERT_FALSE(err);
149 }
150 } // namespace panda::compiler
151