blob: 93473fb4c7513eee5bbd6d9ec357b4dea091c30c [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
Chris Larsendbce0d72015-09-17 13:34:00 -0700141 template <typename Reg1Type, typename Reg2Type, typename ImmType,
142 RegisterView Reg1View, RegisterView Reg2View>
143 std::string RepeatRegRegImmBits(void (Ass::*f)(Reg1Type, Reg2Type, ImmType),
144 int imm_bits,
145 std::string fmt) {
146 const std::vector<Reg1Type*> reg1_registers = GetRegisters();
147 const std::vector<Reg2Type*> reg2_registers = GetRegisters();
148 std::string str;
149 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0);
150
151 for (auto reg1 : reg1_registers) {
152 for (auto reg2 : reg2_registers) {
153 for (int64_t imm : imms) {
154 ImmType new_imm = CreateImmediate(imm);
155 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
156 std::string base = fmt;
157
158 std::string reg1_string = GetRegName<Reg1View>(*reg1);
159 size_t reg1_index;
160 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
161 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
162 }
163
164 std::string reg2_string = GetRegName<Reg2View>(*reg2);
165 size_t reg2_index;
166 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
167 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
168 }
169
170 size_t imm_index = base.find(IMM_TOKEN);
171 if (imm_index != std::string::npos) {
172 std::ostringstream sreg;
173 sreg << imm;
174 std::string imm_string = sreg.str();
175 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
176 }
177
178 if (str.size() > 0) {
179 str += "\n";
180 }
181 str += base;
182 }
183 }
184 }
185 // Add a newline at the end.
186 str += "\n";
187 return str;
188 }
189
190 template <typename Reg1Type, typename Reg2Type, typename ImmType>
191 std::string RepeatRRIb(void (Ass::*f)(Reg1Type, Reg2Type, ImmType),
192 int imm_bits,
193 std::string fmt) {
194 return RepeatRegRegImmBits<Reg1Type,
195 Reg2Type,
196 ImmType,
197 RegisterView::kUsePrimaryName,
198 RegisterView::kUsePrimaryName>(f, imm_bits, fmt);
199 }
200
Andreas Gampe851df202014-11-12 14:05:46 -0800201 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
202 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
203 GetFPRegisters(),
204 GetFPRegisters(),
205 &AssemblerTest::GetFPRegName,
206 &AssemblerTest::GetFPRegName,
207 fmt);
208 }
209
Chris Larsendbce0d72015-09-17 13:34:00 -0700210 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), std::string fmt) {
211 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
212 GetFPRegisters(),
213 GetFPRegisters(),
214 GetFPRegisters(),
215 &AssemblerTest::GetFPRegName,
216 &AssemblerTest::GetFPRegName,
217 &AssemblerTest::GetFPRegName,
218 fmt);
219 }
220
221 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
222 size_t imm_bytes,
223 std::string fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400224 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700225 GetFPRegisters(),
226 GetFPRegisters(),
227 &AssemblerTest::GetFPRegName,
228 &AssemblerTest::GetFPRegName,
229 imm_bytes,
230 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400231 }
232
Andreas Gampe851df202014-11-12 14:05:46 -0800233 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
234 return RepeatTemplatedRegisters<FPReg, Reg>(f,
235 GetFPRegisters(),
236 GetRegisters(),
237 &AssemblerTest::GetFPRegName,
238 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
239 fmt);
240 }
241
242 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), std::string fmt) {
243 return RepeatTemplatedRegisters<FPReg, Reg>(f,
244 GetFPRegisters(),
245 GetRegisters(),
246 &AssemblerTest::GetFPRegName,
247 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
248 fmt);
249 }
250
251 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
252 return RepeatTemplatedRegisters<Reg, FPReg>(f,
253 GetRegisters(),
254 GetFPRegisters(),
255 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
256 &AssemblerTest::GetFPRegName,
257 fmt);
258 }
259
260 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
261 return RepeatTemplatedRegisters<Reg, FPReg>(f,
262 GetRegisters(),
263 GetFPRegisters(),
264 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
265 &AssemblerTest::GetFPRegName,
266 fmt);
267 }
268
269 std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt,
270 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700271 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800272 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800273
274 WarnOnCombinations(imms.size());
275
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700276 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700277 Imm new_imm = CreateImmediate(imm);
278 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700279 std::string base = fmt;
280
Andreas Gampe851df202014-11-12 14:05:46 -0800281 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700282 if (imm_index != std::string::npos) {
283 std::ostringstream sreg;
284 sreg << imm;
285 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800286 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700287 }
288
289 if (str.size() > 0) {
290 str += "\n";
291 }
292 str += base;
293 }
294 // Add a newline at the end.
295 str += "\n";
296 return str;
297 }
298
299 // This is intended to be run as a test.
300 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700301 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700302 }
303
Andreas Gampe851df202014-11-12 14:05:46 -0800304 // The following functions are public so that TestFn can use them...
305
306 virtual std::vector<Reg*> GetRegisters() = 0;
307
308 virtual std::vector<FPReg*> GetFPRegisters() {
309 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
310 UNREACHABLE();
311 }
312
313 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
314 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
315 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
316 UNREACHABLE();
317 }
318
Chao-ying Fud23840d2015-04-07 16:03:04 -0700319 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
320 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
321 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
322 UNREACHABLE();
323 }
324
325 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
326 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
327 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
328 UNREACHABLE();
329 }
330
Calin Juravle9aec02f2014-11-18 23:06:35 +0000331 std::string GetRegisterName(const Reg& reg) {
332 return GetRegName<RegisterView::kUsePrimaryName>(reg);
333 }
334
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700335 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800336 explicit AssemblerTest() {}
337
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700338 void SetUp() OVERRIDE {
339 assembler_.reset(new Ass());
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700340 test_helper_.reset(
341 new AssemblerTestInfrastructure(GetArchitectureString(),
342 GetAssemblerCmdName(),
343 GetAssemblerParameters(),
344 GetObjdumpCmdName(),
345 GetObjdumpParameters(),
346 GetDisassembleCmdName(),
347 GetDisassembleParameters(),
348 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700349
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700350 SetUpHelpers();
351 }
352
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700353 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700354 test_helper_.reset(); // Clean up the helper.
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700355 }
356
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700357 // Override this to set up any architecture-specific things, e.g., register vectors.
358 virtual void SetUpHelpers() {}
359
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700360 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
361 virtual std::string GetArchitectureString() = 0;
362
363 // Get the name of the assembler, e.g., "as" by default.
364 virtual std::string GetAssemblerCmdName() {
365 return "as";
366 }
367
368 // Switches to the assembler command. Default none.
369 virtual std::string GetAssemblerParameters() {
370 return "";
371 }
372
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700373 // Get the name of the objdump, e.g., "objdump" by default.
374 virtual std::string GetObjdumpCmdName() {
375 return "objdump";
376 }
377
378 // Switches to the objdump command. Default is " -h".
379 virtual std::string GetObjdumpParameters() {
380 return " -h";
381 }
382
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700383 // Get the name of the objdump, e.g., "objdump" by default.
384 virtual std::string GetDisassembleCmdName() {
385 return "objdump";
386 }
387
388 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
389 // such to objdump, so it's architecture-specific and there is no default.
390 virtual std::string GetDisassembleParameters() = 0;
391
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700392 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800393 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700394 std::vector<int64_t> res;
395 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800396 if (!as_uint) {
397 res.push_back(-1);
398 } else {
399 res.push_back(0xFF);
400 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700401 res.push_back(0x12);
402 if (imm_bytes >= 2) {
403 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800404 if (!as_uint) {
405 res.push_back(-0x1234);
406 } else {
407 res.push_back(0xFFFF);
408 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700409 if (imm_bytes >= 4) {
410 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800411 if (!as_uint) {
412 res.push_back(-0x12345678);
413 } else {
414 res.push_back(0xFFFFFFFF);
415 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700416 if (imm_bytes >= 6) {
417 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800418 if (!as_uint) {
419 res.push_back(-0x123456789ABC);
420 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700421 if (imm_bytes >= 8) {
422 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800423 if (!as_uint) {
424 res.push_back(-0x123456789ABCDEF0);
425 } else {
426 res.push_back(0xFFFFFFFFFFFFFFFF);
427 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700428 }
429 }
430 }
431 }
432 return res;
433 }
434
Chris Larsendbce0d72015-09-17 13:34:00 -0700435 const int kMaxBitsExhaustiveTest = 8;
436
437 // Create a couple of immediate values up to the number of bits given.
438 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
439 CHECK_GT(imm_bits, 0);
440 CHECK_LE(imm_bits, 64);
441 std::vector<int64_t> res;
442
443 if (imm_bits <= kMaxBitsExhaustiveTest) {
444 if (as_uint) {
445 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
446 res.push_back(static_cast<int64_t>(i));
447 }
448 } else {
449 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
450 res.push_back(i);
451 }
452 }
453 } else {
454 if (as_uint) {
455 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
456 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
457 i++) {
458 res.push_back(static_cast<int64_t>(i));
459 }
460 for (int i = 0; i <= imm_bits; i++) {
461 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
462 ((MaxInt<uint64_t>(imm_bits) -
463 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
464 * i / imm_bits);
465 res.push_back(static_cast<int64_t>(j));
466 }
467 } else {
468 for (int i = 0; i <= imm_bits; i++) {
469 int64_t j = MinInt<int64_t>(imm_bits) +
470 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
471 MinInt<int64_t>(imm_bits))
472 * i) / imm_bits);
473 res.push_back(static_cast<int64_t>(j));
474 }
475 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
476 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
477 i++) {
478 res.push_back(static_cast<int64_t>(i));
479 }
480 for (int i = 0; i <= imm_bits; i++) {
481 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
482 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
483 * i / imm_bits);
484 res.push_back(static_cast<int64_t>(j));
485 }
486 }
487 }
488
489 return res;
490 }
491
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700492 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700493 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700494
Andreas Gampe851df202014-11-12 14:05:46 -0800495 template <typename RegType>
496 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
497 const std::vector<RegType*> registers,
498 std::string (AssemblerTest::*GetName)(const RegType&),
499 std::string fmt) {
500 std::string str;
501 for (auto reg : registers) {
502 (assembler_.get()->*f)(*reg);
503 std::string base = fmt;
504
505 std::string reg_string = (this->*GetName)(*reg);
506 size_t reg_index;
507 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
508 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
509 }
510
511 if (str.size() > 0) {
512 str += "\n";
513 }
514 str += base;
515 }
516 // Add a newline at the end.
517 str += "\n";
518 return str;
519 }
520
521 template <typename Reg1, typename Reg2>
522 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
523 const std::vector<Reg1*> reg1_registers,
524 const std::vector<Reg2*> reg2_registers,
525 std::string (AssemblerTest::*GetName1)(const Reg1&),
526 std::string (AssemblerTest::*GetName2)(const Reg2&),
527 std::string fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800528 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
529
Andreas Gampe851df202014-11-12 14:05:46 -0800530 std::string str;
531 for (auto reg1 : reg1_registers) {
532 for (auto reg2 : reg2_registers) {
533 (assembler_.get()->*f)(*reg1, *reg2);
534 std::string base = fmt;
535
536 std::string reg1_string = (this->*GetName1)(*reg1);
537 size_t reg1_index;
538 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
539 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
540 }
541
542 std::string reg2_string = (this->*GetName2)(*reg2);
543 size_t reg2_index;
544 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
545 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
546 }
547
548 if (str.size() > 0) {
549 str += "\n";
550 }
551 str += base;
552 }
553 }
554 // Add a newline at the end.
555 str += "\n";
556 return str;
557 }
558
Chris Larsen51417632015-10-02 13:24:25 -0700559 template <typename Reg1, typename Reg2>
560 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
561 const std::vector<Reg1*> reg1_registers,
562 const std::vector<Reg2*> reg2_registers,
563 std::string (AssemblerTest::*GetName1)(const Reg1&),
564 std::string (AssemblerTest::*GetName2)(const Reg2&),
565 std::string fmt) {
566 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
567
568 std::string str;
569 for (auto reg1 : reg1_registers) {
570 for (auto reg2 : reg2_registers) {
571 if (reg1 == reg2) continue;
572 (assembler_.get()->*f)(*reg1, *reg2);
573 std::string base = fmt;
574
575 std::string reg1_string = (this->*GetName1)(*reg1);
576 size_t reg1_index;
577 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
578 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
579 }
580
581 std::string reg2_string = (this->*GetName2)(*reg2);
582 size_t reg2_index;
583 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
584 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
585 }
586
587 if (str.size() > 0) {
588 str += "\n";
589 }
590 str += base;
591 }
592 }
593 // Add a newline at the end.
594 str += "\n";
595 return str;
596 }
597
Chris Larsendbce0d72015-09-17 13:34:00 -0700598 template <typename Reg1, typename Reg2, typename Reg3>
599 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
600 const std::vector<Reg1*> reg1_registers,
601 const std::vector<Reg2*> reg2_registers,
602 const std::vector<Reg3*> reg3_registers,
603 std::string (AssemblerTest::*GetName1)(const Reg1&),
604 std::string (AssemblerTest::*GetName2)(const Reg2&),
605 std::string (AssemblerTest::*GetName3)(const Reg3&),
606 std::string fmt) {
607 std::string str;
608 for (auto reg1 : reg1_registers) {
609 for (auto reg2 : reg2_registers) {
610 for (auto reg3 : reg3_registers) {
611 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
612 std::string base = fmt;
613
614 std::string reg1_string = (this->*GetName1)(*reg1);
615 size_t reg1_index;
616 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
617 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
618 }
619
620 std::string reg2_string = (this->*GetName2)(*reg2);
621 size_t reg2_index;
622 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
623 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
624 }
625
626 std::string reg3_string = (this->*GetName3)(*reg3);
627 size_t reg3_index;
628 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
629 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
630 }
631
632 if (str.size() > 0) {
633 str += "\n";
634 }
635 str += base;
636 }
637 }
638 }
639 // Add a newline at the end.
640 str += "\n";
641 return str;
642 }
643
Mark Mendellfb8d2792015-03-31 22:16:59 -0400644 template <typename Reg1, typename Reg2>
645 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
646 const std::vector<Reg1*> reg1_registers,
647 const std::vector<Reg2*> reg2_registers,
648 std::string (AssemblerTest::*GetName1)(const Reg1&),
649 std::string (AssemblerTest::*GetName2)(const Reg2&),
650 size_t imm_bytes,
651 std::string fmt) {
652 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
653 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
654
655 std::string str;
656 for (auto reg1 : reg1_registers) {
657 for (auto reg2 : reg2_registers) {
658 for (int64_t imm : imms) {
659 Imm new_imm = CreateImmediate(imm);
660 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
661 std::string base = fmt;
662
663 std::string reg1_string = (this->*GetName1)(*reg1);
664 size_t reg1_index;
665 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
666 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
667 }
668
669 std::string reg2_string = (this->*GetName2)(*reg2);
670 size_t reg2_index;
671 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
672 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
673 }
674
675 size_t imm_index = base.find(IMM_TOKEN);
676 if (imm_index != std::string::npos) {
677 std::ostringstream sreg;
678 sreg << imm;
679 std::string imm_string = sreg.str();
680 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
681 }
682
683 if (str.size() > 0) {
684 str += "\n";
685 }
686 str += base;
687 }
688 }
689 }
690 // Add a newline at the end.
691 str += "\n";
692 return str;
693 }
694
Andreas Gampe851df202014-11-12 14:05:46 -0800695 template <RegisterView kRegView>
696 std::string GetRegName(const Reg& reg) {
697 std::ostringstream sreg;
698 switch (kRegView) {
699 case RegisterView::kUsePrimaryName:
700 sreg << reg;
701 break;
702
703 case RegisterView::kUseSecondaryName:
704 sreg << GetSecondaryRegisterName(reg);
705 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -0700706
707 case RegisterView::kUseTertiaryName:
708 sreg << GetTertiaryRegisterName(reg);
709 break;
710
711 case RegisterView::kUseQuaternaryName:
712 sreg << GetQuaternaryRegisterName(reg);
713 break;
Andreas Gampe851df202014-11-12 14:05:46 -0800714 }
715 return sreg.str();
716 }
717
718 std::string GetFPRegName(const FPReg& reg) {
719 std::ostringstream sreg;
720 sreg << reg;
721 return sreg.str();
722 }
723
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800724 // If the assembly file needs a header, return it in a sub-class.
725 virtual const char* GetAssemblyHeader() {
726 return nullptr;
727 }
728
729 void WarnOnCombinations(size_t count) {
730 if (count > kWarnManyCombinationsThreshold) {
731 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
732 }
733 }
734
735 static constexpr const char* REG_TOKEN = "{reg}";
736 static constexpr const char* REG1_TOKEN = "{reg1}";
737 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -0700738 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800739 static constexpr const char* IMM_TOKEN = "{imm}";
740
741 private:
Andreas Gampe851df202014-11-12 14:05:46 -0800742 template <RegisterView kRegView>
743 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
744 std::string fmt) {
745 const std::vector<Reg*> registers = GetRegisters();
746 std::string str;
747 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800748
749 WarnOnCombinations(registers.size() * imms.size());
750
Andreas Gampe851df202014-11-12 14:05:46 -0800751 for (auto reg : registers) {
752 for (int64_t imm : imms) {
753 Imm new_imm = CreateImmediate(imm);
754 (assembler_.get()->*f)(*reg, new_imm);
755 std::string base = fmt;
756
757 std::string reg_string = GetRegName<kRegView>(*reg);
758 size_t reg_index;
759 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
760 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
761 }
762
763 size_t imm_index = base.find(IMM_TOKEN);
764 if (imm_index != std::string::npos) {
765 std::ostringstream sreg;
766 sreg << imm;
767 std::string imm_string = sreg.str();
768 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
769 }
770
771 if (str.size() > 0) {
772 str += "\n";
773 }
774 str += base;
775 }
776 }
777 // Add a newline at the end.
778 str += "\n";
779 return str;
780 }
781
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700782 void DriverWrapper(std::string assembly_text, std::string test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000783 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700784 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700785 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700786 MemoryRegion code(&(*data)[0], data->size());
787 assembler_->FinalizeInstructions(code);
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700788 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700789 }
790
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800791 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -0800792
Ian Rogers700a4022014-05-19 16:49:03 -0700793 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700794 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700795
Andreas Gampe851df202014-11-12 14:05:46 -0800796 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700797};
798
799} // namespace art
800
801#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_