blob: d265a440925191bd6795810101e5107d6d5c6bd1 [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
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +000045// For use in the template as the default type to get a nonvector registers version.
46struct NoVectorRegs {};
47
48template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070049class AssemblerTest : public testing::Test {
50 public:
51 Ass* GetAssembler() {
52 return assembler_.get();
53 }
54
Andreas Gampe851df202014-11-12 14:05:46 -080055 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070056
Andreas Gampe2e965ac2016-11-03 17:24:15 -070057 void DriverFn(TestFn f, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070058 DriverWrapper(f(this, assembler_.get()), test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070059 }
60
61 // This driver assumes the assembler has already been called.
Andreas Gampe2e965ac2016-11-03 17:24:15 -070062 void DriverStr(const std::string& assembly_string, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070063 DriverWrapper(assembly_string, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070064 }
65
Andreas Gampe2e965ac2016-11-03 17:24:15 -070066 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080067 return RepeatTemplatedRegister<Reg>(f,
68 GetRegisters(),
69 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
70 fmt);
71 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070072
Andreas Gampe2e965ac2016-11-03 17:24:15 -070073 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080074 return RepeatTemplatedRegister<Reg>(f,
75 GetRegisters(),
76 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
77 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070078 }
79
Andreas Gampe2e965ac2016-11-03 17:24:15 -070080 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080081 return RepeatTemplatedRegisters<Reg, Reg>(f,
82 GetRegisters(),
83 GetRegisters(),
84 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
85 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
86 fmt);
87 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070088
Andreas Gampe2e965ac2016-11-03 17:24:15 -070089 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -070090 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
91 GetRegisters(),
92 GetRegisters(),
93 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
94 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
95 fmt);
96 }
97
Andreas Gampe2e965ac2016-11-03 17:24:15 -070098 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080099 return RepeatTemplatedRegisters<Reg, Reg>(f,
100 GetRegisters(),
101 GetRegisters(),
102 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
103 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
104 fmt);
105 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700106
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700107 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700108 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
109 GetRegisters(),
110 GetRegisters(),
111 GetRegisters(),
112 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
113 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
114 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
115 fmt);
116 }
117
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700118 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chao-ying Fud23840d2015-04-07 16:03:04 -0700119 return RepeatTemplatedRegisters<Reg, Reg>(f,
120 GetRegisters(),
121 GetRegisters(),
122 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
123 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
124 fmt);
125 }
126
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700127 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800128 return RepeatTemplatedRegisters<Reg, Reg>(f,
129 GetRegisters(),
130 GetRegisters(),
131 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
132 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
133 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700134 }
135
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700136 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800137 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700138 }
139
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700140 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800141 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
142 }
143
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200144 template <typename Reg1, typename Reg2, typename ImmType>
145 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
146 int imm_bits,
147 const std::vector<Reg1*> reg1_registers,
148 const std::vector<Reg2*> reg2_registers,
149 std::string (AssemblerTest::*GetName1)(const Reg1&),
150 std::string (AssemblerTest::*GetName2)(const Reg2&),
Chris Larsene3660592016-11-09 11:13:42 -0800151 const std::string& fmt,
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000152 int bias = 0,
153 int multiplier = 1) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700154 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800155 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Chris Larsendbce0d72015-09-17 13:34:00 -0700156
157 for (auto reg1 : reg1_registers) {
158 for (auto reg2 : reg2_registers) {
159 for (int64_t imm : imms) {
160 ImmType new_imm = CreateImmediate(imm);
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000161 (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700162 std::string base = fmt;
163
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200164 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700165 size_t reg1_index;
166 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
167 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
168 }
169
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200170 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700171 size_t reg2_index;
172 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
173 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
174 }
175
176 size_t imm_index = base.find(IMM_TOKEN);
177 if (imm_index != std::string::npos) {
178 std::ostringstream sreg;
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000179 sreg << imm * multiplier + bias;
Chris Larsendbce0d72015-09-17 13:34:00 -0700180 std::string imm_string = sreg.str();
181 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
182 }
183
184 if (str.size() > 0) {
185 str += "\n";
186 }
187 str += base;
188 }
189 }
190 }
191 // Add a newline at the end.
192 str += "\n";
193 return str;
194 }
195
Chris Larsene3660592016-11-09 11:13:42 -0800196 template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
197 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
198 int imm_bits,
199 const std::vector<Reg1*> reg1_registers,
200 const std::vector<Reg2*> reg2_registers,
201 const std::vector<Reg3*> reg3_registers,
202 std::string (AssemblerTest::*GetName1)(const Reg1&),
203 std::string (AssemblerTest::*GetName2)(const Reg2&),
204 std::string (AssemblerTest::*GetName3)(const Reg3&),
205 std::string fmt,
206 int bias) {
207 std::string str;
208 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
209
210 for (auto reg1 : reg1_registers) {
211 for (auto reg2 : reg2_registers) {
212 for (auto reg3 : reg3_registers) {
213 for (int64_t imm : imms) {
214 ImmType new_imm = CreateImmediate(imm);
215 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
216 std::string base = fmt;
217
218 std::string reg1_string = (this->*GetName1)(*reg1);
219 size_t reg1_index;
220 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
221 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
222 }
223
224 std::string reg2_string = (this->*GetName2)(*reg2);
225 size_t reg2_index;
226 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
227 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
228 }
229
230 std::string reg3_string = (this->*GetName3)(*reg3);
231 size_t reg3_index;
232 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
233 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
234 }
235
236 size_t imm_index = base.find(IMM_TOKEN);
237 if (imm_index != std::string::npos) {
238 std::ostringstream sreg;
239 sreg << imm + bias;
240 std::string imm_string = sreg.str();
241 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
242 }
243
244 if (str.size() > 0) {
245 str += "\n";
246 }
247 str += base;
248 }
249 }
250 }
251 }
252 // Add a newline at the end.
253 str += "\n";
254 return str;
255 }
256
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800257 template <typename ImmType, typename Reg1, typename Reg2>
258 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
259 const std::vector<Reg1*> reg1_registers,
260 const std::vector<Reg2*> reg2_registers,
261 std::string (AssemblerTest::*GetName1)(const Reg1&),
262 std::string (AssemblerTest::*GetName2)(const Reg2&),
263 int imm_bits,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700264 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800265 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
266
267 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
268
269 std::string str;
270 for (auto reg1 : reg1_registers) {
271 for (auto reg2 : reg2_registers) {
272 for (int64_t imm : imms) {
273 ImmType new_imm = CreateImmediate(imm);
274 (assembler_.get()->*f)(new_imm, *reg1, *reg2);
275 std::string base = fmt;
276
277 std::string reg1_string = (this->*GetName1)(*reg1);
278 size_t reg1_index;
279 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
280 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
281 }
282
283 std::string reg2_string = (this->*GetName2)(*reg2);
284 size_t reg2_index;
285 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
286 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
287 }
288
289 size_t imm_index = base.find(IMM_TOKEN);
290 if (imm_index != std::string::npos) {
291 std::ostringstream sreg;
292 sreg << imm;
293 std::string imm_string = sreg.str();
294 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
295 }
296
297 if (str.size() > 0) {
298 str += "\n";
299 }
300 str += base;
301 }
302 }
303 }
304 // Add a newline at the end.
305 str += "\n";
306 return str;
307 }
308
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200309 template <typename RegType, typename ImmType>
310 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800311 int imm_bits,
312 const std::vector<Reg*> registers,
313 std::string (AssemblerTest::*GetName)(const RegType&),
Chris Larsene3660592016-11-09 11:13:42 -0800314 const std::string& fmt,
315 int bias) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200316 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800317 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200318
319 for (auto reg : registers) {
320 for (int64_t imm : imms) {
321 ImmType new_imm = CreateImmediate(imm);
Chris Larsene3660592016-11-09 11:13:42 -0800322 (assembler_.get()->*f)(*reg, new_imm + bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200323 std::string base = fmt;
324
325 std::string reg_string = (this->*GetName)(*reg);
326 size_t reg_index;
327 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
328 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
329 }
330
331 size_t imm_index = base.find(IMM_TOKEN);
332 if (imm_index != std::string::npos) {
333 std::ostringstream sreg;
Chris Larsene3660592016-11-09 11:13:42 -0800334 sreg << imm + bias;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200335 std::string imm_string = sreg.str();
336 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
337 }
338
339 if (str.size() > 0) {
340 str += "\n";
341 }
342 str += base;
343 }
344 }
345 // Add a newline at the end.
346 str += "\n";
347 return str;
348 }
349
350 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800351 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
352 int imm_bits,
353 const std::string& fmt,
354 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200355 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
356 imm_bits,
357 GetRegisters(),
358 GetRegisters(),
359 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
360 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800361 fmt,
362 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200363 }
364
365 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800366 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
367 int imm_bits,
368 const std::string& fmt,
369 int bias = 0) {
370 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
371 imm_bits,
372 GetRegisters(),
373 GetRegisters(),
374 GetRegisters(),
375 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
376 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
377 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
378 fmt,
379 bias);
380 }
381
382 template <typename ImmType>
383 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200384 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
385 imm_bits,
386 GetRegisters(),
387 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800388 fmt,
389 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200390 }
391
392 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700393 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
394 int imm_bits,
Chris Larsene3660592016-11-09 11:13:42 -0800395 const std::string& fmt,
396 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200397 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
398 imm_bits,
399 GetFPRegisters(),
400 GetRegisters(),
401 &AssemblerTest::GetFPRegName,
402 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800403 fmt,
404 bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700405 }
406
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700407 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800408 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
409 GetFPRegisters(),
410 GetFPRegisters(),
411 &AssemblerTest::GetFPRegName,
412 &AssemblerTest::GetFPRegName,
413 fmt);
414 }
415
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700416 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700417 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
418 GetFPRegisters(),
419 GetFPRegisters(),
420 GetFPRegisters(),
421 &AssemblerTest::GetFPRegName,
422 &AssemblerTest::GetFPRegName,
423 &AssemblerTest::GetFPRegName,
424 fmt);
425 }
426
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700427 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700428 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
429 f,
430 GetFPRegisters(),
431 GetFPRegisters(),
432 GetRegisters(),
433 &AssemblerTest::GetFPRegName,
434 &AssemblerTest::GetFPRegName,
435 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
436 fmt);
437 }
438
Chris Larsendbce0d72015-09-17 13:34:00 -0700439 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
440 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700441 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400442 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700443 GetFPRegisters(),
444 GetFPRegisters(),
445 &AssemblerTest::GetFPRegName,
446 &AssemblerTest::GetFPRegName,
447 imm_bytes,
448 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400449 }
450
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800451 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700452 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
453 int imm_bits,
454 const std::string& fmt) {
Alexey Frunzea8aaf5a2016-06-27 14:48:20 -0700455 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
456 imm_bits,
457 GetFPRegisters(),
458 GetFPRegisters(),
459 &AssemblerTest::GetFPRegName,
460 &AssemblerTest::GetFPRegName,
461 fmt);
462 }
463
464 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700465 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
466 int imm_bits,
467 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800468 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
469 GetFPRegisters(),
470 GetFPRegisters(),
471 &AssemblerTest::GetFPRegName,
472 &AssemblerTest::GetFPRegName,
473 imm_bits,
474 fmt);
475 }
476
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700477 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800478 return RepeatTemplatedRegisters<FPReg, Reg>(f,
479 GetFPRegisters(),
480 GetRegisters(),
481 &AssemblerTest::GetFPRegName,
482 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
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::kUseSecondaryName>,
492 fmt);
493 }
494
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700495 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800496 return RepeatTemplatedRegisters<Reg, FPReg>(f,
497 GetRegisters(),
498 GetFPRegisters(),
499 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
500 &AssemblerTest::GetFPRegName,
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::kUseSecondaryName>,
509 &AssemblerTest::GetFPRegName,
510 fmt);
511 }
512
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700513 std::string RepeatI(void (Ass::*f)(const Imm&),
514 size_t imm_bytes,
515 const std::string& fmt,
Andreas Gampe851df202014-11-12 14:05:46 -0800516 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700517 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800518 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800519
520 WarnOnCombinations(imms.size());
521
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700522 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700523 Imm new_imm = CreateImmediate(imm);
524 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700525 std::string base = fmt;
526
Andreas Gampe851df202014-11-12 14:05:46 -0800527 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700528 if (imm_index != std::string::npos) {
529 std::ostringstream sreg;
530 sreg << imm;
531 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800532 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700533 }
534
535 if (str.size() > 0) {
536 str += "\n";
537 }
538 str += base;
539 }
540 // Add a newline at the end.
541 str += "\n";
542 return str;
543 }
544
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000545 std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
546 return RepeatTemplatedRegisters<VecReg, VecReg>(f,
547 GetVectorRegisters(),
548 GetVectorRegisters(),
549 &AssemblerTest::GetVecRegName,
550 &AssemblerTest::GetVecRegName,
551 fmt);
552 }
553
554 std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
555 return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
556 GetVectorRegisters(),
557 GetVectorRegisters(),
558 GetVectorRegisters(),
559 &AssemblerTest::GetVecRegName,
560 &AssemblerTest::GetVecRegName,
561 &AssemblerTest::GetVecRegName,
562 fmt);
563 }
564
565 std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
566 return RepeatTemplatedRegisters<VecReg, Reg>(
567 f,
568 GetVectorRegisters(),
569 GetRegisters(),
570 &AssemblerTest::GetVecRegName,
571 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
572 fmt);
573 }
574
575 template <typename ImmType>
576 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
577 int imm_bits,
578 const std::string& fmt,
579 int bias = 0,
580 int multiplier = 1) {
581 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
582 f,
583 imm_bits,
584 GetVectorRegisters(),
585 GetRegisters(),
586 &AssemblerTest::GetVecRegName,
587 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
588 fmt,
589 bias,
590 multiplier);
591 }
592
593 template <typename ImmType>
594 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
595 int imm_bits,
596 const std::string& fmt,
597 int bias = 0) {
598 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
599 imm_bits,
600 GetVectorRegisters(),
601 GetVectorRegisters(),
602 &AssemblerTest::GetVecRegName,
603 &AssemblerTest::GetVecRegName,
604 fmt,
605 bias);
606 }
607
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700608 // This is intended to be run as a test.
609 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700610 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700611 }
612
Andreas Gampe851df202014-11-12 14:05:46 -0800613 // The following functions are public so that TestFn can use them...
614
615 virtual std::vector<Reg*> GetRegisters() = 0;
616
617 virtual std::vector<FPReg*> GetFPRegisters() {
618 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
619 UNREACHABLE();
620 }
621
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000622 virtual std::vector<VecReg*> GetVectorRegisters() {
623 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
624 UNREACHABLE();
625 }
626
Andreas Gampe851df202014-11-12 14:05:46 -0800627 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
628 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
629 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
630 UNREACHABLE();
631 }
632
Chao-ying Fud23840d2015-04-07 16:03:04 -0700633 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
634 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
635 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
636 UNREACHABLE();
637 }
638
639 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
640 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
641 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
642 UNREACHABLE();
643 }
644
Calin Juravle9aec02f2014-11-18 23:06:35 +0000645 std::string GetRegisterName(const Reg& reg) {
646 return GetRegName<RegisterView::kUsePrimaryName>(reg);
647 }
648
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700649 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800650 explicit AssemblerTest() {}
651
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700652 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100653 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700654 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700655 test_helper_.reset(
656 new AssemblerTestInfrastructure(GetArchitectureString(),
657 GetAssemblerCmdName(),
658 GetAssemblerParameters(),
659 GetObjdumpCmdName(),
660 GetObjdumpParameters(),
661 GetDisassembleCmdName(),
662 GetDisassembleParameters(),
663 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700664
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700665 SetUpHelpers();
666 }
667
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700668 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700669 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100670 assembler_.reset();
671 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700672 }
673
Chris Larsen3add9cb2016-04-14 14:01:33 -0700674 // Override this to set up any architecture-specific things, e.g., CPU revision.
675 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
676 return new (arena) Ass(arena);
677 }
678
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700679 // Override this to set up any architecture-specific things, e.g., register vectors.
680 virtual void SetUpHelpers() {}
681
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700682 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
683 virtual std::string GetArchitectureString() = 0;
684
685 // Get the name of the assembler, e.g., "as" by default.
686 virtual std::string GetAssemblerCmdName() {
687 return "as";
688 }
689
690 // Switches to the assembler command. Default none.
691 virtual std::string GetAssemblerParameters() {
692 return "";
693 }
694
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700695 // Get the name of the objdump, e.g., "objdump" by default.
696 virtual std::string GetObjdumpCmdName() {
697 return "objdump";
698 }
699
700 // Switches to the objdump command. Default is " -h".
701 virtual std::string GetObjdumpParameters() {
702 return " -h";
703 }
704
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700705 // Get the name of the objdump, e.g., "objdump" by default.
706 virtual std::string GetDisassembleCmdName() {
707 return "objdump";
708 }
709
710 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
711 // such to objdump, so it's architecture-specific and there is no default.
712 virtual std::string GetDisassembleParameters() = 0;
713
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700714 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800715 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700716 std::vector<int64_t> res;
717 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800718 if (!as_uint) {
719 res.push_back(-1);
720 } else {
721 res.push_back(0xFF);
722 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700723 res.push_back(0x12);
724 if (imm_bytes >= 2) {
725 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800726 if (!as_uint) {
727 res.push_back(-0x1234);
728 } else {
729 res.push_back(0xFFFF);
730 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700731 if (imm_bytes >= 4) {
732 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800733 if (!as_uint) {
734 res.push_back(-0x12345678);
735 } else {
736 res.push_back(0xFFFFFFFF);
737 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700738 if (imm_bytes >= 6) {
739 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800740 if (!as_uint) {
741 res.push_back(-0x123456789ABC);
742 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700743 if (imm_bytes >= 8) {
744 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800745 if (!as_uint) {
746 res.push_back(-0x123456789ABCDEF0);
747 } else {
748 res.push_back(0xFFFFFFFFFFFFFFFF);
749 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700750 }
751 }
752 }
753 }
754 return res;
755 }
756
Chris Larsendbce0d72015-09-17 13:34:00 -0700757 const int kMaxBitsExhaustiveTest = 8;
758
759 // Create a couple of immediate values up to the number of bits given.
760 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
761 CHECK_GT(imm_bits, 0);
762 CHECK_LE(imm_bits, 64);
763 std::vector<int64_t> res;
764
765 if (imm_bits <= kMaxBitsExhaustiveTest) {
766 if (as_uint) {
767 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
768 res.push_back(static_cast<int64_t>(i));
769 }
770 } else {
771 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
772 res.push_back(i);
773 }
774 }
775 } else {
776 if (as_uint) {
777 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
778 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
779 i++) {
780 res.push_back(static_cast<int64_t>(i));
781 }
782 for (int i = 0; i <= imm_bits; i++) {
783 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
784 ((MaxInt<uint64_t>(imm_bits) -
785 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
786 * i / imm_bits);
787 res.push_back(static_cast<int64_t>(j));
788 }
789 } else {
790 for (int i = 0; i <= imm_bits; i++) {
791 int64_t j = MinInt<int64_t>(imm_bits) +
792 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
793 MinInt<int64_t>(imm_bits))
794 * i) / imm_bits);
795 res.push_back(static_cast<int64_t>(j));
796 }
797 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
798 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
799 i++) {
800 res.push_back(static_cast<int64_t>(i));
801 }
802 for (int i = 0; i <= imm_bits; i++) {
803 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
804 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
805 * i / imm_bits);
806 res.push_back(static_cast<int64_t>(j));
807 }
808 }
809 }
810
811 return res;
812 }
813
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700814 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700815 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700816
Andreas Gampe851df202014-11-12 14:05:46 -0800817 template <typename RegType>
818 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
819 const std::vector<RegType*> registers,
820 std::string (AssemblerTest::*GetName)(const RegType&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700821 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800822 std::string str;
823 for (auto reg : registers) {
824 (assembler_.get()->*f)(*reg);
825 std::string base = fmt;
826
827 std::string reg_string = (this->*GetName)(*reg);
828 size_t reg_index;
829 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
830 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
831 }
832
833 if (str.size() > 0) {
834 str += "\n";
835 }
836 str += base;
837 }
838 // Add a newline at the end.
839 str += "\n";
840 return str;
841 }
842
843 template <typename Reg1, typename Reg2>
844 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
845 const std::vector<Reg1*> reg1_registers,
846 const std::vector<Reg2*> reg2_registers,
847 std::string (AssemblerTest::*GetName1)(const Reg1&),
848 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700849 const std::string& fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800850 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
851
Andreas Gampe851df202014-11-12 14:05:46 -0800852 std::string str;
853 for (auto reg1 : reg1_registers) {
854 for (auto reg2 : reg2_registers) {
855 (assembler_.get()->*f)(*reg1, *reg2);
856 std::string base = fmt;
857
858 std::string reg1_string = (this->*GetName1)(*reg1);
859 size_t reg1_index;
860 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
861 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
862 }
863
864 std::string reg2_string = (this->*GetName2)(*reg2);
865 size_t reg2_index;
866 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
867 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
868 }
869
870 if (str.size() > 0) {
871 str += "\n";
872 }
873 str += base;
874 }
875 }
876 // Add a newline at the end.
877 str += "\n";
878 return str;
879 }
880
Chris Larsen51417632015-10-02 13:24:25 -0700881 template <typename Reg1, typename Reg2>
882 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
883 const std::vector<Reg1*> reg1_registers,
884 const std::vector<Reg2*> reg2_registers,
885 std::string (AssemblerTest::*GetName1)(const Reg1&),
886 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700887 const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -0700888 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
889
890 std::string str;
891 for (auto reg1 : reg1_registers) {
892 for (auto reg2 : reg2_registers) {
893 if (reg1 == reg2) continue;
894 (assembler_.get()->*f)(*reg1, *reg2);
895 std::string base = fmt;
896
897 std::string reg1_string = (this->*GetName1)(*reg1);
898 size_t reg1_index;
899 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
900 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
901 }
902
903 std::string reg2_string = (this->*GetName2)(*reg2);
904 size_t reg2_index;
905 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
906 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
907 }
908
909 if (str.size() > 0) {
910 str += "\n";
911 }
912 str += base;
913 }
914 }
915 // Add a newline at the end.
916 str += "\n";
917 return str;
918 }
919
Chris Larsendbce0d72015-09-17 13:34:00 -0700920 template <typename Reg1, typename Reg2, typename Reg3>
921 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
922 const std::vector<Reg1*> reg1_registers,
923 const std::vector<Reg2*> reg2_registers,
924 const std::vector<Reg3*> reg3_registers,
925 std::string (AssemblerTest::*GetName1)(const Reg1&),
926 std::string (AssemblerTest::*GetName2)(const Reg2&),
927 std::string (AssemblerTest::*GetName3)(const Reg3&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700928 const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700929 std::string str;
930 for (auto reg1 : reg1_registers) {
931 for (auto reg2 : reg2_registers) {
932 for (auto reg3 : reg3_registers) {
933 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
934 std::string base = fmt;
935
936 std::string reg1_string = (this->*GetName1)(*reg1);
937 size_t reg1_index;
938 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
939 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
940 }
941
942 std::string reg2_string = (this->*GetName2)(*reg2);
943 size_t reg2_index;
944 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
945 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
946 }
947
948 std::string reg3_string = (this->*GetName3)(*reg3);
949 size_t reg3_index;
950 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
951 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
952 }
953
954 if (str.size() > 0) {
955 str += "\n";
956 }
957 str += base;
958 }
959 }
960 }
961 // Add a newline at the end.
962 str += "\n";
963 return str;
964 }
965
Mark Mendellfb8d2792015-03-31 22:16:59 -0400966 template <typename Reg1, typename Reg2>
967 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
968 const std::vector<Reg1*> reg1_registers,
969 const std::vector<Reg2*> reg2_registers,
970 std::string (AssemblerTest::*GetName1)(const Reg1&),
971 std::string (AssemblerTest::*GetName2)(const Reg2&),
972 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700973 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400974 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
975 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
976
977 std::string str;
978 for (auto reg1 : reg1_registers) {
979 for (auto reg2 : reg2_registers) {
980 for (int64_t imm : imms) {
981 Imm new_imm = CreateImmediate(imm);
982 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
983 std::string base = fmt;
984
985 std::string reg1_string = (this->*GetName1)(*reg1);
986 size_t reg1_index;
987 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
988 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
989 }
990
991 std::string reg2_string = (this->*GetName2)(*reg2);
992 size_t reg2_index;
993 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
994 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
995 }
996
997 size_t imm_index = base.find(IMM_TOKEN);
998 if (imm_index != std::string::npos) {
999 std::ostringstream sreg;
1000 sreg << imm;
1001 std::string imm_string = sreg.str();
1002 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1003 }
1004
1005 if (str.size() > 0) {
1006 str += "\n";
1007 }
1008 str += base;
1009 }
1010 }
1011 }
1012 // Add a newline at the end.
1013 str += "\n";
1014 return str;
1015 }
1016
Andreas Gampe851df202014-11-12 14:05:46 -08001017 template <RegisterView kRegView>
1018 std::string GetRegName(const Reg& reg) {
1019 std::ostringstream sreg;
1020 switch (kRegView) {
1021 case RegisterView::kUsePrimaryName:
1022 sreg << reg;
1023 break;
1024
1025 case RegisterView::kUseSecondaryName:
1026 sreg << GetSecondaryRegisterName(reg);
1027 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -07001028
1029 case RegisterView::kUseTertiaryName:
1030 sreg << GetTertiaryRegisterName(reg);
1031 break;
1032
1033 case RegisterView::kUseQuaternaryName:
1034 sreg << GetQuaternaryRegisterName(reg);
1035 break;
Andreas Gampe851df202014-11-12 14:05:46 -08001036 }
1037 return sreg.str();
1038 }
1039
1040 std::string GetFPRegName(const FPReg& reg) {
1041 std::ostringstream sreg;
1042 sreg << reg;
1043 return sreg.str();
1044 }
1045
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001046 std::string GetVecRegName(const VecReg& reg) {
1047 std::ostringstream sreg;
1048 sreg << reg;
1049 return sreg.str();
1050 }
1051
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001052 // If the assembly file needs a header, return it in a sub-class.
1053 virtual const char* GetAssemblyHeader() {
1054 return nullptr;
1055 }
1056
1057 void WarnOnCombinations(size_t count) {
1058 if (count > kWarnManyCombinationsThreshold) {
1059 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1060 }
1061 }
1062
1063 static constexpr const char* REG_TOKEN = "{reg}";
1064 static constexpr const char* REG1_TOKEN = "{reg1}";
1065 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -07001066 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001067 static constexpr const char* IMM_TOKEN = "{imm}";
1068
1069 private:
Andreas Gampe851df202014-11-12 14:05:46 -08001070 template <RegisterView kRegView>
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001071 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1072 size_t imm_bytes,
1073 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -08001074 const std::vector<Reg*> registers = GetRegisters();
1075 std::string str;
1076 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001077
1078 WarnOnCombinations(registers.size() * imms.size());
1079
Andreas Gampe851df202014-11-12 14:05:46 -08001080 for (auto reg : registers) {
1081 for (int64_t imm : imms) {
1082 Imm new_imm = CreateImmediate(imm);
1083 (assembler_.get()->*f)(*reg, new_imm);
1084 std::string base = fmt;
1085
1086 std::string reg_string = GetRegName<kRegView>(*reg);
1087 size_t reg_index;
1088 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1089 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1090 }
1091
1092 size_t imm_index = base.find(IMM_TOKEN);
1093 if (imm_index != std::string::npos) {
1094 std::ostringstream sreg;
1095 sreg << imm;
1096 std::string imm_string = sreg.str();
1097 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1098 }
1099
1100 if (str.size() > 0) {
1101 str += "\n";
1102 }
1103 str += base;
1104 }
1105 }
1106 // Add a newline at the end.
1107 str += "\n";
1108 return str;
1109 }
1110
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001111 // Override this to pad the code with NOPs to a certain size if needed.
1112 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1113 }
1114
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001115 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001116 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001117 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -07001118 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001119 MemoryRegion code(&(*data)[0], data->size());
1120 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001121 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001122 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001123 }
1124
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001125 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -08001126
Vladimir Marko93205e32016-04-13 11:59:46 +01001127 ArenaPool pool_;
1128 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -07001129 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001130 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -07001131
Andreas Gampe851df202014-11-12 14:05:46 -08001132 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001133};
1134
1135} // namespace art
1136
1137#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_