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 #include "mem/pool_manager.h"
21
22 namespace panda::compiler {
23 using namespace asmjit;
24
25 class AsmJitTest : public ::testing::Test {
26 public:
AsmJitTest()27 AsmJitTest()
28 {
29 panda::mem::MemConfig::Initialize(64_MB, 64_MB, 64_MB, 32_MB);
30 PoolManager::Initialize();
31 allocator_ = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
32 }
33
~AsmJitTest()34 ~AsmJitTest()
35 {
36 delete allocator_;
37 PoolManager::Finalize();
38 panda::mem::MemConfig::Finalize();
39 }
40
GetAllocator()41 ArenaAllocator *GetAllocator()
42 {
43 return allocator_;
44 }
45
46 private:
47 ArenaAllocator *allocator_ {nullptr};
48 };
49
TEST_F(AsmJitTest, HelloWorld)50 TEST_F(AsmJitTest, HelloWorld)
51 {
52 // Runtime designed for JIT code execution.
53 JitRuntime rt;
54
55 // Holds code and relocation information.
56 CodeHolder code(GetAllocator());
57 code.init(rt.environment());
58
59 x86::Assembler a(&code);
60 a.mov(x86::rax, 1);
61 a.ret();
62
63 // Signature of the generated function.
64 typedef int (*Func)(void);
65 Func fn {nullptr};
66
67 // Add the generated code to the runtime.
68 Error err = rt.add(&fn, &code);
69 ASSERT_FALSE(err);
70
71 int result {fn()};
72 ASSERT_EQ(1, result);
73 }
74
TEST_F(AsmJitTest, Add)75 TEST_F(AsmJitTest, Add)
76 {
77 // Runtime designed for JIT code execution.
78 JitRuntime rt;
79
80 // Holds code and relocation information.
81 CodeHolder code(GetAllocator());
82 code.init(rt.environment());
83
84 // Generating code:
85 x86::Assembler a(&code);
86 x86::Gp lhs = a.zax();
87 x86::Gp rhs = a.zcx();
88
89 FuncDetail func;
90 func.init(FuncSignatureT<size_t, size_t, size_t>(CallConv::kIdHost), code.environment());
91
92 FuncFrame frame;
93 frame.init(func);
94 frame.addDirtyRegs(lhs, rhs);
95
96 FuncArgsAssignment args(&func);
97 args.assignAll(lhs, rhs);
98 args.updateFuncFrame(frame);
99 frame.finalize();
100
101 a.emitProlog(frame);
102 a.emitArgsAssignment(frame, args);
103 a.add(lhs, rhs);
104 a.emitEpilog(frame);
105
106 // Signature of the generated function.
107 typedef size_t (*Func)(size_t, size_t);
108 Func fn {nullptr};
109
110 // Add the generated code to the runtime.
111 Error err = rt.add(&fn, &code);
112 ASSERT_FALSE(err);
113
114 size_t result {fn(size_t(2), size_t(3))};
115 ASSERT_EQ(size_t(5), result);
116 }
117
TEST_F(AsmJitTest, Add2)118 TEST_F(AsmJitTest, Add2)
119 {
120 JitRuntime rt;
121
122 CodeHolder code(GetAllocator());
123 code.init(rt.environment());
124
125 // Generating code:
126 x86::Assembler a(&code);
127 a.add(x86::rdi, x86::rsi);
128 a.mov(x86::rax, x86::rdi);
129 a.ret();
130
131 // Signature of the generated function.
132 typedef size_t (*Func)(size_t, size_t);
133 Func fn {nullptr};
134
135 // Add the generated code to the runtime.
136 Error err = rt.add(&fn, &code);
137 ASSERT_FALSE(err);
138
139 size_t result {fn(size_t(2), size_t(3))};
140 ASSERT_EQ(size_t(5), result);
141 }
142
TEST_F(AsmJitTest, AddDouble)143 TEST_F(AsmJitTest, AddDouble)
144 {
145 JitRuntime rt;
146
147 CodeHolder code(GetAllocator());
148 code.init(rt.environment());
149
150 // Generating code:
151 x86::Assembler a(&code);
152 a.addsd(x86::xmm0, x86::xmm1);
153 a.ret();
154
155 // Signature of the generated function.
156 typedef double (*Func)(double, double);
157 Func fn {nullptr};
158
159 // Add the generated code to the runtime.
160 Error err = rt.add(&fn, &code);
161 ASSERT_FALSE(err);
162
163 double result {fn(2.0, 3.0)};
164 ASSERT_EQ(5.0, result);
165 }
166
TEST_F(AsmJitTest, AddExplicit)167 TEST_F(AsmJitTest, AddExplicit)
168 {
169 Environment env = hostEnvironment();
170 JitAllocator allocator;
171
172 CodeHolder code(GetAllocator());
173 code.init(env);
174
175 // Generating code:
176 x86::Assembler a(&code);
177 x86::Gp lhs = a.zax();
178 x86::Gp rhs = a.zcx();
179
180 FuncDetail func;
181 func.init(FuncSignatureT<size_t, size_t, size_t>(CallConv::kIdHost), code.environment());
182
183 FuncFrame frame;
184 frame.init(func);
185 frame.addDirtyRegs(lhs, rhs);
186
187 FuncArgsAssignment args(&func);
188 args.assignAll(lhs, rhs);
189 args.updateFuncFrame(frame);
190 frame.finalize();
191
192 a.emitProlog(frame);
193 a.emitArgsAssignment(frame, args);
194 a.add(lhs, rhs);
195 a.emitEpilog(frame);
196
197 code.flatten();
198 code.resolveUnresolvedLinks();
199 size_t estimated_size = code.codeSize();
200
201 // Allocate memory for the function and relocate it there.
202 void *ro_ptr;
203 void *rw_ptr;
204 Error err = allocator.alloc(&ro_ptr, &rw_ptr, estimated_size);
205 ASSERT_FALSE(err);
206
207 // Relocate to the base-address of the allocated memory.
208 code.relocateToBase(reinterpret_cast<uintptr_t>(rw_ptr));
209 size_t code_size = code.codeSize();
210
211 code.copyFlattenedData(rw_ptr, code_size, CodeHolder::kCopyPadSectionBuffer);
212
213 // Execute the function and test whether it works.
214 typedef size_t (*Func)(size_t lhs, size_t rhs);
215 Func fn = (Func)ro_ptr;
216
217 size_t result {fn(size_t(2), size_t(3))};
218 ASSERT_EQ(size_t(5), result);
219
220 err = allocator.release(ro_ptr);
221 ASSERT_FALSE(err);
222 }
223 } // namespace panda::compiler
224