blob: b30f7d772eaa903e2dfe85143cc51b4e376e8a91 [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
Chris Larsendbce0d72015-09-17 13:34:00 -070095 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), std::string fmt) {
96 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
97 GetRegisters(),
98 GetRegisters(),
99 GetRegisters(),
100 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
101 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
102 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
103 fmt);
104 }
105
Chao-ying Fud23840d2015-04-07 16:03:04 -0700106 std::string Repeatrb(void (Ass::*f)(Reg, Reg), std::string fmt) {
107 return RepeatTemplatedRegisters<Reg, Reg>(f,
108 GetRegisters(),
109 GetRegisters(),
110 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
111 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
112 fmt);
113 }
114
Andreas Gampe851df202014-11-12 14:05:46 -0800115 std::string RepeatRr(void (Ass::*f)(Reg, Reg), std::string fmt) {
116 return RepeatTemplatedRegisters<Reg, Reg>(f,
117 GetRegisters(),
118 GetRegisters(),
119 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
120 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
121 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700122 }
123
124 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800125 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700126 }
127
Andreas Gampe851df202014-11-12 14:05:46 -0800128 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
129 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
130 }
131
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200132 template <typename Reg1, typename Reg2, typename ImmType>
133 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
134 int imm_bits,
135 const std::vector<Reg1*> reg1_registers,
136 const std::vector<Reg2*> reg2_registers,
137 std::string (AssemblerTest::*GetName1)(const Reg1&),
138 std::string (AssemblerTest::*GetName2)(const Reg2&),
139 std::string fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700140 std::string str;
141 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0);
142
143 for (auto reg1 : reg1_registers) {
144 for (auto reg2 : reg2_registers) {
145 for (int64_t imm : imms) {
146 ImmType new_imm = CreateImmediate(imm);
147 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
148 std::string base = fmt;
149
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200150 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700151 size_t reg1_index;
152 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
153 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
154 }
155
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200156 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700157 size_t reg2_index;
158 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
159 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
160 }
161
162 size_t imm_index = base.find(IMM_TOKEN);
163 if (imm_index != std::string::npos) {
164 std::ostringstream sreg;
165 sreg << imm;
166 std::string imm_string = sreg.str();
167 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
168 }
169
170 if (str.size() > 0) {
171 str += "\n";
172 }
173 str += base;
174 }
175 }
176 }
177 // Add a newline at the end.
178 str += "\n";
179 return str;
180 }
181
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200182 template <typename RegType, typename ImmType>
183 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
184 int imm_bits,
185 const std::vector<Reg*> registers,
186 std::string (AssemblerTest::*GetName)(const RegType&),
187 std::string fmt) {
188 std::string str;
189 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0);
190
191 for (auto reg : registers) {
192 for (int64_t imm : imms) {
193 ImmType new_imm = CreateImmediate(imm);
194 (assembler_.get()->*f)(*reg, new_imm);
195 std::string base = fmt;
196
197 std::string reg_string = (this->*GetName)(*reg);
198 size_t reg_index;
199 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
200 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
201 }
202
203 size_t imm_index = base.find(IMM_TOKEN);
204 if (imm_index != std::string::npos) {
205 std::ostringstream sreg;
206 sreg << imm;
207 std::string imm_string = sreg.str();
208 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
209 }
210
211 if (str.size() > 0) {
212 str += "\n";
213 }
214 str += base;
215 }
216 }
217 // Add a newline at the end.
218 str += "\n";
219 return str;
220 }
221
222 template <typename ImmType>
223 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType), int imm_bits, std::string fmt) {
224 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
225 imm_bits,
226 GetRegisters(),
227 GetRegisters(),
228 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
229 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
230 fmt);
231 }
232
233 template <typename ImmType>
234 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt) {
235 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
236 imm_bits,
237 GetRegisters(),
238 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
239 fmt);
240 }
241
242 template <typename ImmType>
243 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType), int imm_bits, std::string fmt) {
244 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
245 imm_bits,
246 GetFPRegisters(),
247 GetRegisters(),
248 &AssemblerTest::GetFPRegName,
249 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
250 fmt);
Chris Larsendbce0d72015-09-17 13:34:00 -0700251 }
252
Andreas Gampe851df202014-11-12 14:05:46 -0800253 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
254 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
255 GetFPRegisters(),
256 GetFPRegisters(),
257 &AssemblerTest::GetFPRegName,
258 &AssemblerTest::GetFPRegName,
259 fmt);
260 }
261
Chris Larsendbce0d72015-09-17 13:34:00 -0700262 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), std::string fmt) {
263 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
264 GetFPRegisters(),
265 GetFPRegisters(),
266 GetFPRegisters(),
267 &AssemblerTest::GetFPRegName,
268 &AssemblerTest::GetFPRegName,
269 &AssemblerTest::GetFPRegName,
270 fmt);
271 }
272
273 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
274 size_t imm_bytes,
275 std::string fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400276 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700277 GetFPRegisters(),
278 GetFPRegisters(),
279 &AssemblerTest::GetFPRegName,
280 &AssemblerTest::GetFPRegName,
281 imm_bytes,
282 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400283 }
284
Andreas Gampe851df202014-11-12 14:05:46 -0800285 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
286 return RepeatTemplatedRegisters<FPReg, Reg>(f,
287 GetFPRegisters(),
288 GetRegisters(),
289 &AssemblerTest::GetFPRegName,
290 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
291 fmt);
292 }
293
294 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), std::string fmt) {
295 return RepeatTemplatedRegisters<FPReg, Reg>(f,
296 GetFPRegisters(),
297 GetRegisters(),
298 &AssemblerTest::GetFPRegName,
299 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
300 fmt);
301 }
302
303 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
304 return RepeatTemplatedRegisters<Reg, FPReg>(f,
305 GetRegisters(),
306 GetFPRegisters(),
307 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
308 &AssemblerTest::GetFPRegName,
309 fmt);
310 }
311
312 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
313 return RepeatTemplatedRegisters<Reg, FPReg>(f,
314 GetRegisters(),
315 GetFPRegisters(),
316 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
317 &AssemblerTest::GetFPRegName,
318 fmt);
319 }
320
321 std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt,
322 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700323 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800324 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800325
326 WarnOnCombinations(imms.size());
327
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700328 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700329 Imm new_imm = CreateImmediate(imm);
330 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700331 std::string base = fmt;
332
Andreas Gampe851df202014-11-12 14:05:46 -0800333 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700334 if (imm_index != std::string::npos) {
335 std::ostringstream sreg;
336 sreg << imm;
337 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800338 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700339 }
340
341 if (str.size() > 0) {
342 str += "\n";
343 }
344 str += base;
345 }
346 // Add a newline at the end.
347 str += "\n";
348 return str;
349 }
350
351 // This is intended to be run as a test.
352 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700353 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700354 }
355
Andreas Gampe851df202014-11-12 14:05:46 -0800356 // The following functions are public so that TestFn can use them...
357
358 virtual std::vector<Reg*> GetRegisters() = 0;
359
360 virtual std::vector<FPReg*> GetFPRegisters() {
361 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
362 UNREACHABLE();
363 }
364
365 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
366 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
367 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
368 UNREACHABLE();
369 }
370
Chao-ying Fud23840d2015-04-07 16:03:04 -0700371 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
372 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
373 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
374 UNREACHABLE();
375 }
376
377 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
378 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
379 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
380 UNREACHABLE();
381 }
382
Calin Juravle9aec02f2014-11-18 23:06:35 +0000383 std::string GetRegisterName(const Reg& reg) {
384 return GetRegName<RegisterView::kUsePrimaryName>(reg);
385 }
386
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700387 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800388 explicit AssemblerTest() {}
389
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700390 void SetUp() OVERRIDE {
391 assembler_.reset(new Ass());
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700392 test_helper_.reset(
393 new AssemblerTestInfrastructure(GetArchitectureString(),
394 GetAssemblerCmdName(),
395 GetAssemblerParameters(),
396 GetObjdumpCmdName(),
397 GetObjdumpParameters(),
398 GetDisassembleCmdName(),
399 GetDisassembleParameters(),
400 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700401
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700402 SetUpHelpers();
403 }
404
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700405 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700406 test_helper_.reset(); // Clean up the helper.
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700407 }
408
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700409 // Override this to set up any architecture-specific things, e.g., register vectors.
410 virtual void SetUpHelpers() {}
411
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700412 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
413 virtual std::string GetArchitectureString() = 0;
414
415 // Get the name of the assembler, e.g., "as" by default.
416 virtual std::string GetAssemblerCmdName() {
417 return "as";
418 }
419
420 // Switches to the assembler command. Default none.
421 virtual std::string GetAssemblerParameters() {
422 return "";
423 }
424
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700425 // Get the name of the objdump, e.g., "objdump" by default.
426 virtual std::string GetObjdumpCmdName() {
427 return "objdump";
428 }
429
430 // Switches to the objdump command. Default is " -h".
431 virtual std::string GetObjdumpParameters() {
432 return " -h";
433 }
434
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700435 // Get the name of the objdump, e.g., "objdump" by default.
436 virtual std::string GetDisassembleCmdName() {
437 return "objdump";
438 }
439
440 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
441 // such to objdump, so it's architecture-specific and there is no default.
442 virtual std::string GetDisassembleParameters() = 0;
443
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700444 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800445 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700446 std::vector<int64_t> res;
447 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800448 if (!as_uint) {
449 res.push_back(-1);
450 } else {
451 res.push_back(0xFF);
452 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700453 res.push_back(0x12);
454 if (imm_bytes >= 2) {
455 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800456 if (!as_uint) {
457 res.push_back(-0x1234);
458 } else {
459 res.push_back(0xFFFF);
460 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700461 if (imm_bytes >= 4) {
462 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800463 if (!as_uint) {
464 res.push_back(-0x12345678);
465 } else {
466 res.push_back(0xFFFFFFFF);
467 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700468 if (imm_bytes >= 6) {
469 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800470 if (!as_uint) {
471 res.push_back(-0x123456789ABC);
472 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700473 if (imm_bytes >= 8) {
474 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800475 if (!as_uint) {
476 res.push_back(-0x123456789ABCDEF0);
477 } else {
478 res.push_back(0xFFFFFFFFFFFFFFFF);
479 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700480 }
481 }
482 }
483 }
484 return res;
485 }
486
Chris Larsendbce0d72015-09-17 13:34:00 -0700487 const int kMaxBitsExhaustiveTest = 8;
488
489 // Create a couple of immediate values up to the number of bits given.
490 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
491 CHECK_GT(imm_bits, 0);
492 CHECK_LE(imm_bits, 64);
493 std::vector<int64_t> res;
494
495 if (imm_bits <= kMaxBitsExhaustiveTest) {
496 if (as_uint) {
497 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
498 res.push_back(static_cast<int64_t>(i));
499 }
500 } else {
501 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
502 res.push_back(i);
503 }
504 }
505 } else {
506 if (as_uint) {
507 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
508 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
509 i++) {
510 res.push_back(static_cast<int64_t>(i));
511 }
512 for (int i = 0; i <= imm_bits; i++) {
513 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
514 ((MaxInt<uint64_t>(imm_bits) -
515 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
516 * i / imm_bits);
517 res.push_back(static_cast<int64_t>(j));
518 }
519 } else {
520 for (int i = 0; i <= imm_bits; i++) {
521 int64_t j = MinInt<int64_t>(imm_bits) +
522 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
523 MinInt<int64_t>(imm_bits))
524 * i) / imm_bits);
525 res.push_back(static_cast<int64_t>(j));
526 }
527 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
528 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
529 i++) {
530 res.push_back(static_cast<int64_t>(i));
531 }
532 for (int i = 0; i <= imm_bits; i++) {
533 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
534 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
535 * i / imm_bits);
536 res.push_back(static_cast<int64_t>(j));
537 }
538 }
539 }
540
541 return res;
542 }
543
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700544 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700545 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700546
Andreas Gampe851df202014-11-12 14:05:46 -0800547 template <typename RegType>
548 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
549 const std::vector<RegType*> registers,
550 std::string (AssemblerTest::*GetName)(const RegType&),
551 std::string fmt) {
552 std::string str;
553 for (auto reg : registers) {
554 (assembler_.get()->*f)(*reg);
555 std::string base = fmt;
556
557 std::string reg_string = (this->*GetName)(*reg);
558 size_t reg_index;
559 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
560 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
561 }
562
563 if (str.size() > 0) {
564 str += "\n";
565 }
566 str += base;
567 }
568 // Add a newline at the end.
569 str += "\n";
570 return str;
571 }
572
573 template <typename Reg1, typename Reg2>
574 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
575 const std::vector<Reg1*> reg1_registers,
576 const std::vector<Reg2*> reg2_registers,
577 std::string (AssemblerTest::*GetName1)(const Reg1&),
578 std::string (AssemblerTest::*GetName2)(const Reg2&),
579 std::string fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800580 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
581
Andreas Gampe851df202014-11-12 14:05:46 -0800582 std::string str;
583 for (auto reg1 : reg1_registers) {
584 for (auto reg2 : reg2_registers) {
585 (assembler_.get()->*f)(*reg1, *reg2);
586 std::string base = fmt;
587
588 std::string reg1_string = (this->*GetName1)(*reg1);
589 size_t reg1_index;
590 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
591 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
592 }
593
594 std::string reg2_string = (this->*GetName2)(*reg2);
595 size_t reg2_index;
596 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
597 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
598 }
599
600 if (str.size() > 0) {
601 str += "\n";
602 }
603 str += base;
604 }
605 }
606 // Add a newline at the end.
607 str += "\n";
608 return str;
609 }
610
Chris Larsendbce0d72015-09-17 13:34:00 -0700611 template <typename Reg1, typename Reg2, typename Reg3>
612 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
613 const std::vector<Reg1*> reg1_registers,
614 const std::vector<Reg2*> reg2_registers,
615 const std::vector<Reg3*> reg3_registers,
616 std::string (AssemblerTest::*GetName1)(const Reg1&),
617 std::string (AssemblerTest::*GetName2)(const Reg2&),
618 std::string (AssemblerTest::*GetName3)(const Reg3&),
619 std::string fmt) {
620 std::string str;
621 for (auto reg1 : reg1_registers) {
622 for (auto reg2 : reg2_registers) {
623 for (auto reg3 : reg3_registers) {
624 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
625 std::string base = fmt;
626
627 std::string reg1_string = (this->*GetName1)(*reg1);
628 size_t reg1_index;
629 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
630 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
631 }
632
633 std::string reg2_string = (this->*GetName2)(*reg2);
634 size_t reg2_index;
635 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
636 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
637 }
638
639 std::string reg3_string = (this->*GetName3)(*reg3);
640 size_t reg3_index;
641 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
642 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
643 }
644
645 if (str.size() > 0) {
646 str += "\n";
647 }
648 str += base;
649 }
650 }
651 }
652 // Add a newline at the end.
653 str += "\n";
654 return str;
655 }
656
Mark Mendellfb8d2792015-03-31 22:16:59 -0400657 template <typename Reg1, typename Reg2>
658 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
659 const std::vector<Reg1*> reg1_registers,
660 const std::vector<Reg2*> reg2_registers,
661 std::string (AssemblerTest::*GetName1)(const Reg1&),
662 std::string (AssemblerTest::*GetName2)(const Reg2&),
663 size_t imm_bytes,
664 std::string fmt) {
665 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
666 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
667
668 std::string str;
669 for (auto reg1 : reg1_registers) {
670 for (auto reg2 : reg2_registers) {
671 for (int64_t imm : imms) {
672 Imm new_imm = CreateImmediate(imm);
673 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
674 std::string base = fmt;
675
676 std::string reg1_string = (this->*GetName1)(*reg1);
677 size_t reg1_index;
678 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
679 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
680 }
681
682 std::string reg2_string = (this->*GetName2)(*reg2);
683 size_t reg2_index;
684 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
685 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
686 }
687
688 size_t imm_index = base.find(IMM_TOKEN);
689 if (imm_index != std::string::npos) {
690 std::ostringstream sreg;
691 sreg << imm;
692 std::string imm_string = sreg.str();
693 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
694 }
695
696 if (str.size() > 0) {
697 str += "\n";
698 }
699 str += base;
700 }
701 }
702 }
703 // Add a newline at the end.
704 str += "\n";
705 return str;
706 }
707
Andreas Gampe851df202014-11-12 14:05:46 -0800708 template <RegisterView kRegView>
709 std::string GetRegName(const Reg& reg) {
710 std::ostringstream sreg;
711 switch (kRegView) {
712 case RegisterView::kUsePrimaryName:
713 sreg << reg;
714 break;
715
716 case RegisterView::kUseSecondaryName:
717 sreg << GetSecondaryRegisterName(reg);
718 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -0700719
720 case RegisterView::kUseTertiaryName:
721 sreg << GetTertiaryRegisterName(reg);
722 break;
723
724 case RegisterView::kUseQuaternaryName:
725 sreg << GetQuaternaryRegisterName(reg);
726 break;
Andreas Gampe851df202014-11-12 14:05:46 -0800727 }
728 return sreg.str();
729 }
730
731 std::string GetFPRegName(const FPReg& reg) {
732 std::ostringstream sreg;
733 sreg << reg;
734 return sreg.str();
735 }
736
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800737 // If the assembly file needs a header, return it in a sub-class.
738 virtual const char* GetAssemblyHeader() {
739 return nullptr;
740 }
741
742 void WarnOnCombinations(size_t count) {
743 if (count > kWarnManyCombinationsThreshold) {
744 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
745 }
746 }
747
748 static constexpr const char* REG_TOKEN = "{reg}";
749 static constexpr const char* REG1_TOKEN = "{reg1}";
750 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -0700751 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800752 static constexpr const char* IMM_TOKEN = "{imm}";
753
754 private:
Andreas Gampe851df202014-11-12 14:05:46 -0800755 template <RegisterView kRegView>
756 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
757 std::string fmt) {
758 const std::vector<Reg*> registers = GetRegisters();
759 std::string str;
760 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800761
762 WarnOnCombinations(registers.size() * imms.size());
763
Andreas Gampe851df202014-11-12 14:05:46 -0800764 for (auto reg : registers) {
765 for (int64_t imm : imms) {
766 Imm new_imm = CreateImmediate(imm);
767 (assembler_.get()->*f)(*reg, new_imm);
768 std::string base = fmt;
769
770 std::string reg_string = GetRegName<kRegView>(*reg);
771 size_t reg_index;
772 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
773 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
774 }
775
776 size_t imm_index = base.find(IMM_TOKEN);
777 if (imm_index != std::string::npos) {
778 std::ostringstream sreg;
779 sreg << imm;
780 std::string imm_string = sreg.str();
781 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
782 }
783
784 if (str.size() > 0) {
785 str += "\n";
786 }
787 str += base;
788 }
789 }
790 // Add a newline at the end.
791 str += "\n";
792 return str;
793 }
794
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700795 void DriverWrapper(std::string assembly_text, std::string test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000796 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700797 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700798 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700799 MemoryRegion code(&(*data)[0], data->size());
800 assembler_->FinalizeInstructions(code);
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700801 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700802 }
803
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800804 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -0800805
Ian Rogers700a4022014-05-19 16:49:03 -0700806 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700807 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700808
Andreas Gampe851df202014-11-12 14:05:46 -0800809 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700810};
811
812} // namespace art
813
814#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_