blob: 9c652804074d71f2fda8765f0e72b14c71aa7567 [file] [log] [blame]
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001/*
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#ifndef ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
18#define ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
19
20#include "assembler.h"
21
Andreas Gampe03b9ee42015-04-24 21:41:45 -070022#include "assembler_test_base.h"
Andreas Gampeb40c6a72014-05-02 14:25:12 -070023#include "common_runtime_test.h" // For ScratchFile
Andreas Gampe5a4fa822014-03-31 16:50:12 -070024
25#include <cstdio>
26#include <cstdlib>
27#include <fstream>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070028#include <iterator>
29#include <sys/stat.h>
30
31namespace art {
32
Andreas Gampe851df202014-11-12 14:05:46 -080033// Helper for a constexpr string length.
34constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
35 return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
36}
37
Andreas Gampe849cc5e2014-11-18 13:46:46 -080038enum class RegisterView { // private
39 kUsePrimaryName,
Chao-ying Fud23840d2015-04-07 16:03:04 -070040 kUseSecondaryName,
41 kUseTertiaryName,
42 kUseQuaternaryName,
Andreas Gampe849cc5e2014-11-18 13:46:46 -080043};
44
Andreas Gampe851df202014-11-12 14:05:46 -080045template<typename Ass, typename Reg, typename FPReg, typename Imm>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070046class AssemblerTest : public testing::Test {
47 public:
48 Ass* GetAssembler() {
49 return assembler_.get();
50 }
51
Andreas Gampe851df202014-11-12 14:05:46 -080052 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070053
54 void DriverFn(TestFn f, std::string test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070055 DriverWrapper(f(this, assembler_.get()), test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070056 }
57
58 // This driver assumes the assembler has already been called.
59 void DriverStr(std::string assembly_string, std::string test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070060 DriverWrapper(assembly_string, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070061 }
62
63 std::string RepeatR(void (Ass::*f)(Reg), std::string fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080064 return RepeatTemplatedRegister<Reg>(f,
65 GetRegisters(),
66 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
67 fmt);
68 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070069
Andreas Gampe851df202014-11-12 14:05:46 -080070 std::string Repeatr(void (Ass::*f)(Reg), std::string fmt) {
71 return RepeatTemplatedRegister<Reg>(f,
72 GetRegisters(),
73 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
74 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070075 }
76
77 std::string RepeatRR(void (Ass::*f)(Reg, Reg), std::string fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080078 return RepeatTemplatedRegisters<Reg, Reg>(f,
79 GetRegisters(),
80 GetRegisters(),
81 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
82 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
83 fmt);
84 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070085
Chris Larsen51417632015-10-02 13:24:25 -070086 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), std::string fmt) {
87 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
88 GetRegisters(),
89 GetRegisters(),
90 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
91 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
92 fmt);
93 }
94
Andreas Gampe851df202014-11-12 14:05:46 -080095 std::string Repeatrr(void (Ass::*f)(Reg, Reg), std::string fmt) {
96 return RepeatTemplatedRegisters<Reg, Reg>(f,
97 GetRegisters(),
98 GetRegisters(),
99 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
100 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
101 fmt);
102 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700103
Chris Larsendbce0d72015-09-17 13:34:00 -0700104 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), std::string fmt) {
105 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
106 GetRegisters(),
107 GetRegisters(),
108 GetRegisters(),
109 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
110 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
111 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
112 fmt);
113 }
114
Chao-ying Fud23840d2015-04-07 16:03:04 -0700115 std::string Repeatrb(void (Ass::*f)(Reg, Reg), std::string fmt) {
116 return RepeatTemplatedRegisters<Reg, Reg>(f,
117 GetRegisters(),
118 GetRegisters(),
119 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
120 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
121 fmt);
122 }
123
Andreas Gampe851df202014-11-12 14:05:46 -0800124 std::string RepeatRr(void (Ass::*f)(Reg, Reg), std::string fmt) {
125 return RepeatTemplatedRegisters<Reg, Reg>(f,
126 GetRegisters(),
127 GetRegisters(),
128 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
129 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
130 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700131 }
132
133 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800134 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700135 }
136
Andreas Gampe851df202014-11-12 14:05:46 -0800137 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
138 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
139 }
140
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200141 template <typename Reg1, typename Reg2, typename ImmType>
142 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
143 int imm_bits,
144 const std::vector<Reg1*> reg1_registers,
145 const std::vector<Reg2*> reg2_registers,
146 std::string (AssemblerTest::*GetName1)(const Reg1&),
147 std::string (AssemblerTest::*GetName2)(const Reg2&),
148 std::string fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700149 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800150 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Chris Larsendbce0d72015-09-17 13:34:00 -0700151
152 for (auto reg1 : reg1_registers) {
153 for (auto reg2 : reg2_registers) {
154 for (int64_t imm : imms) {
155 ImmType new_imm = CreateImmediate(imm);
156 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
157 std::string base = fmt;
158
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200159 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700160 size_t reg1_index;
161 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
162 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
163 }
164
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200165 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700166 size_t reg2_index;
167 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
168 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
169 }
170
171 size_t imm_index = base.find(IMM_TOKEN);
172 if (imm_index != std::string::npos) {
173 std::ostringstream sreg;
174 sreg << imm;
175 std::string imm_string = sreg.str();
176 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
177 }
178
179 if (str.size() > 0) {
180 str += "\n";
181 }
182 str += base;
183 }
184 }
185 }
186 // Add a newline at the end.
187 str += "\n";
188 return str;
189 }
190
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800191 template <typename ImmType, typename Reg1, typename Reg2>
192 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
193 const std::vector<Reg1*> reg1_registers,
194 const std::vector<Reg2*> reg2_registers,
195 std::string (AssemblerTest::*GetName1)(const Reg1&),
196 std::string (AssemblerTest::*GetName2)(const Reg2&),
197 int imm_bits,
198 std::string fmt) {
199 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
200
201 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
202
203 std::string str;
204 for (auto reg1 : reg1_registers) {
205 for (auto reg2 : reg2_registers) {
206 for (int64_t imm : imms) {
207 ImmType new_imm = CreateImmediate(imm);
208 (assembler_.get()->*f)(new_imm, *reg1, *reg2);
209 std::string base = fmt;
210
211 std::string reg1_string = (this->*GetName1)(*reg1);
212 size_t reg1_index;
213 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
214 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
215 }
216
217 std::string reg2_string = (this->*GetName2)(*reg2);
218 size_t reg2_index;
219 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
220 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
221 }
222
223 size_t imm_index = base.find(IMM_TOKEN);
224 if (imm_index != std::string::npos) {
225 std::ostringstream sreg;
226 sreg << imm;
227 std::string imm_string = sreg.str();
228 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
229 }
230
231 if (str.size() > 0) {
232 str += "\n";
233 }
234 str += base;
235 }
236 }
237 }
238 // Add a newline at the end.
239 str += "\n";
240 return str;
241 }
242
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200243 template <typename RegType, typename ImmType>
244 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800245 int imm_bits,
246 const std::vector<Reg*> registers,
247 std::string (AssemblerTest::*GetName)(const RegType&),
248 std::string fmt) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200249 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800250 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200251
252 for (auto reg : registers) {
253 for (int64_t imm : imms) {
254 ImmType new_imm = CreateImmediate(imm);
255 (assembler_.get()->*f)(*reg, new_imm);
256 std::string base = fmt;
257
258 std::string reg_string = (this->*GetName)(*reg);
259 size_t reg_index;
260 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
261 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
262 }
263
264 size_t imm_index = base.find(IMM_TOKEN);
265 if (imm_index != std::string::npos) {
266 std::ostringstream sreg;
267 sreg << imm;
268 std::string imm_string = sreg.str();
269 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
270 }
271
272 if (str.size() > 0) {
273 str += "\n";
274 }
275 str += base;
276 }
277 }
278 // Add a newline at the end.
279 str += "\n";
280 return str;
281 }
282
283 template <typename ImmType>
284 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType), int imm_bits, std::string fmt) {
285 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
286 imm_bits,
287 GetRegisters(),
288 GetRegisters(),
289 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
290 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
291 fmt);
292 }
293
294 template <typename ImmType>
295 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt) {
296 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
297 imm_bits,
298 GetRegisters(),
299 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
300 fmt);
301 }
302
303 template <typename ImmType>
304 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType), int imm_bits, std::string fmt) {
305 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
306 imm_bits,
307 GetFPRegisters(),
308 GetRegisters(),
309 &AssemblerTest::GetFPRegName,
310 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
311 fmt);
Chris Larsendbce0d72015-09-17 13:34:00 -0700312 }
313
Andreas Gampe851df202014-11-12 14:05:46 -0800314 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
315 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
316 GetFPRegisters(),
317 GetFPRegisters(),
318 &AssemblerTest::GetFPRegName,
319 &AssemblerTest::GetFPRegName,
320 fmt);
321 }
322
Chris Larsendbce0d72015-09-17 13:34:00 -0700323 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), std::string fmt) {
324 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
325 GetFPRegisters(),
326 GetFPRegisters(),
327 GetFPRegisters(),
328 &AssemblerTest::GetFPRegName,
329 &AssemblerTest::GetFPRegName,
330 &AssemblerTest::GetFPRegName,
331 fmt);
332 }
333
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700334 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), std::string fmt) {
335 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
336 f,
337 GetFPRegisters(),
338 GetFPRegisters(),
339 GetRegisters(),
340 &AssemblerTest::GetFPRegName,
341 &AssemblerTest::GetFPRegName,
342 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
343 fmt);
344 }
345
Chris Larsendbce0d72015-09-17 13:34:00 -0700346 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
347 size_t imm_bytes,
348 std::string fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400349 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700350 GetFPRegisters(),
351 GetFPRegisters(),
352 &AssemblerTest::GetFPRegName,
353 &AssemblerTest::GetFPRegName,
354 imm_bytes,
355 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400356 }
357
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800358 template <typename ImmType>
Alexey Frunzea8aaf5a2016-06-27 14:48:20 -0700359 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType), int imm_bits, std::string fmt) {
360 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
361 imm_bits,
362 GetFPRegisters(),
363 GetFPRegisters(),
364 &AssemblerTest::GetFPRegName,
365 &AssemblerTest::GetFPRegName,
366 fmt);
367 }
368
369 template <typename ImmType>
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800370 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), int imm_bits, std::string fmt) {
371 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
372 GetFPRegisters(),
373 GetFPRegisters(),
374 &AssemblerTest::GetFPRegName,
375 &AssemblerTest::GetFPRegName,
376 imm_bits,
377 fmt);
378 }
379
Andreas Gampe851df202014-11-12 14:05:46 -0800380 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
381 return RepeatTemplatedRegisters<FPReg, Reg>(f,
382 GetFPRegisters(),
383 GetRegisters(),
384 &AssemblerTest::GetFPRegName,
385 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
386 fmt);
387 }
388
389 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), std::string fmt) {
390 return RepeatTemplatedRegisters<FPReg, Reg>(f,
391 GetFPRegisters(),
392 GetRegisters(),
393 &AssemblerTest::GetFPRegName,
394 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
395 fmt);
396 }
397
398 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
399 return RepeatTemplatedRegisters<Reg, FPReg>(f,
400 GetRegisters(),
401 GetFPRegisters(),
402 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
403 &AssemblerTest::GetFPRegName,
404 fmt);
405 }
406
407 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
408 return RepeatTemplatedRegisters<Reg, FPReg>(f,
409 GetRegisters(),
410 GetFPRegisters(),
411 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
412 &AssemblerTest::GetFPRegName,
413 fmt);
414 }
415
416 std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt,
417 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700418 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800419 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800420
421 WarnOnCombinations(imms.size());
422
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700423 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700424 Imm new_imm = CreateImmediate(imm);
425 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700426 std::string base = fmt;
427
Andreas Gampe851df202014-11-12 14:05:46 -0800428 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700429 if (imm_index != std::string::npos) {
430 std::ostringstream sreg;
431 sreg << imm;
432 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800433 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700434 }
435
436 if (str.size() > 0) {
437 str += "\n";
438 }
439 str += base;
440 }
441 // Add a newline at the end.
442 str += "\n";
443 return str;
444 }
445
446 // This is intended to be run as a test.
447 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700448 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700449 }
450
Andreas Gampe851df202014-11-12 14:05:46 -0800451 // The following functions are public so that TestFn can use them...
452
453 virtual std::vector<Reg*> GetRegisters() = 0;
454
455 virtual std::vector<FPReg*> GetFPRegisters() {
456 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
457 UNREACHABLE();
458 }
459
460 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
461 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
462 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
463 UNREACHABLE();
464 }
465
Chao-ying Fud23840d2015-04-07 16:03:04 -0700466 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
467 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
468 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
469 UNREACHABLE();
470 }
471
472 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
473 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
474 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
475 UNREACHABLE();
476 }
477
Calin Juravle9aec02f2014-11-18 23:06:35 +0000478 std::string GetRegisterName(const Reg& reg) {
479 return GetRegName<RegisterView::kUsePrimaryName>(reg);
480 }
481
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700482 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800483 explicit AssemblerTest() {}
484
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700485 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100486 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700487 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700488 test_helper_.reset(
489 new AssemblerTestInfrastructure(GetArchitectureString(),
490 GetAssemblerCmdName(),
491 GetAssemblerParameters(),
492 GetObjdumpCmdName(),
493 GetObjdumpParameters(),
494 GetDisassembleCmdName(),
495 GetDisassembleParameters(),
496 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700497
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700498 SetUpHelpers();
499 }
500
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700501 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700502 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100503 assembler_.reset();
504 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700505 }
506
Chris Larsen3add9cb2016-04-14 14:01:33 -0700507 // Override this to set up any architecture-specific things, e.g., CPU revision.
508 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
509 return new (arena) Ass(arena);
510 }
511
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700512 // Override this to set up any architecture-specific things, e.g., register vectors.
513 virtual void SetUpHelpers() {}
514
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700515 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
516 virtual std::string GetArchitectureString() = 0;
517
518 // Get the name of the assembler, e.g., "as" by default.
519 virtual std::string GetAssemblerCmdName() {
520 return "as";
521 }
522
523 // Switches to the assembler command. Default none.
524 virtual std::string GetAssemblerParameters() {
525 return "";
526 }
527
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700528 // Get the name of the objdump, e.g., "objdump" by default.
529 virtual std::string GetObjdumpCmdName() {
530 return "objdump";
531 }
532
533 // Switches to the objdump command. Default is " -h".
534 virtual std::string GetObjdumpParameters() {
535 return " -h";
536 }
537
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700538 // Get the name of the objdump, e.g., "objdump" by default.
539 virtual std::string GetDisassembleCmdName() {
540 return "objdump";
541 }
542
543 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
544 // such to objdump, so it's architecture-specific and there is no default.
545 virtual std::string GetDisassembleParameters() = 0;
546
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700547 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800548 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700549 std::vector<int64_t> res;
550 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800551 if (!as_uint) {
552 res.push_back(-1);
553 } else {
554 res.push_back(0xFF);
555 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700556 res.push_back(0x12);
557 if (imm_bytes >= 2) {
558 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800559 if (!as_uint) {
560 res.push_back(-0x1234);
561 } else {
562 res.push_back(0xFFFF);
563 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700564 if (imm_bytes >= 4) {
565 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800566 if (!as_uint) {
567 res.push_back(-0x12345678);
568 } else {
569 res.push_back(0xFFFFFFFF);
570 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700571 if (imm_bytes >= 6) {
572 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800573 if (!as_uint) {
574 res.push_back(-0x123456789ABC);
575 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700576 if (imm_bytes >= 8) {
577 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800578 if (!as_uint) {
579 res.push_back(-0x123456789ABCDEF0);
580 } else {
581 res.push_back(0xFFFFFFFFFFFFFFFF);
582 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700583 }
584 }
585 }
586 }
587 return res;
588 }
589
Chris Larsendbce0d72015-09-17 13:34:00 -0700590 const int kMaxBitsExhaustiveTest = 8;
591
592 // Create a couple of immediate values up to the number of bits given.
593 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
594 CHECK_GT(imm_bits, 0);
595 CHECK_LE(imm_bits, 64);
596 std::vector<int64_t> res;
597
598 if (imm_bits <= kMaxBitsExhaustiveTest) {
599 if (as_uint) {
600 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
601 res.push_back(static_cast<int64_t>(i));
602 }
603 } else {
604 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
605 res.push_back(i);
606 }
607 }
608 } else {
609 if (as_uint) {
610 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
611 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
612 i++) {
613 res.push_back(static_cast<int64_t>(i));
614 }
615 for (int i = 0; i <= imm_bits; i++) {
616 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
617 ((MaxInt<uint64_t>(imm_bits) -
618 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
619 * i / imm_bits);
620 res.push_back(static_cast<int64_t>(j));
621 }
622 } else {
623 for (int i = 0; i <= imm_bits; i++) {
624 int64_t j = MinInt<int64_t>(imm_bits) +
625 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
626 MinInt<int64_t>(imm_bits))
627 * i) / imm_bits);
628 res.push_back(static_cast<int64_t>(j));
629 }
630 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
631 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
632 i++) {
633 res.push_back(static_cast<int64_t>(i));
634 }
635 for (int i = 0; i <= imm_bits; i++) {
636 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
637 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
638 * i / imm_bits);
639 res.push_back(static_cast<int64_t>(j));
640 }
641 }
642 }
643
644 return res;
645 }
646
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700647 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700648 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700649
Andreas Gampe851df202014-11-12 14:05:46 -0800650 template <typename RegType>
651 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
652 const std::vector<RegType*> registers,
653 std::string (AssemblerTest::*GetName)(const RegType&),
654 std::string fmt) {
655 std::string str;
656 for (auto reg : registers) {
657 (assembler_.get()->*f)(*reg);
658 std::string base = fmt;
659
660 std::string reg_string = (this->*GetName)(*reg);
661 size_t reg_index;
662 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
663 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
664 }
665
666 if (str.size() > 0) {
667 str += "\n";
668 }
669 str += base;
670 }
671 // Add a newline at the end.
672 str += "\n";
673 return str;
674 }
675
676 template <typename Reg1, typename Reg2>
677 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
678 const std::vector<Reg1*> reg1_registers,
679 const std::vector<Reg2*> reg2_registers,
680 std::string (AssemblerTest::*GetName1)(const Reg1&),
681 std::string (AssemblerTest::*GetName2)(const Reg2&),
682 std::string fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800683 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
684
Andreas Gampe851df202014-11-12 14:05:46 -0800685 std::string str;
686 for (auto reg1 : reg1_registers) {
687 for (auto reg2 : reg2_registers) {
688 (assembler_.get()->*f)(*reg1, *reg2);
689 std::string base = fmt;
690
691 std::string reg1_string = (this->*GetName1)(*reg1);
692 size_t reg1_index;
693 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
694 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
695 }
696
697 std::string reg2_string = (this->*GetName2)(*reg2);
698 size_t reg2_index;
699 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
700 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
701 }
702
703 if (str.size() > 0) {
704 str += "\n";
705 }
706 str += base;
707 }
708 }
709 // Add a newline at the end.
710 str += "\n";
711 return str;
712 }
713
Chris Larsen51417632015-10-02 13:24:25 -0700714 template <typename Reg1, typename Reg2>
715 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
716 const std::vector<Reg1*> reg1_registers,
717 const std::vector<Reg2*> reg2_registers,
718 std::string (AssemblerTest::*GetName1)(const Reg1&),
719 std::string (AssemblerTest::*GetName2)(const Reg2&),
720 std::string fmt) {
721 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
722
723 std::string str;
724 for (auto reg1 : reg1_registers) {
725 for (auto reg2 : reg2_registers) {
726 if (reg1 == reg2) continue;
727 (assembler_.get()->*f)(*reg1, *reg2);
728 std::string base = fmt;
729
730 std::string reg1_string = (this->*GetName1)(*reg1);
731 size_t reg1_index;
732 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
733 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
734 }
735
736 std::string reg2_string = (this->*GetName2)(*reg2);
737 size_t reg2_index;
738 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
739 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
740 }
741
742 if (str.size() > 0) {
743 str += "\n";
744 }
745 str += base;
746 }
747 }
748 // Add a newline at the end.
749 str += "\n";
750 return str;
751 }
752
Chris Larsendbce0d72015-09-17 13:34:00 -0700753 template <typename Reg1, typename Reg2, typename Reg3>
754 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
755 const std::vector<Reg1*> reg1_registers,
756 const std::vector<Reg2*> reg2_registers,
757 const std::vector<Reg3*> reg3_registers,
758 std::string (AssemblerTest::*GetName1)(const Reg1&),
759 std::string (AssemblerTest::*GetName2)(const Reg2&),
760 std::string (AssemblerTest::*GetName3)(const Reg3&),
761 std::string fmt) {
762 std::string str;
763 for (auto reg1 : reg1_registers) {
764 for (auto reg2 : reg2_registers) {
765 for (auto reg3 : reg3_registers) {
766 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
767 std::string base = fmt;
768
769 std::string reg1_string = (this->*GetName1)(*reg1);
770 size_t reg1_index;
771 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
772 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
773 }
774
775 std::string reg2_string = (this->*GetName2)(*reg2);
776 size_t reg2_index;
777 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
778 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
779 }
780
781 std::string reg3_string = (this->*GetName3)(*reg3);
782 size_t reg3_index;
783 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
784 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
785 }
786
787 if (str.size() > 0) {
788 str += "\n";
789 }
790 str += base;
791 }
792 }
793 }
794 // Add a newline at the end.
795 str += "\n";
796 return str;
797 }
798
Mark Mendellfb8d2792015-03-31 22:16:59 -0400799 template <typename Reg1, typename Reg2>
800 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
801 const std::vector<Reg1*> reg1_registers,
802 const std::vector<Reg2*> reg2_registers,
803 std::string (AssemblerTest::*GetName1)(const Reg1&),
804 std::string (AssemblerTest::*GetName2)(const Reg2&),
805 size_t imm_bytes,
806 std::string fmt) {
807 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
808 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
809
810 std::string str;
811 for (auto reg1 : reg1_registers) {
812 for (auto reg2 : reg2_registers) {
813 for (int64_t imm : imms) {
814 Imm new_imm = CreateImmediate(imm);
815 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
816 std::string base = fmt;
817
818 std::string reg1_string = (this->*GetName1)(*reg1);
819 size_t reg1_index;
820 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
821 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
822 }
823
824 std::string reg2_string = (this->*GetName2)(*reg2);
825 size_t reg2_index;
826 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
827 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
828 }
829
830 size_t imm_index = base.find(IMM_TOKEN);
831 if (imm_index != std::string::npos) {
832 std::ostringstream sreg;
833 sreg << imm;
834 std::string imm_string = sreg.str();
835 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
836 }
837
838 if (str.size() > 0) {
839 str += "\n";
840 }
841 str += base;
842 }
843 }
844 }
845 // Add a newline at the end.
846 str += "\n";
847 return str;
848 }
849
Andreas Gampe851df202014-11-12 14:05:46 -0800850 template <RegisterView kRegView>
851 std::string GetRegName(const Reg& reg) {
852 std::ostringstream sreg;
853 switch (kRegView) {
854 case RegisterView::kUsePrimaryName:
855 sreg << reg;
856 break;
857
858 case RegisterView::kUseSecondaryName:
859 sreg << GetSecondaryRegisterName(reg);
860 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -0700861
862 case RegisterView::kUseTertiaryName:
863 sreg << GetTertiaryRegisterName(reg);
864 break;
865
866 case RegisterView::kUseQuaternaryName:
867 sreg << GetQuaternaryRegisterName(reg);
868 break;
Andreas Gampe851df202014-11-12 14:05:46 -0800869 }
870 return sreg.str();
871 }
872
873 std::string GetFPRegName(const FPReg& reg) {
874 std::ostringstream sreg;
875 sreg << reg;
876 return sreg.str();
877 }
878
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800879 // If the assembly file needs a header, return it in a sub-class.
880 virtual const char* GetAssemblyHeader() {
881 return nullptr;
882 }
883
884 void WarnOnCombinations(size_t count) {
885 if (count > kWarnManyCombinationsThreshold) {
886 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
887 }
888 }
889
890 static constexpr const char* REG_TOKEN = "{reg}";
891 static constexpr const char* REG1_TOKEN = "{reg1}";
892 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -0700893 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800894 static constexpr const char* IMM_TOKEN = "{imm}";
895
896 private:
Andreas Gampe851df202014-11-12 14:05:46 -0800897 template <RegisterView kRegView>
898 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
899 std::string fmt) {
900 const std::vector<Reg*> registers = GetRegisters();
901 std::string str;
902 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800903
904 WarnOnCombinations(registers.size() * imms.size());
905
Andreas Gampe851df202014-11-12 14:05:46 -0800906 for (auto reg : registers) {
907 for (int64_t imm : imms) {
908 Imm new_imm = CreateImmediate(imm);
909 (assembler_.get()->*f)(*reg, new_imm);
910 std::string base = fmt;
911
912 std::string reg_string = GetRegName<kRegView>(*reg);
913 size_t reg_index;
914 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
915 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
916 }
917
918 size_t imm_index = base.find(IMM_TOKEN);
919 if (imm_index != std::string::npos) {
920 std::ostringstream sreg;
921 sreg << imm;
922 std::string imm_string = sreg.str();
923 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
924 }
925
926 if (str.size() > 0) {
927 str += "\n";
928 }
929 str += base;
930 }
931 }
932 // Add a newline at the end.
933 str += "\n";
934 return str;
935 }
936
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700937 // Override this to pad the code with NOPs to a certain size if needed.
938 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
939 }
940
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700941 void DriverWrapper(std::string assembly_text, std::string test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000942 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700943 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700944 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700945 MemoryRegion code(&(*data)[0], data->size());
946 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700947 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700948 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700949 }
950
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800951 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -0800952
Vladimir Marko93205e32016-04-13 11:59:46 +0100953 ArenaPool pool_;
954 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -0700955 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700956 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700957
Andreas Gampe851df202014-11-12 14:05:46 -0800958 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700959};
960
961} // namespace art
962
963#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_