blob: bd994f46fc86115521058e4db3c365c80eee26b0 [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
Chris Larsendbce0d72015-09-17 13:34:00 -0700132 template <typename Reg1Type, typename Reg2Type, typename ImmType,
133 RegisterView Reg1View, RegisterView Reg2View>
134 std::string RepeatRegRegImmBits(void (Ass::*f)(Reg1Type, Reg2Type, ImmType),
135 int imm_bits,
136 std::string fmt) {
137 const std::vector<Reg1Type*> reg1_registers = GetRegisters();
138 const std::vector<Reg2Type*> reg2_registers = GetRegisters();
139 std::string str;
140 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0);
141
142 for (auto reg1 : reg1_registers) {
143 for (auto reg2 : reg2_registers) {
144 for (int64_t imm : imms) {
145 ImmType new_imm = CreateImmediate(imm);
146 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
147 std::string base = fmt;
148
149 std::string reg1_string = GetRegName<Reg1View>(*reg1);
150 size_t reg1_index;
151 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
152 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
153 }
154
155 std::string reg2_string = GetRegName<Reg2View>(*reg2);
156 size_t reg2_index;
157 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
158 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
159 }
160
161 size_t imm_index = base.find(IMM_TOKEN);
162 if (imm_index != std::string::npos) {
163 std::ostringstream sreg;
164 sreg << imm;
165 std::string imm_string = sreg.str();
166 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
167 }
168
169 if (str.size() > 0) {
170 str += "\n";
171 }
172 str += base;
173 }
174 }
175 }
176 // Add a newline at the end.
177 str += "\n";
178 return str;
179 }
180
181 template <typename Reg1Type, typename Reg2Type, typename ImmType>
182 std::string RepeatRRIb(void (Ass::*f)(Reg1Type, Reg2Type, ImmType),
183 int imm_bits,
184 std::string fmt) {
185 return RepeatRegRegImmBits<Reg1Type,
186 Reg2Type,
187 ImmType,
188 RegisterView::kUsePrimaryName,
189 RegisterView::kUsePrimaryName>(f, imm_bits, fmt);
190 }
191
Andreas Gampe851df202014-11-12 14:05:46 -0800192 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
193 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
194 GetFPRegisters(),
195 GetFPRegisters(),
196 &AssemblerTest::GetFPRegName,
197 &AssemblerTest::GetFPRegName,
198 fmt);
199 }
200
Chris Larsendbce0d72015-09-17 13:34:00 -0700201 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), std::string fmt) {
202 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
203 GetFPRegisters(),
204 GetFPRegisters(),
205 GetFPRegisters(),
206 &AssemblerTest::GetFPRegName,
207 &AssemblerTest::GetFPRegName,
208 &AssemblerTest::GetFPRegName,
209 fmt);
210 }
211
212 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
213 size_t imm_bytes,
214 std::string fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400215 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700216 GetFPRegisters(),
217 GetFPRegisters(),
218 &AssemblerTest::GetFPRegName,
219 &AssemblerTest::GetFPRegName,
220 imm_bytes,
221 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400222 }
223
Andreas Gampe851df202014-11-12 14:05:46 -0800224 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
225 return RepeatTemplatedRegisters<FPReg, Reg>(f,
226 GetFPRegisters(),
227 GetRegisters(),
228 &AssemblerTest::GetFPRegName,
229 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
230 fmt);
231 }
232
233 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::kUseSecondaryName>,
239 fmt);
240 }
241
242 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
243 return RepeatTemplatedRegisters<Reg, FPReg>(f,
244 GetRegisters(),
245 GetFPRegisters(),
246 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
247 &AssemblerTest::GetFPRegName,
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::kUseSecondaryName>,
256 &AssemblerTest::GetFPRegName,
257 fmt);
258 }
259
260 std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt,
261 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700262 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800263 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800264
265 WarnOnCombinations(imms.size());
266
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700267 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700268 Imm new_imm = CreateImmediate(imm);
269 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700270 std::string base = fmt;
271
Andreas Gampe851df202014-11-12 14:05:46 -0800272 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700273 if (imm_index != std::string::npos) {
274 std::ostringstream sreg;
275 sreg << imm;
276 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800277 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700278 }
279
280 if (str.size() > 0) {
281 str += "\n";
282 }
283 str += base;
284 }
285 // Add a newline at the end.
286 str += "\n";
287 return str;
288 }
289
290 // This is intended to be run as a test.
291 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700292 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700293 }
294
Andreas Gampe851df202014-11-12 14:05:46 -0800295 // The following functions are public so that TestFn can use them...
296
297 virtual std::vector<Reg*> GetRegisters() = 0;
298
299 virtual std::vector<FPReg*> GetFPRegisters() {
300 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
301 UNREACHABLE();
302 }
303
304 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
305 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
306 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
307 UNREACHABLE();
308 }
309
Chao-ying Fud23840d2015-04-07 16:03:04 -0700310 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
311 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
312 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
313 UNREACHABLE();
314 }
315
316 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
317 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
318 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
319 UNREACHABLE();
320 }
321
Calin Juravle9aec02f2014-11-18 23:06:35 +0000322 std::string GetRegisterName(const Reg& reg) {
323 return GetRegName<RegisterView::kUsePrimaryName>(reg);
324 }
325
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700326 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800327 explicit AssemblerTest() {}
328
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700329 void SetUp() OVERRIDE {
330 assembler_.reset(new Ass());
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700331 test_helper_.reset(
332 new AssemblerTestInfrastructure(GetArchitectureString(),
333 GetAssemblerCmdName(),
334 GetAssemblerParameters(),
335 GetObjdumpCmdName(),
336 GetObjdumpParameters(),
337 GetDisassembleCmdName(),
338 GetDisassembleParameters(),
339 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700340
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700341 SetUpHelpers();
342 }
343
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700344 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700345 test_helper_.reset(); // Clean up the helper.
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700346 }
347
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700348 // Override this to set up any architecture-specific things, e.g., register vectors.
349 virtual void SetUpHelpers() {}
350
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700351 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
352 virtual std::string GetArchitectureString() = 0;
353
354 // Get the name of the assembler, e.g., "as" by default.
355 virtual std::string GetAssemblerCmdName() {
356 return "as";
357 }
358
359 // Switches to the assembler command. Default none.
360 virtual std::string GetAssemblerParameters() {
361 return "";
362 }
363
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700364 // Get the name of the objdump, e.g., "objdump" by default.
365 virtual std::string GetObjdumpCmdName() {
366 return "objdump";
367 }
368
369 // Switches to the objdump command. Default is " -h".
370 virtual std::string GetObjdumpParameters() {
371 return " -h";
372 }
373
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700374 // Get the name of the objdump, e.g., "objdump" by default.
375 virtual std::string GetDisassembleCmdName() {
376 return "objdump";
377 }
378
379 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
380 // such to objdump, so it's architecture-specific and there is no default.
381 virtual std::string GetDisassembleParameters() = 0;
382
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700383 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800384 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700385 std::vector<int64_t> res;
386 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800387 if (!as_uint) {
388 res.push_back(-1);
389 } else {
390 res.push_back(0xFF);
391 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700392 res.push_back(0x12);
393 if (imm_bytes >= 2) {
394 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800395 if (!as_uint) {
396 res.push_back(-0x1234);
397 } else {
398 res.push_back(0xFFFF);
399 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700400 if (imm_bytes >= 4) {
401 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800402 if (!as_uint) {
403 res.push_back(-0x12345678);
404 } else {
405 res.push_back(0xFFFFFFFF);
406 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700407 if (imm_bytes >= 6) {
408 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800409 if (!as_uint) {
410 res.push_back(-0x123456789ABC);
411 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700412 if (imm_bytes >= 8) {
413 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800414 if (!as_uint) {
415 res.push_back(-0x123456789ABCDEF0);
416 } else {
417 res.push_back(0xFFFFFFFFFFFFFFFF);
418 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700419 }
420 }
421 }
422 }
423 return res;
424 }
425
Chris Larsendbce0d72015-09-17 13:34:00 -0700426 const int kMaxBitsExhaustiveTest = 8;
427
428 // Create a couple of immediate values up to the number of bits given.
429 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
430 CHECK_GT(imm_bits, 0);
431 CHECK_LE(imm_bits, 64);
432 std::vector<int64_t> res;
433
434 if (imm_bits <= kMaxBitsExhaustiveTest) {
435 if (as_uint) {
436 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
437 res.push_back(static_cast<int64_t>(i));
438 }
439 } else {
440 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
441 res.push_back(i);
442 }
443 }
444 } else {
445 if (as_uint) {
446 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
447 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
448 i++) {
449 res.push_back(static_cast<int64_t>(i));
450 }
451 for (int i = 0; i <= imm_bits; i++) {
452 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
453 ((MaxInt<uint64_t>(imm_bits) -
454 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
455 * i / imm_bits);
456 res.push_back(static_cast<int64_t>(j));
457 }
458 } else {
459 for (int i = 0; i <= imm_bits; i++) {
460 int64_t j = MinInt<int64_t>(imm_bits) +
461 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
462 MinInt<int64_t>(imm_bits))
463 * i) / imm_bits);
464 res.push_back(static_cast<int64_t>(j));
465 }
466 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
467 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
468 i++) {
469 res.push_back(static_cast<int64_t>(i));
470 }
471 for (int i = 0; i <= imm_bits; i++) {
472 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
473 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
474 * i / imm_bits);
475 res.push_back(static_cast<int64_t>(j));
476 }
477 }
478 }
479
480 return res;
481 }
482
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700483 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700484 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700485
Andreas Gampe851df202014-11-12 14:05:46 -0800486 template <typename RegType>
487 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
488 const std::vector<RegType*> registers,
489 std::string (AssemblerTest::*GetName)(const RegType&),
490 std::string fmt) {
491 std::string str;
492 for (auto reg : registers) {
493 (assembler_.get()->*f)(*reg);
494 std::string base = fmt;
495
496 std::string reg_string = (this->*GetName)(*reg);
497 size_t reg_index;
498 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
499 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
500 }
501
502 if (str.size() > 0) {
503 str += "\n";
504 }
505 str += base;
506 }
507 // Add a newline at the end.
508 str += "\n";
509 return str;
510 }
511
512 template <typename Reg1, typename Reg2>
513 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
514 const std::vector<Reg1*> reg1_registers,
515 const std::vector<Reg2*> reg2_registers,
516 std::string (AssemblerTest::*GetName1)(const Reg1&),
517 std::string (AssemblerTest::*GetName2)(const Reg2&),
518 std::string fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800519 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
520
Andreas Gampe851df202014-11-12 14:05:46 -0800521 std::string str;
522 for (auto reg1 : reg1_registers) {
523 for (auto reg2 : reg2_registers) {
524 (assembler_.get()->*f)(*reg1, *reg2);
525 std::string base = fmt;
526
527 std::string reg1_string = (this->*GetName1)(*reg1);
528 size_t reg1_index;
529 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
530 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
531 }
532
533 std::string reg2_string = (this->*GetName2)(*reg2);
534 size_t reg2_index;
535 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
536 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
537 }
538
539 if (str.size() > 0) {
540 str += "\n";
541 }
542 str += base;
543 }
544 }
545 // Add a newline at the end.
546 str += "\n";
547 return str;
548 }
549
Chris Larsendbce0d72015-09-17 13:34:00 -0700550 template <typename Reg1, typename Reg2, typename Reg3>
551 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
552 const std::vector<Reg1*> reg1_registers,
553 const std::vector<Reg2*> reg2_registers,
554 const std::vector<Reg3*> reg3_registers,
555 std::string (AssemblerTest::*GetName1)(const Reg1&),
556 std::string (AssemblerTest::*GetName2)(const Reg2&),
557 std::string (AssemblerTest::*GetName3)(const Reg3&),
558 std::string fmt) {
559 std::string str;
560 for (auto reg1 : reg1_registers) {
561 for (auto reg2 : reg2_registers) {
562 for (auto reg3 : reg3_registers) {
563 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
564 std::string base = fmt;
565
566 std::string reg1_string = (this->*GetName1)(*reg1);
567 size_t reg1_index;
568 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
569 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
570 }
571
572 std::string reg2_string = (this->*GetName2)(*reg2);
573 size_t reg2_index;
574 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
575 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
576 }
577
578 std::string reg3_string = (this->*GetName3)(*reg3);
579 size_t reg3_index;
580 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
581 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
582 }
583
584 if (str.size() > 0) {
585 str += "\n";
586 }
587 str += base;
588 }
589 }
590 }
591 // Add a newline at the end.
592 str += "\n";
593 return str;
594 }
595
Mark Mendellfb8d2792015-03-31 22:16:59 -0400596 template <typename Reg1, typename Reg2>
597 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
598 const std::vector<Reg1*> reg1_registers,
599 const std::vector<Reg2*> reg2_registers,
600 std::string (AssemblerTest::*GetName1)(const Reg1&),
601 std::string (AssemblerTest::*GetName2)(const Reg2&),
602 size_t imm_bytes,
603 std::string fmt) {
604 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
605 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
606
607 std::string str;
608 for (auto reg1 : reg1_registers) {
609 for (auto reg2 : reg2_registers) {
610 for (int64_t imm : imms) {
611 Imm new_imm = CreateImmediate(imm);
612 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
613 std::string base = fmt;
614
615 std::string reg1_string = (this->*GetName1)(*reg1);
616 size_t reg1_index;
617 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
618 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
619 }
620
621 std::string reg2_string = (this->*GetName2)(*reg2);
622 size_t reg2_index;
623 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
624 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
625 }
626
627 size_t imm_index = base.find(IMM_TOKEN);
628 if (imm_index != std::string::npos) {
629 std::ostringstream sreg;
630 sreg << imm;
631 std::string imm_string = sreg.str();
632 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
633 }
634
635 if (str.size() > 0) {
636 str += "\n";
637 }
638 str += base;
639 }
640 }
641 }
642 // Add a newline at the end.
643 str += "\n";
644 return str;
645 }
646
Andreas Gampe851df202014-11-12 14:05:46 -0800647 template <RegisterView kRegView>
648 std::string GetRegName(const Reg& reg) {
649 std::ostringstream sreg;
650 switch (kRegView) {
651 case RegisterView::kUsePrimaryName:
652 sreg << reg;
653 break;
654
655 case RegisterView::kUseSecondaryName:
656 sreg << GetSecondaryRegisterName(reg);
657 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -0700658
659 case RegisterView::kUseTertiaryName:
660 sreg << GetTertiaryRegisterName(reg);
661 break;
662
663 case RegisterView::kUseQuaternaryName:
664 sreg << GetQuaternaryRegisterName(reg);
665 break;
Andreas Gampe851df202014-11-12 14:05:46 -0800666 }
667 return sreg.str();
668 }
669
670 std::string GetFPRegName(const FPReg& reg) {
671 std::ostringstream sreg;
672 sreg << reg;
673 return sreg.str();
674 }
675
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800676 // If the assembly file needs a header, return it in a sub-class.
677 virtual const char* GetAssemblyHeader() {
678 return nullptr;
679 }
680
681 void WarnOnCombinations(size_t count) {
682 if (count > kWarnManyCombinationsThreshold) {
683 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
684 }
685 }
686
687 static constexpr const char* REG_TOKEN = "{reg}";
688 static constexpr const char* REG1_TOKEN = "{reg1}";
689 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -0700690 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800691 static constexpr const char* IMM_TOKEN = "{imm}";
692
693 private:
Andreas Gampe851df202014-11-12 14:05:46 -0800694 template <RegisterView kRegView>
695 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
696 std::string fmt) {
697 const std::vector<Reg*> registers = GetRegisters();
698 std::string str;
699 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800700
701 WarnOnCombinations(registers.size() * imms.size());
702
Andreas Gampe851df202014-11-12 14:05:46 -0800703 for (auto reg : registers) {
704 for (int64_t imm : imms) {
705 Imm new_imm = CreateImmediate(imm);
706 (assembler_.get()->*f)(*reg, new_imm);
707 std::string base = fmt;
708
709 std::string reg_string = GetRegName<kRegView>(*reg);
710 size_t reg_index;
711 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
712 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
713 }
714
715 size_t imm_index = base.find(IMM_TOKEN);
716 if (imm_index != std::string::npos) {
717 std::ostringstream sreg;
718 sreg << imm;
719 std::string imm_string = sreg.str();
720 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
721 }
722
723 if (str.size() > 0) {
724 str += "\n";
725 }
726 str += base;
727 }
728 }
729 // Add a newline at the end.
730 str += "\n";
731 return str;
732 }
733
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700734 void DriverWrapper(std::string assembly_text, std::string test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000735 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700736 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700737 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700738 MemoryRegion code(&(*data)[0], data->size());
739 assembler_->FinalizeInstructions(code);
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700740 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700741 }
742
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800743 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -0800744
Ian Rogers700a4022014-05-19 16:49:03 -0700745 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700746 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700747
Andreas Gampe851df202014-11-12 14:05:46 -0800748 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700749};
750
751} // namespace art
752
753#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_