blob: f655994bd361d98112a818915b02aaf77e52aebc [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,
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200312 const std::vector<RegType*> registers,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800313 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>
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200576 std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
577 int imm_bits,
578 std::string fmt,
579 int bias = 0) {
580 return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
581 imm_bits,
582 GetVectorRegisters(),
583 &AssemblerTest::GetVecRegName,
584 fmt,
585 bias);
586 }
587
588 template <typename ImmType>
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000589 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
590 int imm_bits,
591 const std::string& fmt,
592 int bias = 0,
593 int multiplier = 1) {
594 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
595 f,
596 imm_bits,
597 GetVectorRegisters(),
598 GetRegisters(),
599 &AssemblerTest::GetVecRegName,
600 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
601 fmt,
602 bias,
603 multiplier);
604 }
605
606 template <typename ImmType>
607 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
608 int imm_bits,
609 const std::string& fmt,
610 int bias = 0) {
611 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
612 imm_bits,
613 GetVectorRegisters(),
614 GetVectorRegisters(),
615 &AssemblerTest::GetVecRegName,
616 &AssemblerTest::GetVecRegName,
617 fmt,
618 bias);
619 }
620
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700621 // This is intended to be run as a test.
622 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700623 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700624 }
625
Andreas Gampe851df202014-11-12 14:05:46 -0800626 // The following functions are public so that TestFn can use them...
627
628 virtual std::vector<Reg*> GetRegisters() = 0;
629
630 virtual std::vector<FPReg*> GetFPRegisters() {
631 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
632 UNREACHABLE();
633 }
634
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000635 virtual std::vector<VecReg*> GetVectorRegisters() {
636 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
637 UNREACHABLE();
638 }
639
Andreas Gampe851df202014-11-12 14:05:46 -0800640 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
641 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
642 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
643 UNREACHABLE();
644 }
645
Chao-ying Fud23840d2015-04-07 16:03:04 -0700646 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
647 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
648 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
649 UNREACHABLE();
650 }
651
652 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
653 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
654 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
655 UNREACHABLE();
656 }
657
Calin Juravle9aec02f2014-11-18 23:06:35 +0000658 std::string GetRegisterName(const Reg& reg) {
659 return GetRegName<RegisterView::kUsePrimaryName>(reg);
660 }
661
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700662 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800663 explicit AssemblerTest() {}
664
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700665 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100666 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700667 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700668 test_helper_.reset(
669 new AssemblerTestInfrastructure(GetArchitectureString(),
670 GetAssemblerCmdName(),
671 GetAssemblerParameters(),
672 GetObjdumpCmdName(),
673 GetObjdumpParameters(),
674 GetDisassembleCmdName(),
675 GetDisassembleParameters(),
676 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700677
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700678 SetUpHelpers();
679 }
680
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700681 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700682 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100683 assembler_.reset();
684 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700685 }
686
Chris Larsen3add9cb2016-04-14 14:01:33 -0700687 // Override this to set up any architecture-specific things, e.g., CPU revision.
688 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
689 return new (arena) Ass(arena);
690 }
691
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700692 // Override this to set up any architecture-specific things, e.g., register vectors.
693 virtual void SetUpHelpers() {}
694
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700695 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
696 virtual std::string GetArchitectureString() = 0;
697
698 // Get the name of the assembler, e.g., "as" by default.
699 virtual std::string GetAssemblerCmdName() {
700 return "as";
701 }
702
703 // Switches to the assembler command. Default none.
704 virtual std::string GetAssemblerParameters() {
705 return "";
706 }
707
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700708 // Get the name of the objdump, e.g., "objdump" by default.
709 virtual std::string GetObjdumpCmdName() {
710 return "objdump";
711 }
712
713 // Switches to the objdump command. Default is " -h".
714 virtual std::string GetObjdumpParameters() {
715 return " -h";
716 }
717
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700718 // Get the name of the objdump, e.g., "objdump" by default.
719 virtual std::string GetDisassembleCmdName() {
720 return "objdump";
721 }
722
723 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
724 // such to objdump, so it's architecture-specific and there is no default.
725 virtual std::string GetDisassembleParameters() = 0;
726
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700727 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800728 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700729 std::vector<int64_t> res;
730 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800731 if (!as_uint) {
732 res.push_back(-1);
733 } else {
734 res.push_back(0xFF);
735 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700736 res.push_back(0x12);
737 if (imm_bytes >= 2) {
738 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800739 if (!as_uint) {
740 res.push_back(-0x1234);
741 } else {
742 res.push_back(0xFFFF);
743 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700744 if (imm_bytes >= 4) {
745 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800746 if (!as_uint) {
747 res.push_back(-0x12345678);
748 } else {
749 res.push_back(0xFFFFFFFF);
750 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700751 if (imm_bytes >= 6) {
752 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800753 if (!as_uint) {
754 res.push_back(-0x123456789ABC);
755 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700756 if (imm_bytes >= 8) {
757 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800758 if (!as_uint) {
759 res.push_back(-0x123456789ABCDEF0);
760 } else {
761 res.push_back(0xFFFFFFFFFFFFFFFF);
762 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700763 }
764 }
765 }
766 }
767 return res;
768 }
769
Chris Larsendbce0d72015-09-17 13:34:00 -0700770 const int kMaxBitsExhaustiveTest = 8;
771
772 // Create a couple of immediate values up to the number of bits given.
773 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
774 CHECK_GT(imm_bits, 0);
775 CHECK_LE(imm_bits, 64);
776 std::vector<int64_t> res;
777
778 if (imm_bits <= kMaxBitsExhaustiveTest) {
779 if (as_uint) {
780 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
781 res.push_back(static_cast<int64_t>(i));
782 }
783 } else {
784 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
785 res.push_back(i);
786 }
787 }
788 } else {
789 if (as_uint) {
790 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
791 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
792 i++) {
793 res.push_back(static_cast<int64_t>(i));
794 }
795 for (int i = 0; i <= imm_bits; i++) {
796 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
797 ((MaxInt<uint64_t>(imm_bits) -
798 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
799 * i / imm_bits);
800 res.push_back(static_cast<int64_t>(j));
801 }
802 } else {
803 for (int i = 0; i <= imm_bits; i++) {
804 int64_t j = MinInt<int64_t>(imm_bits) +
805 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
806 MinInt<int64_t>(imm_bits))
807 * i) / imm_bits);
808 res.push_back(static_cast<int64_t>(j));
809 }
810 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
811 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
812 i++) {
813 res.push_back(static_cast<int64_t>(i));
814 }
815 for (int i = 0; i <= imm_bits; i++) {
816 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
817 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
818 * i / imm_bits);
819 res.push_back(static_cast<int64_t>(j));
820 }
821 }
822 }
823
824 return res;
825 }
826
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700827 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700828 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700829
Andreas Gampe851df202014-11-12 14:05:46 -0800830 template <typename RegType>
831 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
832 const std::vector<RegType*> registers,
833 std::string (AssemblerTest::*GetName)(const RegType&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700834 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800835 std::string str;
836 for (auto reg : registers) {
837 (assembler_.get()->*f)(*reg);
838 std::string base = fmt;
839
840 std::string reg_string = (this->*GetName)(*reg);
841 size_t reg_index;
842 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
843 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
844 }
845
846 if (str.size() > 0) {
847 str += "\n";
848 }
849 str += base;
850 }
851 // Add a newline at the end.
852 str += "\n";
853 return str;
854 }
855
856 template <typename Reg1, typename Reg2>
857 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
858 const std::vector<Reg1*> reg1_registers,
859 const std::vector<Reg2*> reg2_registers,
860 std::string (AssemblerTest::*GetName1)(const Reg1&),
861 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700862 const std::string& fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800863 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
864
Andreas Gampe851df202014-11-12 14:05:46 -0800865 std::string str;
866 for (auto reg1 : reg1_registers) {
867 for (auto reg2 : reg2_registers) {
868 (assembler_.get()->*f)(*reg1, *reg2);
869 std::string base = fmt;
870
871 std::string reg1_string = (this->*GetName1)(*reg1);
872 size_t reg1_index;
873 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
874 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
875 }
876
877 std::string reg2_string = (this->*GetName2)(*reg2);
878 size_t reg2_index;
879 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
880 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
881 }
882
883 if (str.size() > 0) {
884 str += "\n";
885 }
886 str += base;
887 }
888 }
889 // Add a newline at the end.
890 str += "\n";
891 return str;
892 }
893
Chris Larsen51417632015-10-02 13:24:25 -0700894 template <typename Reg1, typename Reg2>
895 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
896 const std::vector<Reg1*> reg1_registers,
897 const std::vector<Reg2*> reg2_registers,
898 std::string (AssemblerTest::*GetName1)(const Reg1&),
899 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700900 const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -0700901 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
902
903 std::string str;
904 for (auto reg1 : reg1_registers) {
905 for (auto reg2 : reg2_registers) {
906 if (reg1 == reg2) continue;
907 (assembler_.get()->*f)(*reg1, *reg2);
908 std::string base = fmt;
909
910 std::string reg1_string = (this->*GetName1)(*reg1);
911 size_t reg1_index;
912 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
913 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
914 }
915
916 std::string reg2_string = (this->*GetName2)(*reg2);
917 size_t reg2_index;
918 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
919 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
920 }
921
922 if (str.size() > 0) {
923 str += "\n";
924 }
925 str += base;
926 }
927 }
928 // Add a newline at the end.
929 str += "\n";
930 return str;
931 }
932
Chris Larsendbce0d72015-09-17 13:34:00 -0700933 template <typename Reg1, typename Reg2, typename Reg3>
934 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
935 const std::vector<Reg1*> reg1_registers,
936 const std::vector<Reg2*> reg2_registers,
937 const std::vector<Reg3*> reg3_registers,
938 std::string (AssemblerTest::*GetName1)(const Reg1&),
939 std::string (AssemblerTest::*GetName2)(const Reg2&),
940 std::string (AssemblerTest::*GetName3)(const Reg3&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700941 const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700942 std::string str;
943 for (auto reg1 : reg1_registers) {
944 for (auto reg2 : reg2_registers) {
945 for (auto reg3 : reg3_registers) {
946 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
947 std::string base = fmt;
948
949 std::string reg1_string = (this->*GetName1)(*reg1);
950 size_t reg1_index;
951 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
952 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
953 }
954
955 std::string reg2_string = (this->*GetName2)(*reg2);
956 size_t reg2_index;
957 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
958 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
959 }
960
961 std::string reg3_string = (this->*GetName3)(*reg3);
962 size_t reg3_index;
963 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
964 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
965 }
966
967 if (str.size() > 0) {
968 str += "\n";
969 }
970 str += base;
971 }
972 }
973 }
974 // Add a newline at the end.
975 str += "\n";
976 return str;
977 }
978
Mark Mendellfb8d2792015-03-31 22:16:59 -0400979 template <typename Reg1, typename Reg2>
980 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
981 const std::vector<Reg1*> reg1_registers,
982 const std::vector<Reg2*> reg2_registers,
983 std::string (AssemblerTest::*GetName1)(const Reg1&),
984 std::string (AssemblerTest::*GetName2)(const Reg2&),
985 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700986 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400987 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
988 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
989
990 std::string str;
991 for (auto reg1 : reg1_registers) {
992 for (auto reg2 : reg2_registers) {
993 for (int64_t imm : imms) {
994 Imm new_imm = CreateImmediate(imm);
995 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
996 std::string base = fmt;
997
998 std::string reg1_string = (this->*GetName1)(*reg1);
999 size_t reg1_index;
1000 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1001 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1002 }
1003
1004 std::string reg2_string = (this->*GetName2)(*reg2);
1005 size_t reg2_index;
1006 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1007 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1008 }
1009
1010 size_t imm_index = base.find(IMM_TOKEN);
1011 if (imm_index != std::string::npos) {
1012 std::ostringstream sreg;
1013 sreg << imm;
1014 std::string imm_string = sreg.str();
1015 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1016 }
1017
1018 if (str.size() > 0) {
1019 str += "\n";
1020 }
1021 str += base;
1022 }
1023 }
1024 }
1025 // Add a newline at the end.
1026 str += "\n";
1027 return str;
1028 }
1029
Andreas Gampe851df202014-11-12 14:05:46 -08001030 template <RegisterView kRegView>
1031 std::string GetRegName(const Reg& reg) {
1032 std::ostringstream sreg;
1033 switch (kRegView) {
1034 case RegisterView::kUsePrimaryName:
1035 sreg << reg;
1036 break;
1037
1038 case RegisterView::kUseSecondaryName:
1039 sreg << GetSecondaryRegisterName(reg);
1040 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -07001041
1042 case RegisterView::kUseTertiaryName:
1043 sreg << GetTertiaryRegisterName(reg);
1044 break;
1045
1046 case RegisterView::kUseQuaternaryName:
1047 sreg << GetQuaternaryRegisterName(reg);
1048 break;
Andreas Gampe851df202014-11-12 14:05:46 -08001049 }
1050 return sreg.str();
1051 }
1052
1053 std::string GetFPRegName(const FPReg& reg) {
1054 std::ostringstream sreg;
1055 sreg << reg;
1056 return sreg.str();
1057 }
1058
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001059 std::string GetVecRegName(const VecReg& reg) {
1060 std::ostringstream sreg;
1061 sreg << reg;
1062 return sreg.str();
1063 }
1064
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001065 // If the assembly file needs a header, return it in a sub-class.
1066 virtual const char* GetAssemblyHeader() {
1067 return nullptr;
1068 }
1069
1070 void WarnOnCombinations(size_t count) {
1071 if (count > kWarnManyCombinationsThreshold) {
1072 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1073 }
1074 }
1075
1076 static constexpr const char* REG_TOKEN = "{reg}";
1077 static constexpr const char* REG1_TOKEN = "{reg1}";
1078 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -07001079 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001080 static constexpr const char* IMM_TOKEN = "{imm}";
1081
1082 private:
Andreas Gampe851df202014-11-12 14:05:46 -08001083 template <RegisterView kRegView>
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001084 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1085 size_t imm_bytes,
1086 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -08001087 const std::vector<Reg*> registers = GetRegisters();
1088 std::string str;
1089 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001090
1091 WarnOnCombinations(registers.size() * imms.size());
1092
Andreas Gampe851df202014-11-12 14:05:46 -08001093 for (auto reg : registers) {
1094 for (int64_t imm : imms) {
1095 Imm new_imm = CreateImmediate(imm);
1096 (assembler_.get()->*f)(*reg, new_imm);
1097 std::string base = fmt;
1098
1099 std::string reg_string = GetRegName<kRegView>(*reg);
1100 size_t reg_index;
1101 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1102 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1103 }
1104
1105 size_t imm_index = base.find(IMM_TOKEN);
1106 if (imm_index != std::string::npos) {
1107 std::ostringstream sreg;
1108 sreg << imm;
1109 std::string imm_string = sreg.str();
1110 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1111 }
1112
1113 if (str.size() > 0) {
1114 str += "\n";
1115 }
1116 str += base;
1117 }
1118 }
1119 // Add a newline at the end.
1120 str += "\n";
1121 return str;
1122 }
1123
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001124 // Override this to pad the code with NOPs to a certain size if needed.
1125 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1126 }
1127
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001128 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001129 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001130 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -07001131 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001132 MemoryRegion code(&(*data)[0], data->size());
1133 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001134 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001135 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001136 }
1137
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001138 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -08001139
Vladimir Marko93205e32016-04-13 11:59:46 +01001140 ArenaPool pool_;
1141 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -07001142 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001143 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -07001144
Andreas Gampe851df202014-11-12 14:05:46 -08001145 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001146};
1147
1148} // namespace art
1149
1150#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_