blob: a339633efe868fc1661dfeedac9559fa02abec06 [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
Andreas Gampe851df202014-11-12 14:05:46 -080086 std::string Repeatrr(void (Ass::*f)(Reg, Reg), std::string fmt) {
87 return RepeatTemplatedRegisters<Reg, Reg>(f,
88 GetRegisters(),
89 GetRegisters(),
90 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
91 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
92 fmt);
93 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070094
Chao-ying Fud23840d2015-04-07 16:03:04 -070095 std::string Repeatrb(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::kUseQuaternaryName>,
101 fmt);
102 }
103
Andreas Gampe851df202014-11-12 14:05:46 -0800104 std::string RepeatRr(void (Ass::*f)(Reg, Reg), std::string fmt) {
105 return RepeatTemplatedRegisters<Reg, Reg>(f,
106 GetRegisters(),
107 GetRegisters(),
108 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
109 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
110 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700111 }
112
113 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800114 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700115 }
116
Andreas Gampe851df202014-11-12 14:05:46 -0800117 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
118 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
119 }
120
121 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
122 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
123 GetFPRegisters(),
124 GetFPRegisters(),
125 &AssemblerTest::GetFPRegName,
126 &AssemblerTest::GetFPRegName,
127 fmt);
128 }
129
Mark Mendellfb8d2792015-03-31 22:16:59 -0400130 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&), size_t imm_bytes, std::string fmt) {
131 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
132 GetFPRegisters(),
133 GetFPRegisters(),
134 &AssemblerTest::GetFPRegName,
135 &AssemblerTest::GetFPRegName,
136 imm_bytes,
137 fmt);
138 }
139
Andreas Gampe851df202014-11-12 14:05:46 -0800140 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
141 return RepeatTemplatedRegisters<FPReg, Reg>(f,
142 GetFPRegisters(),
143 GetRegisters(),
144 &AssemblerTest::GetFPRegName,
145 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
146 fmt);
147 }
148
149 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), std::string fmt) {
150 return RepeatTemplatedRegisters<FPReg, Reg>(f,
151 GetFPRegisters(),
152 GetRegisters(),
153 &AssemblerTest::GetFPRegName,
154 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
155 fmt);
156 }
157
158 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
159 return RepeatTemplatedRegisters<Reg, FPReg>(f,
160 GetRegisters(),
161 GetFPRegisters(),
162 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
163 &AssemblerTest::GetFPRegName,
164 fmt);
165 }
166
167 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
168 return RepeatTemplatedRegisters<Reg, FPReg>(f,
169 GetRegisters(),
170 GetFPRegisters(),
171 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
172 &AssemblerTest::GetFPRegName,
173 fmt);
174 }
175
176 std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt,
177 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700178 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800179 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800180
181 WarnOnCombinations(imms.size());
182
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700183 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700184 Imm new_imm = CreateImmediate(imm);
185 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700186 std::string base = fmt;
187
Andreas Gampe851df202014-11-12 14:05:46 -0800188 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700189 if (imm_index != std::string::npos) {
190 std::ostringstream sreg;
191 sreg << imm;
192 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800193 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700194 }
195
196 if (str.size() > 0) {
197 str += "\n";
198 }
199 str += base;
200 }
201 // Add a newline at the end.
202 str += "\n";
203 return str;
204 }
205
206 // This is intended to be run as a test.
207 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700208 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700209 }
210
Andreas Gampe851df202014-11-12 14:05:46 -0800211 // The following functions are public so that TestFn can use them...
212
213 virtual std::vector<Reg*> GetRegisters() = 0;
214
215 virtual std::vector<FPReg*> GetFPRegisters() {
216 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
217 UNREACHABLE();
218 }
219
220 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
221 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
222 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
223 UNREACHABLE();
224 }
225
Chao-ying Fud23840d2015-04-07 16:03:04 -0700226 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
227 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
228 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
229 UNREACHABLE();
230 }
231
232 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
233 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
234 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
235 UNREACHABLE();
236 }
237
Calin Juravle9aec02f2014-11-18 23:06:35 +0000238 std::string GetRegisterName(const Reg& reg) {
239 return GetRegName<RegisterView::kUsePrimaryName>(reg);
240 }
241
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700242 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800243 explicit AssemblerTest() {}
244
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700245 void SetUp() OVERRIDE {
246 assembler_.reset(new Ass());
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700247 test_helper_.reset(
248 new AssemblerTestInfrastructure(GetArchitectureString(),
249 GetAssemblerCmdName(),
250 GetAssemblerParameters(),
251 GetObjdumpCmdName(),
252 GetObjdumpParameters(),
253 GetDisassembleCmdName(),
254 GetDisassembleParameters(),
255 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700256
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700257 SetUpHelpers();
258 }
259
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700260 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700261 test_helper_.reset(); // Clean up the helper.
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700262 }
263
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700264 // Override this to set up any architecture-specific things, e.g., register vectors.
265 virtual void SetUpHelpers() {}
266
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700267 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
268 virtual std::string GetArchitectureString() = 0;
269
270 // Get the name of the assembler, e.g., "as" by default.
271 virtual std::string GetAssemblerCmdName() {
272 return "as";
273 }
274
275 // Switches to the assembler command. Default none.
276 virtual std::string GetAssemblerParameters() {
277 return "";
278 }
279
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700280 // Get the name of the objdump, e.g., "objdump" by default.
281 virtual std::string GetObjdumpCmdName() {
282 return "objdump";
283 }
284
285 // Switches to the objdump command. Default is " -h".
286 virtual std::string GetObjdumpParameters() {
287 return " -h";
288 }
289
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700290 // Get the name of the objdump, e.g., "objdump" by default.
291 virtual std::string GetDisassembleCmdName() {
292 return "objdump";
293 }
294
295 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
296 // such to objdump, so it's architecture-specific and there is no default.
297 virtual std::string GetDisassembleParameters() = 0;
298
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700299 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800300 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700301 std::vector<int64_t> res;
302 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800303 if (!as_uint) {
304 res.push_back(-1);
305 } else {
306 res.push_back(0xFF);
307 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700308 res.push_back(0x12);
309 if (imm_bytes >= 2) {
310 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800311 if (!as_uint) {
312 res.push_back(-0x1234);
313 } else {
314 res.push_back(0xFFFF);
315 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700316 if (imm_bytes >= 4) {
317 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800318 if (!as_uint) {
319 res.push_back(-0x12345678);
320 } else {
321 res.push_back(0xFFFFFFFF);
322 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700323 if (imm_bytes >= 6) {
324 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800325 if (!as_uint) {
326 res.push_back(-0x123456789ABC);
327 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700328 if (imm_bytes >= 8) {
329 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800330 if (!as_uint) {
331 res.push_back(-0x123456789ABCDEF0);
332 } else {
333 res.push_back(0xFFFFFFFFFFFFFFFF);
334 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700335 }
336 }
337 }
338 }
339 return res;
340 }
341
342 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700343 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700344
Andreas Gampe851df202014-11-12 14:05:46 -0800345 template <typename RegType>
346 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
347 const std::vector<RegType*> registers,
348 std::string (AssemblerTest::*GetName)(const RegType&),
349 std::string fmt) {
350 std::string str;
351 for (auto reg : registers) {
352 (assembler_.get()->*f)(*reg);
353 std::string base = fmt;
354
355 std::string reg_string = (this->*GetName)(*reg);
356 size_t reg_index;
357 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
358 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
359 }
360
361 if (str.size() > 0) {
362 str += "\n";
363 }
364 str += base;
365 }
366 // Add a newline at the end.
367 str += "\n";
368 return str;
369 }
370
371 template <typename Reg1, typename Reg2>
372 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
373 const std::vector<Reg1*> reg1_registers,
374 const std::vector<Reg2*> reg2_registers,
375 std::string (AssemblerTest::*GetName1)(const Reg1&),
376 std::string (AssemblerTest::*GetName2)(const Reg2&),
377 std::string fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800378 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
379
Andreas Gampe851df202014-11-12 14:05:46 -0800380 std::string str;
381 for (auto reg1 : reg1_registers) {
382 for (auto reg2 : reg2_registers) {
383 (assembler_.get()->*f)(*reg1, *reg2);
384 std::string base = fmt;
385
386 std::string reg1_string = (this->*GetName1)(*reg1);
387 size_t reg1_index;
388 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
389 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
390 }
391
392 std::string reg2_string = (this->*GetName2)(*reg2);
393 size_t reg2_index;
394 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
395 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
396 }
397
398 if (str.size() > 0) {
399 str += "\n";
400 }
401 str += base;
402 }
403 }
404 // Add a newline at the end.
405 str += "\n";
406 return str;
407 }
408
Mark Mendellfb8d2792015-03-31 22:16:59 -0400409 template <typename Reg1, typename Reg2>
410 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
411 const std::vector<Reg1*> reg1_registers,
412 const std::vector<Reg2*> reg2_registers,
413 std::string (AssemblerTest::*GetName1)(const Reg1&),
414 std::string (AssemblerTest::*GetName2)(const Reg2&),
415 size_t imm_bytes,
416 std::string fmt) {
417 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
418 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
419
420 std::string str;
421 for (auto reg1 : reg1_registers) {
422 for (auto reg2 : reg2_registers) {
423 for (int64_t imm : imms) {
424 Imm new_imm = CreateImmediate(imm);
425 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
426 std::string base = fmt;
427
428 std::string reg1_string = (this->*GetName1)(*reg1);
429 size_t reg1_index;
430 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
431 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
432 }
433
434 std::string reg2_string = (this->*GetName2)(*reg2);
435 size_t reg2_index;
436 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
437 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
438 }
439
440 size_t imm_index = base.find(IMM_TOKEN);
441 if (imm_index != std::string::npos) {
442 std::ostringstream sreg;
443 sreg << imm;
444 std::string imm_string = sreg.str();
445 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
446 }
447
448 if (str.size() > 0) {
449 str += "\n";
450 }
451 str += base;
452 }
453 }
454 }
455 // Add a newline at the end.
456 str += "\n";
457 return str;
458 }
459
Andreas Gampe851df202014-11-12 14:05:46 -0800460 template <RegisterView kRegView>
461 std::string GetRegName(const Reg& reg) {
462 std::ostringstream sreg;
463 switch (kRegView) {
464 case RegisterView::kUsePrimaryName:
465 sreg << reg;
466 break;
467
468 case RegisterView::kUseSecondaryName:
469 sreg << GetSecondaryRegisterName(reg);
470 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -0700471
472 case RegisterView::kUseTertiaryName:
473 sreg << GetTertiaryRegisterName(reg);
474 break;
475
476 case RegisterView::kUseQuaternaryName:
477 sreg << GetQuaternaryRegisterName(reg);
478 break;
Andreas Gampe851df202014-11-12 14:05:46 -0800479 }
480 return sreg.str();
481 }
482
483 std::string GetFPRegName(const FPReg& reg) {
484 std::ostringstream sreg;
485 sreg << reg;
486 return sreg.str();
487 }
488
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800489 // If the assembly file needs a header, return it in a sub-class.
490 virtual const char* GetAssemblyHeader() {
491 return nullptr;
492 }
493
494 void WarnOnCombinations(size_t count) {
495 if (count > kWarnManyCombinationsThreshold) {
496 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
497 }
498 }
499
500 static constexpr const char* REG_TOKEN = "{reg}";
501 static constexpr const char* REG1_TOKEN = "{reg1}";
502 static constexpr const char* REG2_TOKEN = "{reg2}";
503 static constexpr const char* IMM_TOKEN = "{imm}";
504
505 private:
Andreas Gampe851df202014-11-12 14:05:46 -0800506 template <RegisterView kRegView>
507 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
508 std::string fmt) {
509 const std::vector<Reg*> registers = GetRegisters();
510 std::string str;
511 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800512
513 WarnOnCombinations(registers.size() * imms.size());
514
Andreas Gampe851df202014-11-12 14:05:46 -0800515 for (auto reg : registers) {
516 for (int64_t imm : imms) {
517 Imm new_imm = CreateImmediate(imm);
518 (assembler_.get()->*f)(*reg, new_imm);
519 std::string base = fmt;
520
521 std::string reg_string = GetRegName<kRegView>(*reg);
522 size_t reg_index;
523 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
524 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
525 }
526
527 size_t imm_index = base.find(IMM_TOKEN);
528 if (imm_index != std::string::npos) {
529 std::ostringstream sreg;
530 sreg << imm;
531 std::string imm_string = sreg.str();
532 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
533 }
534
535 if (str.size() > 0) {
536 str += "\n";
537 }
538 str += base;
539 }
540 }
541 // Add a newline at the end.
542 str += "\n";
543 return str;
544 }
545
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700546 void DriverWrapper(std::string assembly_text, std::string test_name) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700547 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700548 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700549 MemoryRegion code(&(*data)[0], data->size());
550 assembler_->FinalizeInstructions(code);
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700551 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700552 }
553
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800554 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -0800555
Ian Rogers700a4022014-05-19 16:49:03 -0700556 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700557 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700558
Andreas Gampe851df202014-11-12 14:05:46 -0800559 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700560};
561
562} // namespace art
563
564#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_