blob: 5ab558b256a6ddcc31f250b4f783f7e49c3fdc28 [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 Gampe8cf9cb32017-07-19 09:28:38 -070022#include <sys/stat.h>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070023
24#include <cstdio>
25#include <cstdlib>
26#include <fstream>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070027#include <iterator>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028
29#include "assembler_test_base.h"
30#include "common_runtime_test.h" // For ScratchFile
Andreas Gampe5a4fa822014-03-31 16:50:12 -070031
32namespace art {
33
Andreas Gampe851df202014-11-12 14:05:46 -080034// Helper for a constexpr string length.
35constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
36 return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
37}
38
Andreas Gampe849cc5e2014-11-18 13:46:46 -080039enum class RegisterView { // private
40 kUsePrimaryName,
Chao-ying Fud23840d2015-04-07 16:03:04 -070041 kUseSecondaryName,
42 kUseTertiaryName,
43 kUseQuaternaryName,
Andreas Gampe849cc5e2014-11-18 13:46:46 -080044};
45
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +000046// For use in the template as the default type to get a nonvector registers version.
47struct NoVectorRegs {};
48
49template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070050class AssemblerTest : public testing::Test {
51 public:
52 Ass* GetAssembler() {
53 return assembler_.get();
54 }
55
Andreas Gampe851df202014-11-12 14:05:46 -080056 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070057
Andreas Gampe2e965ac2016-11-03 17:24:15 -070058 void DriverFn(TestFn f, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070059 DriverWrapper(f(this, assembler_.get()), test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070060 }
61
62 // This driver assumes the assembler has already been called.
Andreas Gampe2e965ac2016-11-03 17:24:15 -070063 void DriverStr(const std::string& assembly_string, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070064 DriverWrapper(assembly_string, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070065 }
66
Andreas Gampe2e965ac2016-11-03 17:24:15 -070067 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080068 return RepeatTemplatedRegister<Reg>(f,
69 GetRegisters(),
70 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
71 fmt);
72 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070073
Andreas Gampe2e965ac2016-11-03 17:24:15 -070074 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080075 return RepeatTemplatedRegister<Reg>(f,
76 GetRegisters(),
77 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
78 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070079 }
80
Andreas Gampe2e965ac2016-11-03 17:24:15 -070081 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080082 return RepeatTemplatedRegisters<Reg, Reg>(f,
83 GetRegisters(),
84 GetRegisters(),
85 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
86 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
87 fmt);
88 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070089
Andreas Gampe2e965ac2016-11-03 17:24:15 -070090 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -070091 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
92 GetRegisters(),
93 GetRegisters(),
94 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
95 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
96 fmt);
97 }
98
Andreas Gampe2e965ac2016-11-03 17:24:15 -070099 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800100 return RepeatTemplatedRegisters<Reg, Reg>(f,
101 GetRegisters(),
102 GetRegisters(),
103 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
104 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
105 fmt);
106 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700107
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700108 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700109 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
110 GetRegisters(),
111 GetRegisters(),
112 GetRegisters(),
113 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
114 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
115 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
116 fmt);
117 }
118
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700119 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chao-ying Fud23840d2015-04-07 16:03:04 -0700120 return RepeatTemplatedRegisters<Reg, Reg>(f,
121 GetRegisters(),
122 GetRegisters(),
123 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
124 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
125 fmt);
126 }
127
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700128 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800129 return RepeatTemplatedRegisters<Reg, Reg>(f,
130 GetRegisters(),
131 GetRegisters(),
132 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
133 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
134 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700135 }
136
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700137 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800138 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700139 }
140
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700141 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800142 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
143 }
144
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200145 template <typename Reg1, typename Reg2, typename ImmType>
146 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
147 int imm_bits,
148 const std::vector<Reg1*> reg1_registers,
149 const std::vector<Reg2*> reg2_registers,
150 std::string (AssemblerTest::*GetName1)(const Reg1&),
151 std::string (AssemblerTest::*GetName2)(const Reg2&),
Chris Larsene3660592016-11-09 11:13:42 -0800152 const std::string& fmt,
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000153 int bias = 0,
154 int multiplier = 1) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700155 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800156 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Chris Larsendbce0d72015-09-17 13:34:00 -0700157
158 for (auto reg1 : reg1_registers) {
159 for (auto reg2 : reg2_registers) {
160 for (int64_t imm : imms) {
161 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700162 if (f != nullptr) {
163 (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
164 }
Chris Larsendbce0d72015-09-17 13:34:00 -0700165 std::string base = fmt;
166
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200167 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700168 size_t reg1_index;
169 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
170 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
171 }
172
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200173 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700174 size_t reg2_index;
175 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
176 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
177 }
178
179 size_t imm_index = base.find(IMM_TOKEN);
180 if (imm_index != std::string::npos) {
181 std::ostringstream sreg;
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000182 sreg << imm * multiplier + bias;
Chris Larsendbce0d72015-09-17 13:34:00 -0700183 std::string imm_string = sreg.str();
184 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
185 }
186
187 if (str.size() > 0) {
188 str += "\n";
189 }
190 str += base;
191 }
192 }
193 }
194 // Add a newline at the end.
195 str += "\n";
196 return str;
197 }
198
Chris Larsene3660592016-11-09 11:13:42 -0800199 template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
200 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
201 int imm_bits,
202 const std::vector<Reg1*> reg1_registers,
203 const std::vector<Reg2*> reg2_registers,
204 const std::vector<Reg3*> reg3_registers,
205 std::string (AssemblerTest::*GetName1)(const Reg1&),
206 std::string (AssemblerTest::*GetName2)(const Reg2&),
207 std::string (AssemblerTest::*GetName3)(const Reg3&),
208 std::string fmt,
209 int bias) {
210 std::string str;
211 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
212
213 for (auto reg1 : reg1_registers) {
214 for (auto reg2 : reg2_registers) {
215 for (auto reg3 : reg3_registers) {
216 for (int64_t imm : imms) {
217 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700218 if (f != nullptr) {
219 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
220 }
Chris Larsene3660592016-11-09 11:13:42 -0800221 std::string base = fmt;
222
223 std::string reg1_string = (this->*GetName1)(*reg1);
224 size_t reg1_index;
225 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
226 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
227 }
228
229 std::string reg2_string = (this->*GetName2)(*reg2);
230 size_t reg2_index;
231 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
232 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
233 }
234
235 std::string reg3_string = (this->*GetName3)(*reg3);
236 size_t reg3_index;
237 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
238 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
239 }
240
241 size_t imm_index = base.find(IMM_TOKEN);
242 if (imm_index != std::string::npos) {
243 std::ostringstream sreg;
244 sreg << imm + bias;
245 std::string imm_string = sreg.str();
246 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
247 }
248
249 if (str.size() > 0) {
250 str += "\n";
251 }
252 str += base;
253 }
254 }
255 }
256 }
257 // Add a newline at the end.
258 str += "\n";
259 return str;
260 }
261
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800262 template <typename ImmType, typename Reg1, typename Reg2>
263 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
264 const std::vector<Reg1*> reg1_registers,
265 const std::vector<Reg2*> reg2_registers,
266 std::string (AssemblerTest::*GetName1)(const Reg1&),
267 std::string (AssemblerTest::*GetName2)(const Reg2&),
268 int imm_bits,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700269 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800270 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
271
272 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
273
274 std::string str;
275 for (auto reg1 : reg1_registers) {
276 for (auto reg2 : reg2_registers) {
277 for (int64_t imm : imms) {
278 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700279 if (f != nullptr) {
280 (assembler_.get()->*f)(new_imm, *reg1, *reg2);
281 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800282 std::string base = fmt;
283
284 std::string reg1_string = (this->*GetName1)(*reg1);
285 size_t reg1_index;
286 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
287 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
288 }
289
290 std::string reg2_string = (this->*GetName2)(*reg2);
291 size_t reg2_index;
292 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
293 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
294 }
295
296 size_t imm_index = base.find(IMM_TOKEN);
297 if (imm_index != std::string::npos) {
298 std::ostringstream sreg;
299 sreg << imm;
300 std::string imm_string = sreg.str();
301 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
302 }
303
304 if (str.size() > 0) {
305 str += "\n";
306 }
307 str += base;
308 }
309 }
310 }
311 // Add a newline at the end.
312 str += "\n";
313 return str;
314 }
315
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200316 template <typename RegType, typename ImmType>
317 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800318 int imm_bits,
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200319 const std::vector<RegType*> registers,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800320 std::string (AssemblerTest::*GetName)(const RegType&),
Chris Larsene3660592016-11-09 11:13:42 -0800321 const std::string& fmt,
322 int bias) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200323 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800324 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200325
326 for (auto reg : registers) {
327 for (int64_t imm : imms) {
328 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700329 if (f != nullptr) {
330 (assembler_.get()->*f)(*reg, new_imm + bias);
331 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200332 std::string base = fmt;
333
334 std::string reg_string = (this->*GetName)(*reg);
335 size_t reg_index;
336 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
337 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
338 }
339
340 size_t imm_index = base.find(IMM_TOKEN);
341 if (imm_index != std::string::npos) {
342 std::ostringstream sreg;
Chris Larsene3660592016-11-09 11:13:42 -0800343 sreg << imm + bias;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200344 std::string imm_string = sreg.str();
345 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
346 }
347
348 if (str.size() > 0) {
349 str += "\n";
350 }
351 str += base;
352 }
353 }
354 // Add a newline at the end.
355 str += "\n";
356 return str;
357 }
358
359 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800360 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
361 int imm_bits,
362 const std::string& fmt,
363 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200364 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
365 imm_bits,
366 GetRegisters(),
367 GetRegisters(),
368 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
369 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800370 fmt,
371 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200372 }
373
374 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800375 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
376 int imm_bits,
377 const std::string& fmt,
378 int bias = 0) {
379 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
380 imm_bits,
381 GetRegisters(),
382 GetRegisters(),
383 GetRegisters(),
384 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
385 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
386 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
387 fmt,
388 bias);
389 }
390
391 template <typename ImmType>
392 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200393 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
394 imm_bits,
395 GetRegisters(),
396 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800397 fmt,
398 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200399 }
400
401 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700402 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
403 int imm_bits,
Chris Larsene3660592016-11-09 11:13:42 -0800404 const std::string& fmt,
405 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200406 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
407 imm_bits,
408 GetFPRegisters(),
409 GetRegisters(),
410 &AssemblerTest::GetFPRegName,
411 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800412 fmt,
413 bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700414 }
415
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700416 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800417 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
418 GetFPRegisters(),
419 GetFPRegisters(),
420 &AssemblerTest::GetFPRegName,
421 &AssemblerTest::GetFPRegName,
422 fmt);
423 }
424
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700425 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700426 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
427 GetFPRegisters(),
428 GetFPRegisters(),
429 GetFPRegisters(),
430 &AssemblerTest::GetFPRegName,
431 &AssemblerTest::GetFPRegName,
432 &AssemblerTest::GetFPRegName,
433 fmt);
434 }
435
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700436 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700437 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
438 f,
439 GetFPRegisters(),
440 GetFPRegisters(),
441 GetRegisters(),
442 &AssemblerTest::GetFPRegName,
443 &AssemblerTest::GetFPRegName,
444 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
445 fmt);
446 }
447
Chris Larsendbce0d72015-09-17 13:34:00 -0700448 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
449 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700450 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400451 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700452 GetFPRegisters(),
453 GetFPRegisters(),
454 &AssemblerTest::GetFPRegName,
455 &AssemblerTest::GetFPRegName,
456 imm_bytes,
457 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400458 }
459
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800460 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700461 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
462 int imm_bits,
463 const std::string& fmt) {
Alexey Frunzea8aaf5a2016-06-27 14:48:20 -0700464 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
465 imm_bits,
466 GetFPRegisters(),
467 GetFPRegisters(),
468 &AssemblerTest::GetFPRegName,
469 &AssemblerTest::GetFPRegName,
470 fmt);
471 }
472
473 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700474 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
475 int imm_bits,
476 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800477 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
478 GetFPRegisters(),
479 GetFPRegisters(),
480 &AssemblerTest::GetFPRegName,
481 &AssemblerTest::GetFPRegName,
482 imm_bits,
483 fmt);
484 }
485
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700486 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800487 return RepeatTemplatedRegisters<FPReg, Reg>(f,
488 GetFPRegisters(),
489 GetRegisters(),
490 &AssemblerTest::GetFPRegName,
491 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
492 fmt);
493 }
494
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700495 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800496 return RepeatTemplatedRegisters<FPReg, Reg>(f,
497 GetFPRegisters(),
498 GetRegisters(),
499 &AssemblerTest::GetFPRegName,
500 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
501 fmt);
502 }
503
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700504 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800505 return RepeatTemplatedRegisters<Reg, FPReg>(f,
506 GetRegisters(),
507 GetFPRegisters(),
508 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
509 &AssemblerTest::GetFPRegName,
510 fmt);
511 }
512
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700513 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800514 return RepeatTemplatedRegisters<Reg, FPReg>(f,
515 GetRegisters(),
516 GetFPRegisters(),
517 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
518 &AssemblerTest::GetFPRegName,
519 fmt);
520 }
521
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700522 std::string RepeatI(void (Ass::*f)(const Imm&),
523 size_t imm_bytes,
524 const std::string& fmt,
Andreas Gampe851df202014-11-12 14:05:46 -0800525 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700526 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800527 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800528
529 WarnOnCombinations(imms.size());
530
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700531 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700532 Imm new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700533 if (f != nullptr) {
534 (assembler_.get()->*f)(new_imm);
535 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700536 std::string base = fmt;
537
Andreas Gampe851df202014-11-12 14:05:46 -0800538 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700539 if (imm_index != std::string::npos) {
540 std::ostringstream sreg;
541 sreg << imm;
542 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800543 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700544 }
545
546 if (str.size() > 0) {
547 str += "\n";
548 }
549 str += base;
550 }
551 // Add a newline at the end.
552 str += "\n";
553 return str;
554 }
555
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000556 std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
557 return RepeatTemplatedRegisters<VecReg, VecReg>(f,
558 GetVectorRegisters(),
559 GetVectorRegisters(),
560 &AssemblerTest::GetVecRegName,
561 &AssemblerTest::GetVecRegName,
562 fmt);
563 }
564
565 std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
566 return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
567 GetVectorRegisters(),
568 GetVectorRegisters(),
569 GetVectorRegisters(),
570 &AssemblerTest::GetVecRegName,
571 &AssemblerTest::GetVecRegName,
572 &AssemblerTest::GetVecRegName,
573 fmt);
574 }
575
576 std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
577 return RepeatTemplatedRegisters<VecReg, Reg>(
578 f,
579 GetVectorRegisters(),
580 GetRegisters(),
581 &AssemblerTest::GetVecRegName,
582 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
583 fmt);
584 }
585
586 template <typename ImmType>
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200587 std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
588 int imm_bits,
589 std::string fmt,
590 int bias = 0) {
591 return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
592 imm_bits,
593 GetVectorRegisters(),
594 &AssemblerTest::GetVecRegName,
595 fmt,
596 bias);
597 }
598
599 template <typename ImmType>
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000600 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
601 int imm_bits,
602 const std::string& fmt,
603 int bias = 0,
604 int multiplier = 1) {
605 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
606 f,
607 imm_bits,
608 GetVectorRegisters(),
609 GetRegisters(),
610 &AssemblerTest::GetVecRegName,
611 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
612 fmt,
613 bias,
614 multiplier);
615 }
616
617 template <typename ImmType>
618 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
619 int imm_bits,
620 const std::string& fmt,
621 int bias = 0) {
622 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
623 imm_bits,
624 GetVectorRegisters(),
625 GetVectorRegisters(),
626 &AssemblerTest::GetVecRegName,
627 &AssemblerTest::GetVecRegName,
628 fmt,
629 bias);
630 }
631
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700632 // This is intended to be run as a test.
633 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700634 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700635 }
636
Andreas Gampe851df202014-11-12 14:05:46 -0800637 // The following functions are public so that TestFn can use them...
638
639 virtual std::vector<Reg*> GetRegisters() = 0;
640
641 virtual std::vector<FPReg*> GetFPRegisters() {
642 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
643 UNREACHABLE();
644 }
645
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000646 virtual std::vector<VecReg*> GetVectorRegisters() {
647 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
648 UNREACHABLE();
649 }
650
Andreas Gampe851df202014-11-12 14:05:46 -0800651 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
652 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
653 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
654 UNREACHABLE();
655 }
656
Chao-ying Fud23840d2015-04-07 16:03:04 -0700657 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
658 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
659 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
660 UNREACHABLE();
661 }
662
663 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
664 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
665 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
666 UNREACHABLE();
667 }
668
Calin Juravle9aec02f2014-11-18 23:06:35 +0000669 std::string GetRegisterName(const Reg& reg) {
670 return GetRegName<RegisterView::kUsePrimaryName>(reg);
671 }
672
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700673 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800674 explicit AssemblerTest() {}
675
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700676 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100677 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700678 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700679 test_helper_.reset(
680 new AssemblerTestInfrastructure(GetArchitectureString(),
681 GetAssemblerCmdName(),
682 GetAssemblerParameters(),
683 GetObjdumpCmdName(),
684 GetObjdumpParameters(),
685 GetDisassembleCmdName(),
686 GetDisassembleParameters(),
687 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700688
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700689 SetUpHelpers();
690 }
691
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700692 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700693 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100694 assembler_.reset();
695 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700696 }
697
Chris Larsen3add9cb2016-04-14 14:01:33 -0700698 // Override this to set up any architecture-specific things, e.g., CPU revision.
699 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
700 return new (arena) Ass(arena);
701 }
702
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700703 // Override this to set up any architecture-specific things, e.g., register vectors.
704 virtual void SetUpHelpers() {}
705
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700706 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
707 virtual std::string GetArchitectureString() = 0;
708
709 // Get the name of the assembler, e.g., "as" by default.
710 virtual std::string GetAssemblerCmdName() {
711 return "as";
712 }
713
714 // Switches to the assembler command. Default none.
715 virtual std::string GetAssemblerParameters() {
716 return "";
717 }
718
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700719 // Get the name of the objdump, e.g., "objdump" by default.
720 virtual std::string GetObjdumpCmdName() {
721 return "objdump";
722 }
723
724 // Switches to the objdump command. Default is " -h".
725 virtual std::string GetObjdumpParameters() {
726 return " -h";
727 }
728
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700729 // Get the name of the objdump, e.g., "objdump" by default.
730 virtual std::string GetDisassembleCmdName() {
731 return "objdump";
732 }
733
734 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
735 // such to objdump, so it's architecture-specific and there is no default.
736 virtual std::string GetDisassembleParameters() = 0;
737
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700738 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800739 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700740 std::vector<int64_t> res;
741 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800742 if (!as_uint) {
743 res.push_back(-1);
744 } else {
745 res.push_back(0xFF);
746 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700747 res.push_back(0x12);
748 if (imm_bytes >= 2) {
749 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800750 if (!as_uint) {
751 res.push_back(-0x1234);
752 } else {
753 res.push_back(0xFFFF);
754 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700755 if (imm_bytes >= 4) {
756 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800757 if (!as_uint) {
758 res.push_back(-0x12345678);
759 } else {
760 res.push_back(0xFFFFFFFF);
761 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700762 if (imm_bytes >= 6) {
763 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800764 if (!as_uint) {
765 res.push_back(-0x123456789ABC);
766 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700767 if (imm_bytes >= 8) {
768 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800769 if (!as_uint) {
770 res.push_back(-0x123456789ABCDEF0);
771 } else {
772 res.push_back(0xFFFFFFFFFFFFFFFF);
773 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700774 }
775 }
776 }
777 }
778 return res;
779 }
780
Chris Larsendbce0d72015-09-17 13:34:00 -0700781 const int kMaxBitsExhaustiveTest = 8;
782
783 // Create a couple of immediate values up to the number of bits given.
784 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
785 CHECK_GT(imm_bits, 0);
786 CHECK_LE(imm_bits, 64);
787 std::vector<int64_t> res;
788
789 if (imm_bits <= kMaxBitsExhaustiveTest) {
790 if (as_uint) {
791 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
792 res.push_back(static_cast<int64_t>(i));
793 }
794 } else {
795 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
796 res.push_back(i);
797 }
798 }
799 } else {
800 if (as_uint) {
801 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
802 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
803 i++) {
804 res.push_back(static_cast<int64_t>(i));
805 }
806 for (int i = 0; i <= imm_bits; i++) {
807 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
808 ((MaxInt<uint64_t>(imm_bits) -
809 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
810 * i / imm_bits);
811 res.push_back(static_cast<int64_t>(j));
812 }
813 } else {
814 for (int i = 0; i <= imm_bits; i++) {
815 int64_t j = MinInt<int64_t>(imm_bits) +
816 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
817 MinInt<int64_t>(imm_bits))
818 * i) / imm_bits);
819 res.push_back(static_cast<int64_t>(j));
820 }
821 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
822 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
823 i++) {
824 res.push_back(static_cast<int64_t>(i));
825 }
826 for (int i = 0; i <= imm_bits; i++) {
827 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
828 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
829 * i / imm_bits);
830 res.push_back(static_cast<int64_t>(j));
831 }
832 }
833 }
834
835 return res;
836 }
837
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700838 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700839 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700840
Andreas Gampe851df202014-11-12 14:05:46 -0800841 template <typename RegType>
842 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
843 const std::vector<RegType*> registers,
844 std::string (AssemblerTest::*GetName)(const RegType&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700845 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800846 std::string str;
847 for (auto reg : registers) {
Aart Bik5dafb3c2017-09-13 13:10:12 -0700848 if (f != nullptr) {
849 (assembler_.get()->*f)(*reg);
850 }
Andreas Gampe851df202014-11-12 14:05:46 -0800851 std::string base = fmt;
852
853 std::string reg_string = (this->*GetName)(*reg);
854 size_t reg_index;
855 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
856 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
857 }
858
859 if (str.size() > 0) {
860 str += "\n";
861 }
862 str += base;
863 }
864 // Add a newline at the end.
865 str += "\n";
866 return str;
867 }
868
869 template <typename Reg1, typename Reg2>
870 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
871 const std::vector<Reg1*> reg1_registers,
872 const std::vector<Reg2*> reg2_registers,
873 std::string (AssemblerTest::*GetName1)(const Reg1&),
874 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700875 const std::string& fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800876 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
877
Andreas Gampe851df202014-11-12 14:05:46 -0800878 std::string str;
879 for (auto reg1 : reg1_registers) {
880 for (auto reg2 : reg2_registers) {
Aart Bik5dafb3c2017-09-13 13:10:12 -0700881 if (f != nullptr) {
882 (assembler_.get()->*f)(*reg1, *reg2);
883 }
Andreas Gampe851df202014-11-12 14:05:46 -0800884 std::string base = fmt;
885
886 std::string reg1_string = (this->*GetName1)(*reg1);
887 size_t reg1_index;
888 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
889 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
890 }
891
892 std::string reg2_string = (this->*GetName2)(*reg2);
893 size_t reg2_index;
894 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
895 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
896 }
897
898 if (str.size() > 0) {
899 str += "\n";
900 }
901 str += base;
902 }
903 }
904 // Add a newline at the end.
905 str += "\n";
906 return str;
907 }
908
Chris Larsen51417632015-10-02 13:24:25 -0700909 template <typename Reg1, typename Reg2>
910 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
911 const std::vector<Reg1*> reg1_registers,
912 const std::vector<Reg2*> reg2_registers,
913 std::string (AssemblerTest::*GetName1)(const Reg1&),
914 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700915 const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -0700916 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
917
918 std::string str;
919 for (auto reg1 : reg1_registers) {
920 for (auto reg2 : reg2_registers) {
921 if (reg1 == reg2) continue;
Aart Bik5dafb3c2017-09-13 13:10:12 -0700922 if (f != nullptr) {
923 (assembler_.get()->*f)(*reg1, *reg2);
924 }
Chris Larsen51417632015-10-02 13:24:25 -0700925 std::string base = fmt;
926
927 std::string reg1_string = (this->*GetName1)(*reg1);
928 size_t reg1_index;
929 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
930 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
931 }
932
933 std::string reg2_string = (this->*GetName2)(*reg2);
934 size_t reg2_index;
935 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
936 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
937 }
938
939 if (str.size() > 0) {
940 str += "\n";
941 }
942 str += base;
943 }
944 }
945 // Add a newline at the end.
946 str += "\n";
947 return str;
948 }
949
Chris Larsendbce0d72015-09-17 13:34:00 -0700950 template <typename Reg1, typename Reg2, typename Reg3>
951 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
952 const std::vector<Reg1*> reg1_registers,
953 const std::vector<Reg2*> reg2_registers,
954 const std::vector<Reg3*> reg3_registers,
955 std::string (AssemblerTest::*GetName1)(const Reg1&),
956 std::string (AssemblerTest::*GetName2)(const Reg2&),
957 std::string (AssemblerTest::*GetName3)(const Reg3&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700958 const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700959 std::string str;
960 for (auto reg1 : reg1_registers) {
961 for (auto reg2 : reg2_registers) {
962 for (auto reg3 : reg3_registers) {
Aart Bik5dafb3c2017-09-13 13:10:12 -0700963 if (f != nullptr) {
964 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
965 }
Chris Larsendbce0d72015-09-17 13:34:00 -0700966 std::string base = fmt;
967
968 std::string reg1_string = (this->*GetName1)(*reg1);
969 size_t reg1_index;
970 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
971 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
972 }
973
974 std::string reg2_string = (this->*GetName2)(*reg2);
975 size_t reg2_index;
976 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
977 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
978 }
979
980 std::string reg3_string = (this->*GetName3)(*reg3);
981 size_t reg3_index;
982 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
983 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
984 }
985
986 if (str.size() > 0) {
987 str += "\n";
988 }
989 str += base;
990 }
991 }
992 }
993 // Add a newline at the end.
994 str += "\n";
995 return str;
996 }
997
Mark Mendellfb8d2792015-03-31 22:16:59 -0400998 template <typename Reg1, typename Reg2>
999 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
1000 const std::vector<Reg1*> reg1_registers,
1001 const std::vector<Reg2*> reg2_registers,
1002 std::string (AssemblerTest::*GetName1)(const Reg1&),
1003 std::string (AssemblerTest::*GetName2)(const Reg2&),
1004 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001005 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001006 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1007 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
1008
1009 std::string str;
1010 for (auto reg1 : reg1_registers) {
1011 for (auto reg2 : reg2_registers) {
1012 for (int64_t imm : imms) {
1013 Imm new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -07001014 if (f != nullptr) {
1015 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
1016 }
Mark Mendellfb8d2792015-03-31 22:16:59 -04001017 std::string base = fmt;
1018
1019 std::string reg1_string = (this->*GetName1)(*reg1);
1020 size_t reg1_index;
1021 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1022 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1023 }
1024
1025 std::string reg2_string = (this->*GetName2)(*reg2);
1026 size_t reg2_index;
1027 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1028 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1029 }
1030
1031 size_t imm_index = base.find(IMM_TOKEN);
1032 if (imm_index != std::string::npos) {
1033 std::ostringstream sreg;
1034 sreg << imm;
1035 std::string imm_string = sreg.str();
1036 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1037 }
1038
1039 if (str.size() > 0) {
1040 str += "\n";
1041 }
1042 str += base;
1043 }
1044 }
1045 }
1046 // Add a newline at the end.
1047 str += "\n";
1048 return str;
1049 }
1050
Andreas Gampe851df202014-11-12 14:05:46 -08001051 template <RegisterView kRegView>
1052 std::string GetRegName(const Reg& reg) {
1053 std::ostringstream sreg;
1054 switch (kRegView) {
1055 case RegisterView::kUsePrimaryName:
1056 sreg << reg;
1057 break;
1058
1059 case RegisterView::kUseSecondaryName:
1060 sreg << GetSecondaryRegisterName(reg);
1061 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -07001062
1063 case RegisterView::kUseTertiaryName:
1064 sreg << GetTertiaryRegisterName(reg);
1065 break;
1066
1067 case RegisterView::kUseQuaternaryName:
1068 sreg << GetQuaternaryRegisterName(reg);
1069 break;
Andreas Gampe851df202014-11-12 14:05:46 -08001070 }
1071 return sreg.str();
1072 }
1073
1074 std::string GetFPRegName(const FPReg& reg) {
1075 std::ostringstream sreg;
1076 sreg << reg;
1077 return sreg.str();
1078 }
1079
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001080 std::string GetVecRegName(const VecReg& reg) {
1081 std::ostringstream sreg;
1082 sreg << reg;
1083 return sreg.str();
1084 }
1085
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001086 // If the assembly file needs a header, return it in a sub-class.
1087 virtual const char* GetAssemblyHeader() {
1088 return nullptr;
1089 }
1090
1091 void WarnOnCombinations(size_t count) {
1092 if (count > kWarnManyCombinationsThreshold) {
1093 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1094 }
1095 }
1096
1097 static constexpr const char* REG_TOKEN = "{reg}";
1098 static constexpr const char* REG1_TOKEN = "{reg1}";
1099 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -07001100 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001101 static constexpr const char* IMM_TOKEN = "{imm}";
1102
1103 private:
Andreas Gampe851df202014-11-12 14:05:46 -08001104 template <RegisterView kRegView>
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001105 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1106 size_t imm_bytes,
1107 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -08001108 const std::vector<Reg*> registers = GetRegisters();
1109 std::string str;
1110 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001111
1112 WarnOnCombinations(registers.size() * imms.size());
1113
Andreas Gampe851df202014-11-12 14:05:46 -08001114 for (auto reg : registers) {
1115 for (int64_t imm : imms) {
1116 Imm new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -07001117 if (f != nullptr) {
1118 (assembler_.get()->*f)(*reg, new_imm);
1119 }
Andreas Gampe851df202014-11-12 14:05:46 -08001120 std::string base = fmt;
1121
1122 std::string reg_string = GetRegName<kRegView>(*reg);
1123 size_t reg_index;
1124 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1125 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1126 }
1127
1128 size_t imm_index = base.find(IMM_TOKEN);
1129 if (imm_index != std::string::npos) {
1130 std::ostringstream sreg;
1131 sreg << imm;
1132 std::string imm_string = sreg.str();
1133 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1134 }
1135
1136 if (str.size() > 0) {
1137 str += "\n";
1138 }
1139 str += base;
1140 }
1141 }
1142 // Add a newline at the end.
1143 str += "\n";
1144 return str;
1145 }
1146
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001147 // Override this to pad the code with NOPs to a certain size if needed.
1148 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1149 }
1150
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001151 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001152 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001153 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -07001154 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001155 MemoryRegion code(&(*data)[0], data->size());
1156 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001157 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001158 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001159 }
1160
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001161 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -08001162
Vladimir Marko93205e32016-04-13 11:59:46 +01001163 ArenaPool pool_;
1164 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -07001165 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001166 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -07001167
Andreas Gampe851df202014-11-12 14:05:46 -08001168 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001169};
1170
1171} // namespace art
1172
1173#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_