1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "gtest/gtest.h"
18
19 #include <sys/mman.h>
20
21 #include <cstring>
22 #include <iterator>
23 #include <string>
24
25 #include "berberis/assembler/machine_code.h"
26 #include "berberis/assembler/rv32e.h"
27 #include "berberis/assembler/rv32i.h"
28 #include "berberis/assembler/rv64i.h"
29 #include "berberis/assembler/x86_32.h"
30 #include "berberis/assembler/x86_64.h"
31 #include "berberis/base/bit_util.h"
32 #include "berberis/base/logging.h"
33 #include "berberis/test_utils/scoped_exec_region.h"
34
35 #if defined(__i386__)
36 using CodeEmitter = berberis::x86_32::Assembler;
37 #elif defined(__amd64__)
38 using CodeEmitter = berberis::x86_64::Assembler;
39 #elif defined(__riscv)
40 using CodeEmitter = berberis::rv64::Assembler;
41 #else
42 #error "Unsupported platform"
43 #endif
44
45 namespace berberis {
46
47 enum class CPUArch {
48 kX86_64,
49 kRiscv64,
50 };
51
Callee()52 int Callee() {
53 return 239;
54 }
55
FloatFunc(float f1,float f2)56 float FloatFunc(float f1, float f2) {
57 return f1 - f2;
58 }
59
IsInstructionEqual(std::string code_str1,std::string code_str2,uint32_t insn,uint32_t insn_size)60 inline bool IsInstructionEqual(std::string code_str1,
61 std::string code_str2,
62 uint32_t insn,
63 uint32_t insn_size) {
64 return code_str1.compare(
65 insn * (insn_size + 1), insn_size, code_str2, insn * (insn_size + 1), insn_size) == 0;
66 }
67
68 template <typename ParcelInt>
CompareCode(const ParcelInt * code_template_begin,const ParcelInt * code_template_end,const MachineCode & code,CPUArch arch)69 inline bool CompareCode(const ParcelInt* code_template_begin,
70 const ParcelInt* code_template_end,
71 const MachineCode& code,
72 CPUArch arch) {
73 if ((code_template_end - code_template_begin) * sizeof(ParcelInt) != code.install_size()) {
74 ALOGE("Code size mismatch: %zd != %u",
75 (code_template_end - code_template_begin) * static_cast<unsigned>(sizeof(ParcelInt)),
76 code.install_size());
77 return false;
78 }
79
80 if (memcmp(code_template_begin, code.AddrAs<uint8_t>(0), code.install_size()) != 0) {
81 ALOGE("Code mismatch");
82 MachineCode code2;
83 code2.AddSequence(code_template_begin, code_template_end - code_template_begin);
84 std::string code_str1, code_str2;
85 uint32_t insn_size = 0;
86 switch (arch) {
87 case CPUArch::kRiscv64:
88 insn_size = 8;
89 code.AsString(&code_str1, InstructionSize::FourBytes);
90 code2.AsString(&code_str2, InstructionSize::FourBytes);
91 break;
92 case CPUArch::kX86_64:
93 insn_size = 2;
94 code.AsString(&code_str1, InstructionSize::OneByte);
95 code2.AsString(&code_str2, InstructionSize::OneByte);
96 break;
97 }
98 CHECK_EQ(code_str1.size() % (insn_size + 1), 0);
99 CHECK_EQ(code_str2.size() % (insn_size + 1), 0);
100 uint32_t number_of_instructions = code_str1.size() / (insn_size + 1);
101 // Skip identical part.
102 uint32_t insn = 0;
103 while (insn < number_of_instructions &&
104 IsInstructionEqual(code_str1, code_str2, insn, insn_size)) {
105 insn++;
106 }
107 for (uint32_t i = insn; i < insn + 20 && i < number_of_instructions; i++) {
108 ALOGE("Assembler generated: %s, should be %s\n",
109 code_str1.substr(i * (insn_size + 1), insn_size).c_str(),
110 code_str2.substr(i * (insn_size + 1), insn_size).c_str());
111 }
112
113 return false;
114 }
115 return true;
116 }
117
118 namespace rv32 {
119
AssemblerTest()120 bool AssemblerTest() {
121 MachineCode code;
122 Assembler assembler(&code);
123 Assembler::Label data_begin, data_end, label;
124 assembler.Bind(&data_begin);
125 // We test loads and stores twice to ensure that both positive and negative immediates are
126 // present both in auipc and in the follow-up load/store instructions.
127 assembler.Fld(Assembler::f1, data_end, Assembler::x2);
128 assembler.Flw(Assembler::f3, data_end, Assembler::x4);
129 assembler.Fsd(Assembler::f5, data_end, Assembler::x6);
130 assembler.Fsw(Assembler::f7, data_end, Assembler::x8);
131 assembler.Lb(Assembler::x9, data_end);
132 assembler.Lbu(Assembler::x10, data_end);
133 assembler.Lh(Assembler::x11, data_end);
134 assembler.Lhu(Assembler::x12, data_end);
135 assembler.Lw(Assembler::x13, data_end);
136 assembler.Sb(Assembler::x14, data_end, Assembler::x15);
137 assembler.Sh(Assembler::x16, data_end, Assembler::x17);
138 assembler.Sw(Assembler::x18, data_end, Assembler::x19);
139 assembler.La(Assembler::x20, data_end);
140 assembler.Bcc(Assembler::Condition::kEqual, Assembler::x1, Assembler::x2, label);
141 assembler.Bcc(Assembler::Condition::kNotEqual, Assembler::x3, Assembler::x4, label);
142 assembler.Bcc(Assembler::Condition::kLess, Assembler::x5, Assembler::x6, label);
143 assembler.Bcc(Assembler::Condition::kGreaterEqual, Assembler::x7, Assembler::x8, label);
144 assembler.Bcc(Assembler::Condition::kBelow, Assembler::x9, Assembler::x10, label);
145 assembler.Bcc(Assembler::Condition::kAboveEqual, Assembler::x11, Assembler::x12, label);
146 assembler.Jal(Assembler::x1, label);
147 assembler.Add(Assembler::x1, Assembler::x2, Assembler::x3);
148 assembler.Addi(Assembler::x1, Assembler::x2, 42);
149 assembler.Bind(&label);
150 // Jalr have two alternate forms.
151 assembler.Jalr(Assembler::x1, Assembler::x2, 42);
152 assembler.Jalr(Assembler::x3, {.base = Assembler::x4, .disp = 42});
153 assembler.Sw(Assembler::x1, {.base = Assembler::x2, .disp = 42});
154 assembler.Jal(Assembler::x2, label);
155 assembler.Beq(Assembler::x1, Assembler::x2, label);
156 assembler.Bne(Assembler::x3, Assembler::x4, label);
157 assembler.Blt(Assembler::x5, Assembler::x6, label);
158 assembler.Bge(Assembler::x7, Assembler::x8, label);
159 assembler.Bltu(Assembler::x9, Assembler::x10, label);
160 assembler.Bgeu(Assembler::x11, Assembler::x12, label);
161 assembler.Csrrc(Assembler::x1, Assembler::Csr::kVl, Assembler::x2);
162 assembler.Csrrs(Assembler::x3, Assembler::Csr::kVtype, Assembler::x4);
163 assembler.Csrrw(Assembler::x5, Assembler::Csr::kVlenb, Assembler::x6);
164 assembler.Slli(Assembler::x1, Assembler::x2, 3);
165 assembler.Srai(Assembler::x4, Assembler::x5, 6);
166 assembler.Srli(Assembler::x7, Assembler::x8, 9);
167 assembler.FcvtSW(Assembler::f1, Assembler::x2, Assembler::Rounding::kRmm);
168 assembler.FcvtSWu(Assembler::f3, Assembler::x4);
169 assembler.FcvtWS(Assembler::x1, Assembler::f2, Assembler::Rounding::kRmm);
170 assembler.FcvtWuS(Assembler::x3, Assembler::f4);
171 assembler.FsqrtS(Assembler::f1, Assembler::f2, Assembler::Rounding::kRmm);
172 assembler.FsqrtD(Assembler::f3, Assembler::f4);
173 assembler.PrefetchI({.base = Assembler::x1, .disp = 32});
174 assembler.PrefetchR({.base = Assembler::x2, .disp = 64});
175 assembler.PrefetchW({.base = Assembler::x3, .disp = 96});
176 assembler.Li(Assembler::x15, static_cast<int32_t>(0xaf));
177 assembler.Seqz(Assembler::x20, Assembler::x10);
178 assembler.Snez(Assembler::x2, Assembler::x9);
179 assembler.Sltz(Assembler::x30, Assembler::x1);
180 assembler.Sgtz(Assembler::x25, Assembler::x16);
181 assembler.J(0x42);
182 assembler.Jal(-0x26);
183 assembler.Jr(Assembler::x19);
184 assembler.Jalr(Assembler::x7);
185 // Move target position for more than 2048 bytes down to ensure auipc would use non-zero
186 // immediate.
187 for (size_t index = 138; index < 1200; ++index) {
188 assembler.TwoByte(uint16_t{0});
189 }
190 assembler.Fld(Assembler::f1, data_begin, Assembler::x2);
191 assembler.Flw(Assembler::f3, data_begin, Assembler::x4);
192 assembler.Fsd(Assembler::f5, data_begin, Assembler::x6);
193 assembler.Fsw(Assembler::f7, data_begin, Assembler::x8);
194 assembler.Lb(Assembler::x9, data_begin);
195 assembler.Lbu(Assembler::x10, data_begin);
196 assembler.Lh(Assembler::x11, data_begin);
197 assembler.Lhu(Assembler::x12, data_begin);
198 assembler.Lw(Assembler::x13, data_begin);
199 assembler.Sb(Assembler::x14, data_begin, Assembler::x15);
200 assembler.Sh(Assembler::x16, data_begin, Assembler::x17);
201 assembler.Sw(Assembler::x18, data_begin, Assembler::x19);
202 assembler.La(Assembler::x20, data_begin);
203 assembler.Bind(&data_end);
204 assembler.Bexti(Assembler::x16, Assembler::x1, 20);
205 assembler.Rori(Assembler::x5, Assembler::x3, 5);
206 assembler.Finalize();
207
208 // clang-format off
209 static const uint16_t kCodeTemplate[] = {
210 0x1117, 0x0000, // begin: auipc x2, 4096
211 0x3087, 0x9c81, // fld f1, -1592(x2)
212 0x1217, 0x0000, // auipc x4, 4096
213 0x2187, 0x9c02, // flw f3, -1600(x4)
214 0x1317, 0x0000, // auipc x6, 4096
215 0x3c27, 0x9a53, // fsd f5, -1608(x6)
216 0x1417, 0x0000, // auipc x8, 4096
217 0x2827, 0x9a74, // fsw f7, -1616(x8)
218 0x1497, 0x0000, // auipc x9, 4096
219 0x8483, 0x9a84, // lb x9, -1624(x9)
220 0x1517, 0x0000, // auipc x10, 4096
221 0x4503, 0x9a05, // lbu x10, -1632(x10)
222 0x1597, 0x0000, // auipc x11, 4096
223 0x9583, 0x9985, // lh x11, -1640(x11)
224 0x1617, 0x0000, // auipc x12, 4096
225 0x5603, 0x9906, // lhu x12, -1648(x12)
226 0x1697, 0x0000, // auipc x13, 4096
227 0xa683, 0x9886, // lw x13, -1656(x13)
228 0x1797, 0x0000, // auipc x15, 4096
229 0x8023, 0x98e7, // sb x14, -1664(x15)
230 0x1897, 0x0000, // auipc x17, 4096
231 0x9c23, 0x9708, // sh x16, -1672(x17)
232 0x1997, 0x0000, // auipc x19, 4096
233 0xa823, 0x9729, // sw x18, -1680(x19)
234 0x1a17, 0x0000, // auipc x20, 4096
235 0x0a13, 0x968a, // addi x20, x20, -1688
236 0x8263, 0x0220, // beq x1, x2, label
237 0x9063, 0x0241, // bne x3, x4, label
238 0xce63, 0x0062, // blt x5, x6, label
239 0xdc63, 0x0083, // bge x7, x8, label
240 0xea63, 0x00a4, // bltu x9, x10, label
241 0xf863, 0x00c5, // bgeu x11, x12, label
242 0x00ef, 0x00c0, // jal x1, label
243 0x00b3, 0x0031, // add x1, x2, x3
244 0x0093, 0x02a1, // addi x1, x2, 42
245 0x00e7, 0x02a1, // label: jalr x1, x2, 42
246 0x01e7, 0x02a2, // jalr x3, 42(x4)
247 0x2523, 0x0211, // sw x1, 42(x2)
248 0xf16f, 0xff5f, // jal x2, label
249 0x88e3, 0xfe20, // beq x1, x2, label
250 0x96e3, 0xfe41, // bne x3, x4, label
251 0xc4e3, 0xfe62, // blt x5, x6, label
252 0xd2e3, 0xfe83, // bge x7, x8, label
253 0xe0e3, 0xfea4, // bltu x9, x10, label
254 0xfee3, 0xfcc5, // bgeu x11, x12, label
255 0x30f3, 0xc201, // csrrc x1, vl, x2
256 0x21f3, 0xc212, // csrrs x3, vtype, x4
257 0x12f3, 0xc223, // csrrw x5, vlenb, x6
258 0x1093, 0x0031, // slli x1, x2, 3
259 0xd213, 0x4062, // srai x4, x5, 6
260 0x5393, 0x0094, // srli x7, x8, 9
261 0x40d3, 0xd001, // fcvt.s.w f1, x2, rmm
262 0x71d3, 0xd012, // fcvt.s.wu f3, x4
263 0x40d3, 0xc001, // fcvt.w.s x1, f2, rmm
264 0x71d3, 0xc012, // fcvt.wu.s x3, f4
265 0x40d3, 0x5801, // fsqrt.s f1, f2, rmm
266 0x71d3, 0x5a02, // fsqrt.d f3, f4
267 0xe013, 0x0200, // prefetch.i 32(x1)
268 0x6013, 0x0411, // prefetch.r 64(x2)
269 0xe013, 0x0631, // prefetch.w 96(x3)
270 0x0793, 0x0af0, // addi x15, x15, 0xaf
271 0x3a13, 0x0015, // sltiu x20, x10, 1
272 0x3133, 0x0090, // sltu x2, x0, x9
273 0xaf33, 0x0000, // slt x30, x1, x0
274 0x2cb3, 0x0100, // slt x25, x0, x16
275 0x006f, 0x0420, // jal zero, 0x42
276 0xf0ef, 0xfdbf, // jal x1, -0x26
277 0x8067, 0x0009, // jalr zero, x19, 0
278 0x80e7, 0x0003, // jalr x1, x7, 0
279 [ 138 ... 1199 ] = 0,// padding
280 0xf117, 0xffff, // auipc x2, -4096
281 0x3087, 0x6a01, // fld f1,1696(x2)
282 0xf217, 0xffff, // auipc x4, -4096
283 0x2187, 0x6982, // flw f3,1688(x4)
284 0xf317, 0xffff, // auipc x6, -4096
285 0x3827, 0x6853, // fsd f5,1680(x6)
286 0xf417, 0xffff, // auipc x8, -4096
287 0x2427, 0x6874, // fsw f7,1672(x8)
288 0xf497, 0xffff, // auipc x9, -4096
289 0x8483, 0x6804, // lb x9,1664(x9)
290 0xf517, 0xffff, // auipc x10, -4096
291 0x4503, 0x6785, // lbu x10,1656(x10)
292 0xf597, 0xffff, // auipc x11, -4096
293 0x9583, 0x6705, // lh x11,1648(x11)
294 0xf617, 0xffff, // auipc x12, -4096
295 0x5603, 0x6686, // lhu x12,1640(x12)
296 0xf697, 0xffff, // auipc x13, -4096
297 0xa683, 0x6606, // lw x13,1632(x13)
298 0xf797, 0xffff, // auipc x15, -4096
299 0x8c23, 0x64e7, // sb x14,1624(x15)
300 0xf897, 0xffff, // auipc x17, -4096
301 0x9823, 0x6508, // sh x16,1616(x17)
302 0xf997, 0xffff, // auipc x19, -4096
303 0xa423, 0x6529, // sw x18,1608(x19)
304 0xfa17, 0xffff, // auipc x20, -4096
305 0x0a13, 0x640a, // addi x20,x20,1600
306 0xd813, 0x4940, // bexti x16,x1,20
307 0xd293, 0x6051, // rori x5, x3, 5
308 }; // end:
309 // clang-format on
310
311 return CompareCode(std::begin(kCodeTemplate), std::end(kCodeTemplate), code, CPUArch::kRiscv64);
312 }
313
314 } // namespace rv32
315
316 namespace rv64 {
317
AssemblerTest()318 bool AssemblerTest() {
319 MachineCode code;
320 Assembler assembler(&code);
321 Assembler::Label data_begin, data_end;
322 assembler.Bind(&data_begin);
323 // We test loads and stores twice to ensure that both positive and negative immediates are
324 // present both in auipc and in the follow-up load/store instructions.
325 assembler.Ld(Assembler::x1, data_end);
326 assembler.Lwu(Assembler::x2, data_end);
327 assembler.Sd(Assembler::x3, data_end, Assembler::x4);
328 assembler.Bcc(Assembler::Condition::kAlways, Assembler::x1, Assembler::x2, 48);
329 assembler.Bcc(Assembler::Condition::kEqual, Assembler::x3, Assembler::x4, 44);
330 assembler.Bcc(Assembler::Condition::kNotEqual, Assembler::x5, Assembler::x6, 40);
331 assembler.Bcc(Assembler::Condition::kLess, Assembler::x7, Assembler::x8, 36);
332 assembler.Bcc(Assembler::Condition::kGreaterEqual, Assembler::x9, Assembler::x10, 32);
333 assembler.Bcc(Assembler::Condition::kBelow, Assembler::x11, Assembler::x12, 28);
334 assembler.Bcc(Assembler::Condition::kAboveEqual, Assembler::x13, Assembler::x14, 24);
335 assembler.Jal(Assembler::x1, 20);
336 assembler.Add(Assembler::x1, Assembler::x2, Assembler::x3);
337 assembler.Addw(Assembler::x1, Assembler::x2, Assembler::x3);
338 assembler.Addi(Assembler::x1, Assembler::x2, 42);
339 assembler.Addiw(Assembler::x1, Assembler::x2, 42);
340 // Jalr have two alternate forms.
341 assembler.Jalr(Assembler::x1, Assembler::x2, 42);
342 assembler.Jalr(Assembler::x3, {.base = Assembler::x4, .disp = 42});
343 assembler.Sw(Assembler::x1, {.base = Assembler::x2, .disp = 42});
344 assembler.Sd(Assembler::x3, {.base = Assembler::x4, .disp = 42});
345 assembler.Jal(Assembler::x2, -16);
346 assembler.Beq(Assembler::x1, Assembler::x2, -20);
347 assembler.Bne(Assembler::x3, Assembler::x4, -24);
348 assembler.Blt(Assembler::x5, Assembler::x6, -28);
349 assembler.Bge(Assembler::x7, Assembler::x8, -32);
350 assembler.Bltu(Assembler::x9, Assembler::x10, -36);
351 assembler.Bgeu(Assembler::x11, Assembler::x12, -40);
352 assembler.Bcc(Assembler::Condition::kAlways, Assembler::x13, Assembler::x14, -44);
353 assembler.Csrrc(Assembler::x1, Assembler::Csr::kVl, 2);
354 assembler.Csrrs(Assembler::x3, Assembler::Csr::kVtype, 4);
355 assembler.Csrrw(Assembler::x5, Assembler::Csr::kVlenb, 6);
356 assembler.Csrrci(Assembler::x7, Assembler::Csr::kVl, 8);
357 assembler.Csrrsi(Assembler::x9, Assembler::Csr::kVtype, 10);
358 assembler.Csrrwi(Assembler::x11, Assembler::Csr::kVlenb, 12);
359 assembler.Slliw(Assembler::x1, Assembler::x2, 3);
360 assembler.Sraiw(Assembler::x4, Assembler::x5, 6);
361 assembler.Srliw(Assembler::x7, Assembler::x8, 9);
362 assembler.FcvtDL(Assembler::f1, Assembler::x2, Assembler::Rounding::kRmm);
363 assembler.FcvtDLu(Assembler::f3, Assembler::x4);
364 assembler.FcvtLD(Assembler::x1, Assembler::f2, Assembler::Rounding::kRmm);
365 assembler.FcvtLuD(Assembler::x3, Assembler::f4);
366 assembler.FsqrtS(Assembler::f1, Assembler::f2, Assembler::Rounding::kRmm);
367 assembler.FsqrtD(Assembler::f3, Assembler::f4);
368 assembler.PrefetchI({.base = Assembler::x1, .disp = 32});
369 assembler.PrefetchR({.base = Assembler::x2, .disp = 64});
370 assembler.PrefetchW({.base = Assembler::x3, .disp = 96});
371 assembler.Li(Assembler::x10, static_cast<int64_t>(0xaaaa'0aa0'aaa0'0aaa));
372 assembler.Ret();
373 assembler.Call(data_end);
374 assembler.Tail(data_end);
375 assembler.Bgt(Assembler::x4, Assembler::x0, data_end);
376 assembler.Bgtu(Assembler::x2, Assembler::x20, data_end);
377 assembler.Ble(Assembler::x1, Assembler::x30, data_end);
378 assembler.Bleu(Assembler::x8, Assembler::x16, data_end);
379 assembler.Beqz(Assembler::x5, data_end);
380 assembler.Bnez(Assembler::x4, data_end);
381 assembler.Blez(Assembler::x2, data_end);
382 assembler.Bgez(Assembler::x3, data_end);
383 assembler.Bltz(Assembler::x9, data_end);
384 assembler.Bgtz(Assembler::x12, data_end);
385 // Move target position for more than 2048 bytes down to ensure auipc would use non-zero
386 // immediate.
387 for (size_t index = 142; index < 1200; ++index) {
388 assembler.TwoByte(uint16_t{0});
389 }
390 assembler.Ld(Assembler::x1, data_begin);
391 assembler.Lwu(Assembler::x2, data_begin);
392 assembler.Sd(Assembler::x3, data_begin, Assembler::x4);
393 assembler.Bind(&data_end);
394 assembler.SextW(Assembler::x15, Assembler::x12);
395 assembler.AddUW(Assembler::x14, Assembler::x22, Assembler::x29);
396 assembler.ZextW(Assembler::x13, Assembler::x21);
397 assembler.Sh3add(Assembler::x13, Assembler::x9, Assembler::x10);
398 assembler.Bexti(Assembler::x16, Assembler::x1, 53);
399 assembler.Rori(Assembler::x22, Assembler::x30, 43);
400 assembler.Roriw(Assembler::x29, Assembler::x2, 30);
401 assembler.Ror(Assembler::x14, Assembler::x1, Assembler::x10);
402 assembler.Rorw(Assembler::x25, Assembler::x5, Assembler::x4);
403 assembler.Not(Assembler::x10, Assembler::x4);
404 assembler.Neg(Assembler::x11, Assembler::x3);
405 assembler.Negw(Assembler::x12, Assembler::x2);
406 assembler.SextB(Assembler::x22, Assembler::x7);
407 assembler.SextH(Assembler::x23, Assembler::x8);
408 assembler.Finalize();
409
410 // clang-format off
411 static const uint16_t kCodeTemplate[] = {
412 0x1097, 0x0000, // begin: auipc x1, 4096
413 0xb083, 0x9780, // ld, x1, -1672(x1)
414 0x1117, 0x0000, // auipc x2, 4096
415 0x6103, 0x9701, // lwu x2,-1680(x2)
416 0x1217, 0x0000, // auipc x4, 4096
417 0x3423, 0x9632, // sd x3,-1688(x4)
418 0x006f, 0x0300, // jal x0, label
419 0x8663, 0x0241, // beq x1, x2, label
420 0x9463, 0x0262, // bne x3, x4, label
421 0xc263, 0x0283, // blt x5, x6, label
422 0xd063, 0x02a4, // bge x7, x8, label
423 0xee63, 0x00c5, // bltu x9, x10, label
424 0xfc63, 0x00e6, // bgeu x11, x12, label
425 0x00ef, 0x0140, // jal x1, label
426 0x00b3, 0x0031, // add x1, x2, x3
427 0x00bb, 0x0031, // addw x1, x2, x3
428 0x0093, 0x02a1, // addi x1, x2, 42
429 0x009b, 0x02a1, // addiw x1, x2, 42
430 0x00e7, 0x02a1, // label: jalr x1, x2, 42
431 0x01e7, 0x02a2, // jalr x3, 42(x4)
432 0x2523, 0x0211, // sw x1, 42(x2)
433 0x3523, 0x0232, // sd x3, 42(x4)
434 0xf16f, 0xff1f, // jal x2, label
435 0x86e3, 0xfe20, // beq x1, x2, label
436 0x94e3, 0xfe41, // bne x3, x4, label
437 0xc2e3, 0xfe62, // blt x5, x6, label
438 0xd0e3, 0xfe83, // bge x7, x8, label
439 0xeee3, 0xfca4, // bltu x9, x10, label
440 0xfce3, 0xfcc5, // bgeu x11, x12, label
441 0xf06f, 0xfd5f, // jal x0, label
442 0x70f3, 0xc201, // csrrc x1, vl, 2
443 0x61f3, 0xc212, // csrrs x3, vtype, 4
444 0x52f3, 0xc223, // csrrw x5, vlenb, 6
445 0x73f3, 0xc204, // csrrci x7, vl, 8
446 0x64f3, 0xc215, // csrrsi x9, vtype, 10
447 0x55f3, 0xc226, // csrrwi x11, vlenb, 12
448 0x109b, 0x0031, // slliw x1, x2, 3
449 0xd21b, 0x4062, // sraiw x4, x5, 6
450 0x539b, 0x0094, // srliw x7, x8, 9
451 0x40d3, 0xd221, // fcvt.d.l f1, x2, rmm
452 0x71d3, 0xd232, // fcvt.d.lu f3, x4
453 0x40d3, 0xc221, // fcvt.l.d x1, f2, rmm
454 0x71d3, 0xc232, // fcvt.lu.d x3, f4
455 0x40d3, 0x5801, // fsqrt.s f1, f2, rmm
456 0x71d3, 0x5a02, // fsqrt.d f3, f4
457 0xe013, 0x0200, // prefetch.i 32(x1)
458 0x6013, 0x0411, // prefetch.r 64(x2)
459 0xe013, 0x0631, // prefetch.w 96(x3)
460 0x5537,0xfd55, // lui a0, 0xfd555
461 0x0513, 0x0555, // addi a0, a0, 85
462 0x1513, 0x00d5, // slli a0, a0, 0xd
463 0x0513, 0x0ab5, // addi a0, a0, 171
464 0x1513, 0x00c5, // slli a0, a0, 0xc
465 0x0513, 0xa015, // addi a0, a0, -1535
466 0x1513, 0x00c5, // slli a0, a0, 0xc
467 0x0513, 0xaaa5, // addi a0,a0,-1366
468 0x8067, 0x0000, // ret
469 0x1317, 0x0000, // auipc x6, 0x1
470 0x00e7, 0x8943, // jalr x1, x6, -1900
471 0x1317, 0x0000, // auipc x6, 0x1
472 0x0067, 0x88c3, // jalr x0, x6, -1908
473 0x42e3, 0x0840, // blt x0, x4, 0x884
474 0x60e3, 0x082a, // bltu x20, x2, 0x880
475 0x5ee3, 0x061f, // bge x30, x1, 0x87c
476 0x7ce3, 0x0688, // bgeu x16, x8, 0x878
477 0x8ae3, 0x0602, // beq x5, 0x874
478 0x18e3, 0x0602, // bne x4, 0x870
479 0x56e3, 0x0620, // ble x2, 0x86c
480 0xd4e3, 0x0601, // bge x3, 0x868
481 0xc2e3, 0x0604, // blt x9, 0x864
482 0x40e3, 0x06c0, // bgt x12, 0x860
483 [ 142 ... 1199 ] = 0,// padding
484 0xf097, 0xffff, // auipc x1, -4096
485 0xb083, 0x6a00, // ld x1, 1696(x1)
486 0xf117, 0xffff, // auipc x2, -4096
487 0x6103, 0x6981, // lwu x2, 1688(x2)
488 0xf217, 0xffff, // auipc x4, -4096
489 0x3823, 0x6832, // sd x3, 1680(x4)
490 0x079b, 0x0006, // addi.w x15, x12, 0
491 0x073b, 0x09db, // add.uw x14, x22, x29
492 0x86bb, 0x080a, // add.uw x13, x21, zero
493 0xe6b3, 0x20a4, // sh3add x13, x9, x10
494 0xd813, 0x4b50, // bexti x16, x1, 53
495 0x5b13, 0x62bf, // rori x22, x30, 43
496 0x5e9b, 0x61e1, // roriw x29, x2, 30
497 0xd733, 0x60a0, // ror x14, x1, x10
498 0xdcbb, 0x6042, // rorw x25, x5, x4
499 0x4513, 0xfff2, // xori x10, x4, -1
500 0x05b3, 0x4030, // sub x11, zero, x3
501 0x063b, 0x4020, // subw x12, zero, x2
502 0x9b13, 0x6043, // sext.b x22, x7
503 0x1b93, 0x6054, // sext.h x23, x8
504 }; // end:
505 // clang-format on
506
507 return CompareCode(std::begin(kCodeTemplate), std::end(kCodeTemplate), code, CPUArch::kRiscv64);
508 }
509
510 } // namespace rv64
511
512 namespace x86_32 {
513
AssemblerTest()514 bool AssemblerTest() {
515 MachineCode code;
516 Assembler assembler(&code);
517 assembler.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
518 assembler.CmpXchgl({.base = Assembler::esp, .disp = 4}, Assembler::eax);
519 assembler.Subl(Assembler::esp, 16);
520 assembler.Movl({.base = Assembler::esp}, Assembler::eax);
521 assembler.Push(Assembler::esp);
522 assembler.Push(0xcccccccc);
523 assembler.Pushl({.base = Assembler::esp, .disp = 0x428});
524 assembler.Popl({.base = Assembler::esp, .disp = 0x428});
525 assembler.Movl(Assembler::ecx, 0xcccccccc);
526 assembler.Call(Assembler::ecx);
527 assembler.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 8});
528 assembler.Addl(Assembler::esp, 24);
529 assembler.Ret();
530 assembler.Finalize();
531
532 // clang-format off
533 static const uint8_t kCodeTemplate[] = {
534 0x8b, 0x44, 0x24, 0x04, // mov 0x4(%esp),%eax
535 0x0f, 0xb1, 0x44, 0x24, 0x04, // cmpxchg 0x4(%esp),%eax
536 0x83, 0xec, 0x10, // sub $16, %esp
537 0x89, 0x04, 0x24, // mov %eax,(%esp)
538 0x54, // push %esp
539 0x68, 0xcc, 0xcc, 0xcc, 0xcc, // push $cccccccc
540 0xff, 0xb4, 0x24, 0x28, 0x04, 0x00, 0x00, // pushl 0x428(%esp)
541 0x8f, 0x84, 0x24, 0x28, 0x04, 0x00, 0x00, // popl 0x428(%esp)
542 0xb9, 0xcc, 0xcc, 0xcc, 0xcc, // mov $cccccccc, %ecx
543 0xff, 0xd1, // call *%ecx
544 0x8b, 0x44, 0x24, 0x08, // mov 0x8(%esp),%eax
545 0x83, 0xc4, 0x18, // add $24, %esp
546 0xc3 // ret
547 };
548 // clang-format on
549
550 return CompareCode(std::begin(kCodeTemplate), std::end(kCodeTemplate), code, CPUArch::kX86_64);
551 }
552
553 } // namespace x86_32
554
555 namespace x86_64 {
556
AssemblerTest()557 bool AssemblerTest() {
558 MachineCode code;
559 Assembler assembler(&code);
560 assembler.Movq(Assembler::rax, Assembler::rdi);
561 assembler.Subq(Assembler::rsp, 16);
562 assembler.Movq({.base = Assembler::rsp}, Assembler::rax);
563 assembler.Movq({.base = Assembler::rsp, .disp = 8}, Assembler::rax);
564 assembler.Movl({.base = Assembler::rax, .disp = 16}, 239);
565 assembler.Movq(Assembler::r11, {.base = Assembler::rsp});
566 assembler.Addq(Assembler::rsp, 16);
567 assembler.Ret();
568 assembler.Finalize();
569
570 // clang-format off
571 static const uint8_t kCodeTemplate[] = {
572 0x48, 0x89, 0xf8, // mov %rdi, %rax
573 0x48, 0x83, 0xec, 0x10, // sub $0x10, %rsp
574 0x48, 0x89, 0x04, 0x24, // mov rax, (%rsp)
575 0x48, 0x89, 0x44, 0x24, 0x08, // mov rax, 8(%rsp)
576 0xc7, 0x40, 0x10, 0xef, 0x00, // movl $239, 0x10(%rax)
577 0x00, 0x00,
578 0x4c, 0x8b, 0x1c, 0x24, // mov (%rsp), r11
579 0x48, 0x83, 0xc4, 0x10, // add $0x10, %rsp
580 0xc3 // ret
581 };
582 // clang-format on
583
584 return CompareCode(std::begin(kCodeTemplate), std::end(kCodeTemplate), code, CPUArch::kX86_64);
585 }
586
587 } // namespace x86_64
588
589 #if defined(__i386__)
590
591 namespace x86_32 {
592
LabelTest()593 bool LabelTest() {
594 MachineCode code;
595 CodeEmitter as(&code);
596 Assembler::Label skip, skip2, back, end;
597 as.Call(bit_cast<const void*>(&Callee));
598 as.Jmp(skip);
599 as.Movl(Assembler::eax, 2);
600 as.Bind(&skip);
601 as.Addl(Assembler::eax, 8);
602 as.Jmp(skip2);
603 as.Bind(&back);
604 as.Addl(Assembler::eax, 12);
605 as.Jmp(end);
606 as.Bind(&skip2);
607 as.Jmp(back);
608 as.Bind(&end);
609 as.Ret();
610 as.Finalize();
611
612 ScopedExecRegion exec(&code);
613
614 int result = exec.get<int()>()();
615 return result == 239 + 8 + 12;
616 }
617
CondTest1()618 bool CondTest1() {
619 MachineCode code;
620 CodeEmitter as(&code);
621 as.Movl(Assembler::eax, 0xcccccccc);
622 as.Movl(Assembler::edx, {.base = Assembler::esp, .disp = 4}); // arg1.
623 as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8}); // arg2.
624 as.Cmpl(Assembler::edx, Assembler::ecx);
625 as.Setcc(Assembler::Condition::kEqual, Assembler::eax);
626 as.Ret();
627 as.Finalize();
628
629 ScopedExecRegion exec(&code);
630
631 using TestFunc = uint32_t(int, int);
632 auto target_func = exec.get<TestFunc>();
633 uint32_t result = target_func(1, 2);
634 if (result != 0xcccccc00) {
635 ALOGE("Bug in seteq(not equal): %x", result);
636 return false;
637 }
638 result = target_func(-1, -1);
639 if (result != 0xcccccc01) {
640 ALOGE("Bug in seteq(equal): %x", result);
641 return false;
642 }
643 return true;
644 }
645
CondTest2()646 bool CondTest2() {
647 MachineCode code;
648 CodeEmitter as(&code);
649 as.Movl(Assembler::edx, {.base = Assembler::esp, .disp = 4}); // arg1.
650 as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8}); // arg2.
651 as.Xorl(Assembler::eax, Assembler::eax);
652 as.Testb(Assembler::edx, Assembler::ecx);
653 as.Setcc(Assembler::Condition::kNotZero, Assembler::eax);
654 as.Xchgl(Assembler::eax, Assembler::ecx);
655 as.Xchgl(Assembler::ecx, Assembler::eax);
656 as.Ret();
657 as.Finalize();
658
659 ScopedExecRegion exec(&code);
660
661 using TestFunc = uint32_t(int, int);
662 auto target_func = exec.get<TestFunc>();
663 uint32_t result = target_func(0x11, 1);
664 if (result != 0x1) {
665 ALOGE("Bug in testb(not zero): %x", result);
666 return false;
667 }
668 result = target_func(0x11, 0x8);
669 if (result != 0x0) {
670 ALOGE("Bug in testb(zero): %x", result);
671 return false;
672 }
673 return true;
674 }
675
JccTest()676 bool JccTest() {
677 MachineCode code;
678 CodeEmitter as(&code);
679 Assembler::Label equal, above, below, done;
680 as.Movl(Assembler::edx, {.base = Assembler::esp, .disp = 4}); // arg1.
681 as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8}); // arg2.
682 as.Cmpl(Assembler::edx, Assembler::ecx);
683 as.Jcc(Assembler::Condition::kEqual, equal);
684 as.Jcc(Assembler::Condition::kBelow, below);
685 as.Jcc(Assembler::Condition::kAbove, above);
686
687 as.Movl(Assembler::eax, 13);
688 as.Jmp(done);
689
690 as.Bind(&equal);
691 as.Movl(Assembler::eax, 0u);
692 as.Jmp(done);
693
694 as.Bind(&below);
695 as.Movl(Assembler::eax, -1);
696 as.Jmp(done);
697
698 as.Bind(&above);
699 as.Movl(Assembler::eax, 1);
700 as.Jmp(done);
701
702 as.Bind(&done);
703 as.Ret();
704 as.Finalize();
705
706 ScopedExecRegion exec(&code);
707
708 using TestFunc = int(int, int);
709 auto target_func = exec.get<TestFunc>();
710 int result = target_func(1, 1);
711 if (result != 0) {
712 ALOGE("Bug in jcc(equal): %x", result);
713 return false;
714 }
715 result = target_func(1, 0);
716 if (result != 1) {
717 ALOGE("Bug in jcc(above): %x", result);
718 return false;
719 }
720 result = target_func(0, 1);
721 if (result != -1) {
722 ALOGE("Bug in jcc(below): %x", result);
723 return false;
724 }
725 return true;
726 }
727
ShiftTest()728 bool ShiftTest() {
729 MachineCode code;
730 CodeEmitter as(&code);
731 as.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
732 as.Shll(Assembler::eax, int8_t{2});
733 as.Shrl(Assembler::eax, int8_t{1});
734 as.Movl(Assembler::ecx, 3);
735 as.ShllByCl(Assembler::eax);
736 as.Ret();
737 as.Finalize();
738
739 ScopedExecRegion exec(&code);
740
741 using TestFunc = uint32_t(uint32_t);
742 uint32_t result = exec.get<TestFunc>()(22);
743 return result == (22 << 4);
744 }
745
LogicTest()746 bool LogicTest() {
747 MachineCode code;
748 CodeEmitter as(&code);
749 as.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
750 as.Movl(Assembler::ecx, 0x1);
751 as.Xorl(Assembler::eax, Assembler::ecx);
752 as.Movl(Assembler::ecx, 0xf);
753 as.Andl(Assembler::eax, Assembler::ecx);
754 as.Ret();
755 as.Finalize();
756
757 ScopedExecRegion exec(&code);
758
759 using TestFunc = uint32_t(uint32_t);
760 uint32_t result = exec.get<TestFunc>()(239);
761 return result == ((239 ^ 1) & 0xf);
762 }
763
BsrTest()764 bool BsrTest() {
765 MachineCode code;
766 CodeEmitter as(&code);
767
768 as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 4});
769 as.Movl(Assembler::edx, 239);
770 as.Bsrl(Assembler::eax, Assembler::ecx);
771 as.Cmovl(Assembler::Condition::kZero, Assembler::eax, Assembler::edx);
772 as.Ret();
773 as.Finalize();
774
775 ScopedExecRegion exec(&code);
776
777 using TestFunc = uint32_t(uint32_t arg);
778 auto func = exec.get<TestFunc>();
779 return func(0) == 239 && func(1 << 15) == 15;
780 }
781
CallFPTest()782 bool CallFPTest() {
783 MachineCode code;
784 CodeEmitter as(&code);
785 as.Push(0x3f800000);
786 as.Push(0x40000000);
787 as.Call(bit_cast<const void*>(&FloatFunc));
788 as.Fstps({.base = Assembler::esp});
789 as.Pop(Assembler::eax);
790 as.Addl(Assembler::esp, 4);
791 as.Ret();
792 as.Finalize();
793
794 ScopedExecRegion exec(&code);
795
796 using TestFunc = uint32_t();
797 uint32_t result = exec.get<TestFunc>()();
798 return result == 0x3f800000;
799 }
800
XmmTest()801 bool XmmTest() {
802 MachineCode code;
803 CodeEmitter as(&code);
804 as.Movl(Assembler::eax, 0x3f800000);
805 as.Movd(Assembler::xmm0, Assembler::eax);
806 as.Movl(Assembler::eax, 0x40000000);
807 as.Movd(Assembler::xmm5, Assembler::eax);
808 as.Addss(Assembler::xmm0, Assembler::xmm5);
809 as.Movd(Assembler::eax, Assembler::xmm0);
810 as.Ret();
811 as.Finalize();
812
813 ScopedExecRegion exec(&code);
814
815 using TestFunc = uint32_t();
816 uint32_t result = exec.get<TestFunc>()();
817 return result == 0x40400000;
818 }
819
ReadGlobalTest()820 bool ReadGlobalTest() {
821 MachineCode code;
822 CodeEmitter as(&code);
823 static const uint32_t kData[] __attribute__((aligned(16))) = // NOLINT
824 {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
825 as.Movsd(Assembler::xmm0, {.disp = bit_cast<int32_t>(&kData)});
826 as.Movdqa(Assembler::xmm1, {.disp = bit_cast<int32_t>(&kData)});
827 as.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
828 as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8});
829 as.Movsd({.base = Assembler::eax}, Assembler::xmm0);
830 as.Movdqu({.base = Assembler::ecx}, Assembler::xmm1);
831
832 as.Ret();
833 as.Finalize();
834
835 ScopedExecRegion exec(&code);
836
837 using TestFunc = void(void*, void*);
838 uint8_t res1[8];
839 uint8_t res2[16];
840 exec.get<TestFunc>()(res1, res2);
841
842 return (memcmp(res1, kData, 8) == 0) && (memcmp(res2, kData, 16) == 0);
843 }
844
845 } // namespace x86_32
846
847 #elif defined(__amd64__)
848
849 namespace x86_64 {
850
LabelTest()851 bool LabelTest() {
852 MachineCode code;
853 CodeEmitter as(&code);
854 Assembler::Label skip, skip2, back, end;
855 as.Call(bit_cast<const void*>(&Callee));
856 as.Jmp(skip);
857 as.Movl(Assembler::rax, 2);
858 as.Bind(&skip);
859 as.Addb(Assembler::rax, {end});
860 as.Jmp(skip2);
861 as.Bind(&back);
862 as.Addl(Assembler::rax, 12);
863 as.Jmp(end);
864 as.Bind(&skip2);
865 as.Jmp(back);
866 as.Bind(&end);
867 as.Ret();
868 as.Finalize();
869
870 ScopedExecRegion exec(&code);
871
872 using TestFunc = int();
873 int result = exec.get<TestFunc>()();
874 return result == uint8_t(239 + 0xc3) + 12;
875 }
876
CondTest1()877 bool CondTest1() {
878 MachineCode code;
879 CodeEmitter as(&code);
880 as.Movl(Assembler::rax, 0xcccccccc);
881 as.Cmpl(Assembler::rdi, Assembler::rsi);
882 as.Setcc(Assembler::Condition::kEqual, Assembler::rax);
883 as.Ret();
884 as.Finalize();
885
886 ScopedExecRegion exec(&code);
887
888 std::string code_str;
889 code.AsString(&code_str, InstructionSize::OneByte);
890 using TestFunc = uint32_t(int, int);
891 auto target_func = exec.get<TestFunc>();
892 uint32_t result;
893 result = target_func(1, 2);
894 if (result != 0xcccccc00) {
895 ALOGE("Bug in seteq(not equal): %x", result);
896 return false;
897 }
898 result = target_func(-1, -1);
899 if (result != 0xcccccc01) {
900 ALOGE("Bug in seteq(equal): %x", result);
901 return false;
902 }
903 return true;
904 }
905
CondTest2()906 bool CondTest2() {
907 MachineCode code;
908 CodeEmitter as(&code);
909 as.Movl(Assembler::rdx, Assembler::rdi); // arg1.
910 as.Movl(Assembler::rcx, Assembler::rsi); // arg2.
911 as.Xorl(Assembler::rax, Assembler::rax);
912 as.Testb(Assembler::rdx, Assembler::rcx);
913 as.Setcc(Assembler::Condition::kNotZero, Assembler::rax);
914 as.Xchgq(Assembler::rax, Assembler::rcx);
915 as.Xchgq(Assembler::rcx, Assembler::rax);
916 as.Xchgq(Assembler::rcx, Assembler::r11);
917 as.Xchgq(Assembler::r11, Assembler::rcx);
918 as.Ret();
919 as.Finalize();
920
921 ScopedExecRegion exec(&code);
922
923 using TestFunc = uint32_t(int, int);
924 auto target_func = exec.get<TestFunc>();
925 uint32_t result = target_func(0x11, 1);
926 if (result != 0x1) {
927 printf("Bug in testb(not zero): %x", result);
928 return false;
929 }
930 result = target_func(0x11, 0x8);
931 if (result != 0x0) {
932 printf("Bug in testb(zero): %x", result);
933 return false;
934 }
935 return true;
936 }
937
JccTest()938 bool JccTest() {
939 MachineCode code;
940 CodeEmitter as(&code);
941 Assembler::Label equal, above, below, done;
942 as.Cmpl(Assembler::rdi, Assembler::rsi);
943 as.Jcc(Assembler::Condition::kEqual, equal);
944 as.Jcc(Assembler::Condition::kBelow, below);
945 as.Jcc(Assembler::Condition::kAbove, above);
946
947 as.Movl(Assembler::rax, 13);
948 as.Jmp(done);
949
950 as.Bind(&equal);
951 as.Movq(Assembler::rax, 0);
952 as.Jmp(done);
953
954 as.Bind(&below);
955 as.Movl(Assembler::rax, -1);
956 as.Jmp(done);
957
958 as.Bind(&above);
959 as.Movl(Assembler::rax, 1);
960 as.Jmp(done);
961
962 as.Bind(&done);
963 as.Ret();
964 as.Finalize();
965
966 ScopedExecRegion exec(&code);
967
968 using TestFunc = int(int, int);
969 auto target_func = exec.get<TestFunc>();
970 int result;
971 result = target_func(1, 1);
972 if (result != 0) {
973 ALOGE("Bug in jcc(equal): %x", result);
974 return false;
975 }
976 result = target_func(1, 0);
977 if (result != 1) {
978 ALOGE("Bug in jcc(above): %x", result);
979 return false;
980 }
981 result = target_func(0, 1);
982 if (result != -1) {
983 ALOGE("Bug in jcc(below): %x", result);
984 return false;
985 }
986 return true;
987 }
988
ReadWriteTest()989 bool ReadWriteTest() {
990 MachineCode code;
991 CodeEmitter as(&code);
992
993 as.Movq(Assembler::rax, 0);
994 as.Movb(Assembler::rax, {.base = Assembler::rdi});
995 as.Movl(Assembler::rcx, {.base = Assembler::rsi});
996 as.Addl(Assembler::rax, Assembler::rcx);
997 as.Movl({.base = Assembler::rsi}, Assembler::rax);
998 as.Ret();
999 as.Finalize();
1000
1001 ScopedExecRegion exec(&code);
1002
1003 using TestFunc = uint32_t(uint8_t*, uint32_t*);
1004 uint8_t p1[4] = {0x12, 0x34, 0x56, 0x78};
1005 uint32_t p2 = 0x239;
1006 uint32_t result = exec.get<TestFunc>()(p1, &p2);
1007 return (result == 0x239 + 0x12) && (p2 == result);
1008 }
1009
CallFPTest()1010 bool CallFPTest() {
1011 MachineCode code;
1012 CodeEmitter as(&code);
1013 as.Movl(Assembler::rax, 0x40000000);
1014 as.Movd(Assembler::xmm0, Assembler::rax);
1015 as.Movl(Assembler::rax, 0x3f800000);
1016 as.Movd(Assembler::xmm1, Assembler::rax);
1017 as.Call(bit_cast<const void*>(&FloatFunc));
1018 as.Movd(Assembler::rax, Assembler::xmm0);
1019 as.Ret();
1020 as.Finalize();
1021
1022 ScopedExecRegion exec(&code);
1023
1024 using TestFunc = uint32_t();
1025 uint32_t result = exec.get<TestFunc>()();
1026 return result == 0x3f800000;
1027 }
1028
XmmTest()1029 bool XmmTest() {
1030 MachineCode code;
1031 CodeEmitter as(&code);
1032 as.Movl(Assembler::rax, 0x40000000);
1033 as.Movd(Assembler::xmm0, Assembler::rax);
1034 as.Movl(Assembler::rax, 0x3f800000);
1035 as.Movd(Assembler::xmm11, Assembler::rax);
1036 as.Addss(Assembler::xmm0, Assembler::xmm11);
1037 as.Movaps(Assembler::xmm12, Assembler::xmm0);
1038 as.Addss(Assembler::xmm0, Assembler::xmm12);
1039 as.Movapd(Assembler::xmm14, Assembler::xmm1);
1040 as.Movd(Assembler::rax, Assembler::xmm0);
1041 as.Ret();
1042 as.Finalize();
1043
1044 ScopedExecRegion exec(&code);
1045
1046 using TestFunc = uint32_t();
1047 uint32_t result = exec.get<TestFunc>()();
1048 return result == 0x40c00000;
1049 }
1050
XmmMemTest()1051 bool XmmMemTest() {
1052 MachineCode code;
1053 CodeEmitter as(&code);
1054
1055 as.Movsd(Assembler::xmm0, {.base = Assembler::rdi});
1056 as.Movaps(Assembler::xmm12, Assembler::xmm0);
1057 as.Addsd(Assembler::xmm12, Assembler::xmm12);
1058 as.Movsd({.base = Assembler::rdi}, Assembler::xmm12);
1059 as.Movq(Assembler::rax, Assembler::xmm0);
1060 as.Ret();
1061 as.Finalize();
1062
1063 ScopedExecRegion exec(&code);
1064
1065 double d = 239.0;
1066 char bits[16], *p = bits + 5;
1067 memcpy(p, &d, sizeof(d));
1068
1069 using TestFunc = uint64_t(char* p);
1070 uint64_t result = exec.get<TestFunc>()(p);
1071 uint64_t doubled = *reinterpret_cast<uint64_t*>(p);
1072 return result == 0x406de00000000000ULL && doubled == 0x407de00000000000ULL;
1073 }
1074
MovsxblRexTest()1075 bool MovsxblRexTest() {
1076 MachineCode code;
1077 CodeEmitter as(&code);
1078
1079 as.Xorl(Assembler::rdx, Assembler::rdx);
1080 as.Movl(Assembler::rsi, 0xdeadff);
1081 // CodeEmitter should use REX prefix to encode SIL.
1082 // Without REX DH is used.
1083 as.Movsxbl(Assembler::rax, Assembler::rsi);
1084 as.Ret();
1085 as.Finalize();
1086
1087 ScopedExecRegion exec(&code);
1088
1089 using TestFunc = uint32_t();
1090 uint32_t result = exec.get<TestFunc>()();
1091
1092 return result == 0xffffffff;
1093 }
1094
MovzxblRexTest()1095 bool MovzxblRexTest() {
1096 MachineCode code;
1097 CodeEmitter as(&code);
1098
1099 as.Xorl(Assembler::rdx, Assembler::rdx);
1100 as.Movl(Assembler::rsi, 0xdeadff);
1101 // CodeEmitter should use REX prefix to encode SIL.
1102 // Without REX DH is used.
1103 as.Movzxbl(Assembler::rax, Assembler::rsi);
1104 as.Ret();
1105 as.Finalize();
1106
1107 ScopedExecRegion exec(&code);
1108
1109 using TestFunc = uint32_t();
1110 uint32_t result = exec.get<TestFunc>()();
1111
1112 return result == 0x000000ff;
1113 }
1114
ShldlRexTest()1115 bool ShldlRexTest() {
1116 MachineCode code;
1117 CodeEmitter as(&code);
1118
1119 as.Movl(Assembler::rdx, 0x12345678);
1120 // If most-significant bit is not encoded correctly with REX
1121 // RAX can be used instead R8 and R10 can be used instead RDX.
1122 // Init them all:
1123 as.Xorl(Assembler::r8, Assembler::r8);
1124 as.Movl(Assembler::rax, 0xdeadbeef);
1125 as.Movl(Assembler::r10, 0xdeadbeef);
1126
1127 as.Shldl(Assembler::r8, Assembler::rdx, int8_t{8});
1128 as.Movl(Assembler::rcx, 8);
1129 as.ShldlByCl(Assembler::r8, Assembler::rdx);
1130
1131 as.Movl(Assembler::rax, Assembler::r8);
1132
1133 as.Ret();
1134 as.Finalize();
1135
1136 ScopedExecRegion exec(&code);
1137
1138 using TestFunc = uint32_t();
1139 uint32_t result = exec.get<TestFunc>()();
1140
1141 return result == 0x1212;
1142 }
1143
ShrdlRexTest()1144 bool ShrdlRexTest() {
1145 MachineCode code;
1146 CodeEmitter as(&code);
1147
1148 as.Movl(Assembler::rdx, 0x12345678);
1149 // If most-significant bit is not encoded correctly with REX
1150 // RAX can be used instead R8 and R10 can be used instead RDX.
1151 // Init them all:
1152 as.Xorl(Assembler::r8, Assembler::r8);
1153 as.Movl(Assembler::rax, 0xdeadbeef);
1154 as.Movl(Assembler::r10, 0xdeadbeef);
1155
1156 as.Shrdl(Assembler::r8, Assembler::rdx, int8_t{8});
1157 as.Movl(Assembler::rcx, 8);
1158 as.ShrdlByCl(Assembler::r8, Assembler::rdx);
1159
1160 as.Movl(Assembler::rax, Assembler::r8);
1161
1162 as.Ret();
1163 as.Finalize();
1164
1165 ScopedExecRegion exec(&code);
1166
1167 using TestFunc = uint32_t();
1168 uint32_t result = exec.get<TestFunc>()();
1169
1170 return result == 0x78780000;
1171 }
1172
ReadGlobalTest()1173 bool ReadGlobalTest() {
1174 MachineCode code;
1175 CodeEmitter as(&code);
1176 static const uint32_t kData[] __attribute__((aligned(16))) = // NOLINT
1177 {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
1178 // We couldn't read data from arbitrary address on x86_64, need address in first 2GiB.
1179 void* data =
1180 mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
1181 // Copy our global there.
1182 memcpy(data, kData, 16);
1183 int32_t data_offset = static_cast<int32_t>(bit_cast<intptr_t>(data));
1184 as.Movsd(Assembler::xmm0, {.disp = data_offset});
1185 as.Movdqa(Assembler::xmm1, {.disp = data_offset});
1186 as.Movsd({.base = Assembler::rdi}, Assembler::xmm0);
1187 as.Movdqu({.base = Assembler::rsi}, Assembler::xmm1);
1188
1189 as.Ret();
1190 as.Finalize();
1191
1192 ScopedExecRegion exec(&code);
1193
1194 using TestFunc = void(void*, void*);
1195 uint8_t res1[8];
1196 uint8_t res2[16];
1197 exec.get<TestFunc>()(res1, res2);
1198
1199 munmap(data, 4096);
1200
1201 return (memcmp(res1, kData, 8) == 0) && (memcmp(res2, kData, 16) == 0);
1202 }
1203
MemShiftTest()1204 bool MemShiftTest() {
1205 MachineCode code;
1206 CodeEmitter as(&code);
1207
1208 as.Push(Assembler::rdi);
1209 as.Movl(Assembler::rcx, 1);
1210 as.ShrlByCl({.base = Assembler::rsp});
1211 as.Addl(Assembler::rcx, 1);
1212 as.Movq(Assembler::rdi, Assembler::rsp);
1213 as.ShllByCl({.base = Assembler::rdi});
1214 as.Pop(Assembler::rax);
1215
1216 as.Ret();
1217 as.Finalize();
1218
1219 ScopedExecRegion exec(&code);
1220
1221 using TestFunc = int(int x);
1222 int result = exec.get<TestFunc>()(0x10);
1223
1224 return result == 0x20;
1225 }
1226
1227 } // namespace x86_64
1228
1229 #endif
1230
1231 #if defined(__i386__) || defined(__amd64__)
1232
1233 #if defined(__i386__)
1234
1235 extern "C" const uint8_t berberis_gnu_as_output_start[] asm(
1236 "berberis_gnu_as_output_start_x86_32");
1237 extern "C" const uint8_t berberis_gnu_as_output_end[] asm(
1238 "berberis_gnu_as_output_end_x86_32");
1239
1240 namespace x86_32 {
1241 void GenInsnsCommon(CodeEmitter* as);
1242 void GenInsnsArch(CodeEmitter* as);
1243 } // namespace x86_32
1244
1245 #else
1246
1247 extern "C" const uint8_t berberis_gnu_as_output_start[] asm(
1248 "berberis_gnu_as_output_start_x86_64");
1249 extern "C" const uint8_t berberis_gnu_as_output_end[] asm(
1250 "berberis_gnu_as_output_end_x86_64");
1251
1252 namespace x86_64 {
1253 void GenInsnsCommon(CodeEmitter* as);
1254 void GenInsnsArch(CodeEmitter* as);
1255 } // namespace x86_64
1256
1257 #endif
1258
ExhaustiveTest()1259 bool ExhaustiveTest() {
1260 MachineCode code;
1261 CodeEmitter as(&code);
1262
1263 #if defined(__i386__)
1264 berberis::x86_32::GenInsnsCommon(&as);
1265 berberis::x86_32::GenInsnsArch(&as);
1266 #else
1267 berberis::x86_64::GenInsnsCommon(&as);
1268 berberis::x86_64::GenInsnsArch(&as);
1269 #endif
1270 as.Finalize();
1271
1272 return CompareCode(
1273 berberis_gnu_as_output_start, berberis_gnu_as_output_end, code, CPUArch::kX86_64);
1274 }
1275
MixedAssembler()1276 bool MixedAssembler() {
1277 MachineCode code;
1278 x86_32::Assembler as32(&code);
1279 x86_64::Assembler as64(&code);
1280 x86_32::Assembler::Label lbl32;
1281 x86_64::Assembler::Label lbl64;
1282
1283 as32.Jmp(lbl32);
1284 as32.Xchgl(x86_32::Assembler::eax, x86_32::Assembler::eax);
1285 as64.Jmp(lbl64);
1286 as64.Xchgl(x86_64::Assembler::rax, x86_64::Assembler::rax);
1287 as32.Bind(&lbl32);
1288 as32.Movl(x86_32::Assembler::eax, {.disp = 0});
1289 as64.Bind(&lbl64);
1290 as32.Finalize();
1291 as64.Finalize();
1292
1293 // clang-format off
1294 static const uint8_t kCodeTemplate[] = {
1295 0xe9, 0x08, 0x00, 0x00, 0x00, // jmp lbl32
1296 0x90, // xchg %eax, %eax == nop
1297 0xe9, 0x07, 0x00, 0x00, 0x00, // jmp lbl64
1298 0x87, 0xc0, // xchg %eax, %eax != nop
1299 // lbl32:
1300 0xa1, 0x00, 0x00, 0x00, 0x00 // movabs %eax, 0x0
1301 // lbl64:
1302 };
1303 // clang-format on
1304
1305 return CompareCode(std::begin(kCodeTemplate), std::end(kCodeTemplate), code, CPUArch::kX86_64);
1306 }
1307 #endif
1308
1309 } // namespace berberis
1310
TEST(Assembler,AssemblerTest)1311 TEST(Assembler, AssemblerTest) {
1312 EXPECT_TRUE(berberis::rv32::AssemblerTest());
1313 EXPECT_TRUE(berberis::rv64::AssemblerTest());
1314 EXPECT_TRUE(berberis::x86_32::AssemblerTest());
1315 EXPECT_TRUE(berberis::x86_64::AssemblerTest());
1316 #if defined(__i386__)
1317 EXPECT_TRUE(berberis::x86_32::LabelTest());
1318 EXPECT_TRUE(berberis::x86_32::CondTest1());
1319 EXPECT_TRUE(berberis::x86_32::CondTest2());
1320 EXPECT_TRUE(berberis::x86_32::JccTest());
1321 EXPECT_TRUE(berberis::x86_32::ShiftTest());
1322 EXPECT_TRUE(berberis::x86_32::LogicTest());
1323 EXPECT_TRUE(berberis::x86_32::CallFPTest());
1324 EXPECT_TRUE(berberis::x86_32::XmmTest());
1325 EXPECT_TRUE(berberis::x86_32::BsrTest());
1326 EXPECT_TRUE(berberis::x86_32::ReadGlobalTest());
1327 #elif defined(__amd64__)
1328 EXPECT_TRUE(berberis::x86_64::LabelTest());
1329 EXPECT_TRUE(berberis::x86_64::CondTest1());
1330 EXPECT_TRUE(berberis::x86_64::CondTest2());
1331 EXPECT_TRUE(berberis::x86_64::JccTest());
1332 EXPECT_TRUE(berberis::x86_64::ReadWriteTest());
1333 EXPECT_TRUE(berberis::x86_64::CallFPTest());
1334 EXPECT_TRUE(berberis::x86_64::XmmTest());
1335 EXPECT_TRUE(berberis::x86_64::XmmMemTest());
1336 EXPECT_TRUE(berberis::x86_64::MovsxblRexTest());
1337 EXPECT_TRUE(berberis::x86_64::MovzxblRexTest());
1338 EXPECT_TRUE(berberis::x86_64::ShldlRexTest());
1339 EXPECT_TRUE(berberis::x86_64::ShrdlRexTest());
1340 EXPECT_TRUE(berberis::x86_64::ReadGlobalTest());
1341 EXPECT_TRUE(berberis::x86_64::MemShiftTest());
1342 #endif
1343 // Currently we don't support these tests for riscv.
1344 // TODO(b/352784623): Implement for riscv.
1345 #if defined(__i386__) || defined(__x86_64__)
1346 EXPECT_TRUE(berberis::ExhaustiveTest());
1347 EXPECT_TRUE(berberis::MixedAssembler());
1348 #endif
1349 }
1350