blob: 12954a4c32a1febc6c0e0fb8e1728cad67f54205 [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
Aart Bikcaa31e72017-09-14 17:08:50 -070049template<typename Ass,
50 typename Addr,
51 typename Reg,
52 typename FPReg,
53 typename Imm,
54 typename VecReg = NoVectorRegs>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070055class AssemblerTest : public testing::Test {
56 public:
57 Ass* GetAssembler() {
58 return assembler_.get();
59 }
60
Andreas Gampe851df202014-11-12 14:05:46 -080061 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070062
Andreas Gampe2e965ac2016-11-03 17:24:15 -070063 void DriverFn(TestFn f, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070064 DriverWrapper(f(this, assembler_.get()), test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070065 }
66
67 // This driver assumes the assembler has already been called.
Andreas Gampe2e965ac2016-11-03 17:24:15 -070068 void DriverStr(const std::string& assembly_string, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070069 DriverWrapper(assembly_string, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070070 }
71
Aart Bikcaa31e72017-09-14 17:08:50 -070072 //
73 // Register repeats.
74 //
75
Andreas Gampe2e965ac2016-11-03 17:24:15 -070076 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080077 return RepeatTemplatedRegister<Reg>(f,
78 GetRegisters(),
79 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
80 fmt);
81 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070082
Andreas Gampe2e965ac2016-11-03 17:24:15 -070083 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080084 return RepeatTemplatedRegister<Reg>(f,
85 GetRegisters(),
86 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
87 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070088 }
89
Andreas Gampe2e965ac2016-11-03 17:24:15 -070090 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080091 return RepeatTemplatedRegisters<Reg, Reg>(f,
92 GetRegisters(),
93 GetRegisters(),
94 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
95 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
96 fmt);
97 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070098
Andreas Gampe2e965ac2016-11-03 17:24:15 -070099 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -0700100 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
101 GetRegisters(),
102 GetRegisters(),
103 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
104 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
105 fmt);
106 }
107
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700108 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800109 return RepeatTemplatedRegisters<Reg, Reg>(f,
110 GetRegisters(),
111 GetRegisters(),
112 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
113 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
114 fmt);
115 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700116
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700117 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700118 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
119 GetRegisters(),
120 GetRegisters(),
121 GetRegisters(),
122 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
123 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
124 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
125 fmt);
126 }
127
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700128 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chao-ying Fud23840d2015-04-07 16:03:04 -0700129 return RepeatTemplatedRegisters<Reg, Reg>(f,
130 GetRegisters(),
131 GetRegisters(),
132 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
133 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
134 fmt);
135 }
136
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700137 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800138 return RepeatTemplatedRegisters<Reg, Reg>(f,
139 GetRegisters(),
140 GetRegisters(),
141 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
142 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
143 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700144 }
145
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700146 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800147 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700148 }
149
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700150 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800151 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
152 }
153
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200154 template <typename Reg1, typename Reg2, typename ImmType>
155 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
156 int imm_bits,
157 const std::vector<Reg1*> reg1_registers,
158 const std::vector<Reg2*> reg2_registers,
159 std::string (AssemblerTest::*GetName1)(const Reg1&),
160 std::string (AssemblerTest::*GetName2)(const Reg2&),
Chris Larsene3660592016-11-09 11:13:42 -0800161 const std::string& fmt,
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000162 int bias = 0,
163 int multiplier = 1) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700164 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800165 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Chris Larsendbce0d72015-09-17 13:34:00 -0700166
167 for (auto reg1 : reg1_registers) {
168 for (auto reg2 : reg2_registers) {
169 for (int64_t imm : imms) {
170 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700171 if (f != nullptr) {
172 (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
173 }
Chris Larsendbce0d72015-09-17 13:34:00 -0700174 std::string base = fmt;
175
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200176 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700177 size_t reg1_index;
178 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
179 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
180 }
181
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200182 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700183 size_t reg2_index;
184 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
185 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
186 }
187
188 size_t imm_index = base.find(IMM_TOKEN);
189 if (imm_index != std::string::npos) {
190 std::ostringstream sreg;
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000191 sreg << imm * multiplier + bias;
Chris Larsendbce0d72015-09-17 13:34:00 -0700192 std::string imm_string = sreg.str();
193 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
194 }
195
196 if (str.size() > 0) {
197 str += "\n";
198 }
199 str += base;
200 }
201 }
202 }
203 // Add a newline at the end.
204 str += "\n";
205 return str;
206 }
207
Chris Larsene3660592016-11-09 11:13:42 -0800208 template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
209 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
210 int imm_bits,
211 const std::vector<Reg1*> reg1_registers,
212 const std::vector<Reg2*> reg2_registers,
213 const std::vector<Reg3*> reg3_registers,
214 std::string (AssemblerTest::*GetName1)(const Reg1&),
215 std::string (AssemblerTest::*GetName2)(const Reg2&),
216 std::string (AssemblerTest::*GetName3)(const Reg3&),
217 std::string fmt,
218 int bias) {
219 std::string str;
220 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
221
222 for (auto reg1 : reg1_registers) {
223 for (auto reg2 : reg2_registers) {
224 for (auto reg3 : reg3_registers) {
225 for (int64_t imm : imms) {
226 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700227 if (f != nullptr) {
228 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
229 }
Chris Larsene3660592016-11-09 11:13:42 -0800230 std::string base = fmt;
231
232 std::string reg1_string = (this->*GetName1)(*reg1);
233 size_t reg1_index;
234 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
235 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
236 }
237
238 std::string reg2_string = (this->*GetName2)(*reg2);
239 size_t reg2_index;
240 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
241 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
242 }
243
244 std::string reg3_string = (this->*GetName3)(*reg3);
245 size_t reg3_index;
246 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
247 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
248 }
249
250 size_t imm_index = base.find(IMM_TOKEN);
251 if (imm_index != std::string::npos) {
252 std::ostringstream sreg;
253 sreg << imm + bias;
254 std::string imm_string = sreg.str();
255 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
256 }
257
258 if (str.size() > 0) {
259 str += "\n";
260 }
261 str += base;
262 }
263 }
264 }
265 }
266 // Add a newline at the end.
267 str += "\n";
268 return str;
269 }
270
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800271 template <typename ImmType, typename Reg1, typename Reg2>
272 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
273 const std::vector<Reg1*> reg1_registers,
274 const std::vector<Reg2*> reg2_registers,
275 std::string (AssemblerTest::*GetName1)(const Reg1&),
276 std::string (AssemblerTest::*GetName2)(const Reg2&),
277 int imm_bits,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700278 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800279 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
280
281 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
282
283 std::string str;
284 for (auto reg1 : reg1_registers) {
285 for (auto reg2 : reg2_registers) {
286 for (int64_t imm : imms) {
287 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700288 if (f != nullptr) {
289 (assembler_.get()->*f)(new_imm, *reg1, *reg2);
290 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800291 std::string base = fmt;
292
293 std::string reg1_string = (this->*GetName1)(*reg1);
294 size_t reg1_index;
295 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
296 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
297 }
298
299 std::string reg2_string = (this->*GetName2)(*reg2);
300 size_t reg2_index;
301 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
302 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
303 }
304
305 size_t imm_index = base.find(IMM_TOKEN);
306 if (imm_index != std::string::npos) {
307 std::ostringstream sreg;
308 sreg << imm;
309 std::string imm_string = sreg.str();
310 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
311 }
312
313 if (str.size() > 0) {
314 str += "\n";
315 }
316 str += base;
317 }
318 }
319 }
320 // Add a newline at the end.
321 str += "\n";
322 return str;
323 }
324
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200325 template <typename RegType, typename ImmType>
326 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800327 int imm_bits,
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200328 const std::vector<RegType*> registers,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800329 std::string (AssemblerTest::*GetName)(const RegType&),
Chris Larsene3660592016-11-09 11:13:42 -0800330 const std::string& fmt,
331 int bias) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200332 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800333 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200334
335 for (auto reg : registers) {
336 for (int64_t imm : imms) {
337 ImmType new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700338 if (f != nullptr) {
339 (assembler_.get()->*f)(*reg, new_imm + bias);
340 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200341 std::string base = fmt;
342
343 std::string reg_string = (this->*GetName)(*reg);
344 size_t reg_index;
345 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
346 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
347 }
348
349 size_t imm_index = base.find(IMM_TOKEN);
350 if (imm_index != std::string::npos) {
351 std::ostringstream sreg;
Chris Larsene3660592016-11-09 11:13:42 -0800352 sreg << imm + bias;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200353 std::string imm_string = sreg.str();
354 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
355 }
356
357 if (str.size() > 0) {
358 str += "\n";
359 }
360 str += base;
361 }
362 }
363 // Add a newline at the end.
364 str += "\n";
365 return str;
366 }
367
368 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800369 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
370 int imm_bits,
371 const std::string& fmt,
372 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200373 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
374 imm_bits,
375 GetRegisters(),
376 GetRegisters(),
377 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
378 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800379 fmt,
380 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200381 }
382
383 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800384 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
385 int imm_bits,
386 const std::string& fmt,
387 int bias = 0) {
388 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
389 imm_bits,
390 GetRegisters(),
391 GetRegisters(),
392 GetRegisters(),
393 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
394 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
395 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
396 fmt,
397 bias);
398 }
399
400 template <typename ImmType>
401 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200402 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
403 imm_bits,
404 GetRegisters(),
405 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800406 fmt,
407 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200408 }
409
410 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700411 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
412 int imm_bits,
Chris Larsene3660592016-11-09 11:13:42 -0800413 const std::string& fmt,
414 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200415 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
416 imm_bits,
417 GetFPRegisters(),
418 GetRegisters(),
419 &AssemblerTest::GetFPRegName,
420 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800421 fmt,
422 bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700423 }
424
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700425 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800426 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
427 GetFPRegisters(),
428 GetFPRegisters(),
429 &AssemblerTest::GetFPRegName,
430 &AssemblerTest::GetFPRegName,
431 fmt);
432 }
433
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700434 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700435 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
436 GetFPRegisters(),
437 GetFPRegisters(),
438 GetFPRegisters(),
439 &AssemblerTest::GetFPRegName,
440 &AssemblerTest::GetFPRegName,
441 &AssemblerTest::GetFPRegName,
442 fmt);
443 }
444
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700445 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700446 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
447 f,
448 GetFPRegisters(),
449 GetFPRegisters(),
450 GetRegisters(),
451 &AssemblerTest::GetFPRegName,
452 &AssemblerTest::GetFPRegName,
453 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
454 fmt);
455 }
456
Chris Larsendbce0d72015-09-17 13:34:00 -0700457 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
458 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700459 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400460 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700461 GetFPRegisters(),
462 GetFPRegisters(),
463 &AssemblerTest::GetFPRegName,
464 &AssemblerTest::GetFPRegName,
465 imm_bytes,
466 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400467 }
468
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800469 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700470 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
471 int imm_bits,
472 const std::string& fmt) {
Alexey Frunzea8aaf5a2016-06-27 14:48:20 -0700473 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
474 imm_bits,
475 GetFPRegisters(),
476 GetFPRegisters(),
477 &AssemblerTest::GetFPRegName,
478 &AssemblerTest::GetFPRegName,
479 fmt);
480 }
481
482 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700483 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
484 int imm_bits,
485 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800486 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
487 GetFPRegisters(),
488 GetFPRegisters(),
489 &AssemblerTest::GetFPRegName,
490 &AssemblerTest::GetFPRegName,
491 imm_bits,
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::kUsePrimaryName>,
501 fmt);
502 }
503
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700504 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800505 return RepeatTemplatedRegisters<FPReg, Reg>(f,
506 GetFPRegisters(),
507 GetRegisters(),
508 &AssemblerTest::GetFPRegName,
509 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
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::kUsePrimaryName>,
518 &AssemblerTest::GetFPRegName,
519 fmt);
520 }
521
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700522 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800523 return RepeatTemplatedRegisters<Reg, FPReg>(f,
524 GetRegisters(),
525 GetFPRegisters(),
526 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
527 &AssemblerTest::GetFPRegName,
528 fmt);
529 }
530
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700531 std::string RepeatI(void (Ass::*f)(const Imm&),
532 size_t imm_bytes,
533 const std::string& fmt,
Andreas Gampe851df202014-11-12 14:05:46 -0800534 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700535 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800536 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800537
538 WarnOnCombinations(imms.size());
539
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700540 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700541 Imm new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -0700542 if (f != nullptr) {
543 (assembler_.get()->*f)(new_imm);
544 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700545 std::string base = fmt;
546
Andreas Gampe851df202014-11-12 14:05:46 -0800547 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700548 if (imm_index != std::string::npos) {
549 std::ostringstream sreg;
550 sreg << imm;
551 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800552 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700553 }
554
555 if (str.size() > 0) {
556 str += "\n";
557 }
558 str += base;
559 }
560 // Add a newline at the end.
561 str += "\n";
562 return str;
563 }
564
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000565 std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
566 return RepeatTemplatedRegisters<VecReg, VecReg>(f,
567 GetVectorRegisters(),
568 GetVectorRegisters(),
569 &AssemblerTest::GetVecRegName,
570 &AssemblerTest::GetVecRegName,
571 fmt);
572 }
573
574 std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
575 return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
576 GetVectorRegisters(),
577 GetVectorRegisters(),
578 GetVectorRegisters(),
579 &AssemblerTest::GetVecRegName,
580 &AssemblerTest::GetVecRegName,
581 &AssemblerTest::GetVecRegName,
582 fmt);
583 }
584
585 std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
586 return RepeatTemplatedRegisters<VecReg, Reg>(
587 f,
588 GetVectorRegisters(),
589 GetRegisters(),
590 &AssemblerTest::GetVecRegName,
591 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
592 fmt);
593 }
594
595 template <typename ImmType>
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200596 std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
597 int imm_bits,
598 std::string fmt,
599 int bias = 0) {
600 return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
601 imm_bits,
602 GetVectorRegisters(),
603 &AssemblerTest::GetVecRegName,
604 fmt,
605 bias);
606 }
607
608 template <typename ImmType>
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000609 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
610 int imm_bits,
611 const std::string& fmt,
612 int bias = 0,
613 int multiplier = 1) {
614 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
615 f,
616 imm_bits,
617 GetVectorRegisters(),
618 GetRegisters(),
619 &AssemblerTest::GetVecRegName,
620 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
621 fmt,
622 bias,
623 multiplier);
624 }
625
626 template <typename ImmType>
627 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
628 int imm_bits,
629 const std::string& fmt,
630 int bias = 0) {
631 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
632 imm_bits,
633 GetVectorRegisters(),
634 GetVectorRegisters(),
635 &AssemblerTest::GetVecRegName,
636 &AssemblerTest::GetVecRegName,
637 fmt,
638 bias);
639 }
640
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700641 // This is intended to be run as a test.
642 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700643 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700644 }
645
Andreas Gampe851df202014-11-12 14:05:46 -0800646 // The following functions are public so that TestFn can use them...
647
Aart Bikcaa31e72017-09-14 17:08:50 -0700648 // Returns a vector of address used by any of the repeat methods
649 // involving an "A" (e.g. RepeatA).
650 virtual std::vector<Addr> GetAddresses() = 0;
651
652 // Returns a vector of registers used by any of the repeat methods
653 // involving an "R" (e.g. RepeatR).
Andreas Gampe851df202014-11-12 14:05:46 -0800654 virtual std::vector<Reg*> GetRegisters() = 0;
655
Aart Bikcaa31e72017-09-14 17:08:50 -0700656 // Returns a vector of fp-registers used by any of the repeat methods
657 // involving an "F" (e.g. RepeatFF).
Andreas Gampe851df202014-11-12 14:05:46 -0800658 virtual std::vector<FPReg*> GetFPRegisters() {
659 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
660 UNREACHABLE();
661 }
662
Aart Bikcaa31e72017-09-14 17:08:50 -0700663 // Returns a vector of dedicated simd-registers used by any of the repeat
664 // methods involving an "V" (e.g. RepeatVV).
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000665 virtual std::vector<VecReg*> GetVectorRegisters() {
666 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
667 UNREACHABLE();
668 }
669
Andreas Gampe851df202014-11-12 14:05:46 -0800670 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
671 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
672 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
673 UNREACHABLE();
674 }
675
Chao-ying Fud23840d2015-04-07 16:03:04 -0700676 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
677 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
678 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
679 UNREACHABLE();
680 }
681
682 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
683 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
684 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
685 UNREACHABLE();
686 }
687
Calin Juravle9aec02f2014-11-18 23:06:35 +0000688 std::string GetRegisterName(const Reg& reg) {
689 return GetRegName<RegisterView::kUsePrimaryName>(reg);
690 }
691
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700692 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800693 explicit AssemblerTest() {}
694
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700695 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100696 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700697 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700698 test_helper_.reset(
699 new AssemblerTestInfrastructure(GetArchitectureString(),
700 GetAssemblerCmdName(),
701 GetAssemblerParameters(),
702 GetObjdumpCmdName(),
703 GetObjdumpParameters(),
704 GetDisassembleCmdName(),
705 GetDisassembleParameters(),
706 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700707
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700708 SetUpHelpers();
709 }
710
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700711 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700712 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100713 assembler_.reset();
714 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700715 }
716
Chris Larsen3add9cb2016-04-14 14:01:33 -0700717 // Override this to set up any architecture-specific things, e.g., CPU revision.
718 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
719 return new (arena) Ass(arena);
720 }
721
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700722 // Override this to set up any architecture-specific things, e.g., register vectors.
723 virtual void SetUpHelpers() {}
724
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700725 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
726 virtual std::string GetArchitectureString() = 0;
727
728 // Get the name of the assembler, e.g., "as" by default.
729 virtual std::string GetAssemblerCmdName() {
730 return "as";
731 }
732
733 // Switches to the assembler command. Default none.
734 virtual std::string GetAssemblerParameters() {
735 return "";
736 }
737
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700738 // Get the name of the objdump, e.g., "objdump" by default.
739 virtual std::string GetObjdumpCmdName() {
740 return "objdump";
741 }
742
743 // Switches to the objdump command. Default is " -h".
744 virtual std::string GetObjdumpParameters() {
745 return " -h";
746 }
747
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700748 // Get the name of the objdump, e.g., "objdump" by default.
749 virtual std::string GetDisassembleCmdName() {
750 return "objdump";
751 }
752
753 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
754 // such to objdump, so it's architecture-specific and there is no default.
755 virtual std::string GetDisassembleParameters() = 0;
756
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700757 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800758 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700759 std::vector<int64_t> res;
760 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800761 if (!as_uint) {
762 res.push_back(-1);
763 } else {
764 res.push_back(0xFF);
765 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700766 res.push_back(0x12);
767 if (imm_bytes >= 2) {
768 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800769 if (!as_uint) {
770 res.push_back(-0x1234);
771 } else {
772 res.push_back(0xFFFF);
773 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700774 if (imm_bytes >= 4) {
775 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800776 if (!as_uint) {
777 res.push_back(-0x12345678);
778 } else {
779 res.push_back(0xFFFFFFFF);
780 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700781 if (imm_bytes >= 6) {
782 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800783 if (!as_uint) {
784 res.push_back(-0x123456789ABC);
785 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700786 if (imm_bytes >= 8) {
787 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800788 if (!as_uint) {
789 res.push_back(-0x123456789ABCDEF0);
790 } else {
791 res.push_back(0xFFFFFFFFFFFFFFFF);
792 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700793 }
794 }
795 }
796 }
797 return res;
798 }
799
Chris Larsendbce0d72015-09-17 13:34:00 -0700800 const int kMaxBitsExhaustiveTest = 8;
801
802 // Create a couple of immediate values up to the number of bits given.
803 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
804 CHECK_GT(imm_bits, 0);
805 CHECK_LE(imm_bits, 64);
806 std::vector<int64_t> res;
807
808 if (imm_bits <= kMaxBitsExhaustiveTest) {
809 if (as_uint) {
810 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
811 res.push_back(static_cast<int64_t>(i));
812 }
813 } else {
814 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
815 res.push_back(i);
816 }
817 }
818 } else {
819 if (as_uint) {
820 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
821 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
822 i++) {
823 res.push_back(static_cast<int64_t>(i));
824 }
825 for (int i = 0; i <= imm_bits; i++) {
826 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
827 ((MaxInt<uint64_t>(imm_bits) -
828 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
829 * i / imm_bits);
830 res.push_back(static_cast<int64_t>(j));
831 }
832 } else {
833 for (int i = 0; i <= imm_bits; i++) {
834 int64_t j = MinInt<int64_t>(imm_bits) +
835 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
836 MinInt<int64_t>(imm_bits))
837 * i) / imm_bits);
838 res.push_back(static_cast<int64_t>(j));
839 }
840 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
841 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
842 i++) {
843 res.push_back(static_cast<int64_t>(i));
844 }
845 for (int i = 0; i <= imm_bits; i++) {
846 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
847 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
848 * i / imm_bits);
849 res.push_back(static_cast<int64_t>(j));
850 }
851 }
852 }
853
854 return res;
855 }
856
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700857 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700858 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700859
Aart Bikcaa31e72017-09-14 17:08:50 -0700860 //
861 // Addresses repeats.
862 //
863
864 // Repeats over addresses provided by fixture.
865 std::string RepeatA(void (Ass::*f)(const Addr&), const std::string& fmt) {
866 return RepeatA(f, GetAddresses(), fmt);
867 }
868
869 // Variant that takes explicit vector of addresss
870 // (to test restricted addressing modes set).
871 std::string RepeatA(void (Ass::*f)(const Addr&),
872 const std::vector<Addr>& a,
873 const std::string& fmt) {
874 return RepeatTemplatedMem<Addr>(f, a, &AssemblerTest::GetAddrName, fmt);
875 }
876
877 // Repeats over addresses and immediates provided by fixture.
878 std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&),
879 size_t imm_bytes,
880 const std::string& fmt) {
881 return RepeatAI(f, imm_bytes, GetAddresses(), fmt);
882 }
883
884 // Variant that takes explicit vector of addresss
885 // (to test restricted addressing modes set).
886 std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&),
887 size_t imm_bytes,
888 const std::vector<Addr>& a,
889 const std::string& fmt) {
890 return RepeatTemplatedMemImm<Addr>(f, imm_bytes, a, &AssemblerTest::GetAddrName, fmt);
891 }
892
893 // Repeats over registers and addresses provided by fixture.
894 std::string RepeatRA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
895 return RepeatRA(f, GetAddresses(), fmt);
896 }
897
898 // Variant that takes explicit vector of addresss
899 // (to test restricted addressing modes set).
900 std::string RepeatRA(void (Ass::*f)(Reg, const Addr&),
901 const std::vector<Addr>& a,
902 const std::string& fmt) {
903 return RepeatTemplatedRegMem<Reg, Addr>(
904 f,
905 GetRegisters(),
906 a,
907 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
908 &AssemblerTest::GetAddrName,
909 fmt);
910 }
911
912 // Repeats over fp-registers and addresses provided by fixture.
913 std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&), const std::string& fmt) {
914 return RepeatFA(f, GetAddresses(), fmt);
915 }
916
917 // Variant that takes explicit vector of addresss
918 // (to test restricted addressing modes set).
919 std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&),
920 const std::vector<Addr>& a,
921 const std::string& fmt) {
922 return RepeatTemplatedRegMem<FPReg, Addr>(
923 f,
924 GetFPRegisters(),
925 a,
926 &AssemblerTest::GetFPRegName,
927 &AssemblerTest::GetAddrName,
928 fmt);
929 }
930
931 // Repeats over addresses and registers provided by fixture.
932 std::string RepeatAR(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
933 return RepeatAR(f, GetAddresses(), fmt);
934 }
935
936 // Variant that takes explicit vector of addresss
937 // (to test restricted addressing modes set).
938 std::string RepeatAR(void (Ass::*f)(const Addr&, Reg),
939 const std::vector<Addr>& a,
940 const std::string& fmt) {
941 return RepeatTemplatedMemReg<Addr, Reg>(
942 f,
943 a,
944 GetRegisters(),
945 &AssemblerTest::GetAddrName,
946 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
947 fmt);
948 }
949
950 // Repeats over addresses and fp-registers provided by fixture.
951 std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg), const std::string& fmt) {
952 return RepeatAF(f, GetAddresses(), fmt);
953 }
954
955 // Variant that takes explicit vector of addresss
956 // (to test restricted addressing modes set).
957 std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg),
958 const std::vector<Addr>& a,
959 const std::string& fmt) {
960 return RepeatTemplatedMemReg<Addr, FPReg>(
961 f,
962 a,
963 GetFPRegisters(),
964 &AssemblerTest::GetAddrName,
965 &AssemblerTest::GetFPRegName,
966 fmt);
967 }
968
969 template <typename AddrType>
970 std::string RepeatTemplatedMem(void (Ass::*f)(const AddrType&),
971 const std::vector<AddrType> addresses,
972 std::string (AssemblerTest::*GetAName)(const AddrType&),
973 const std::string& fmt) {
974 WarnOnCombinations(addresses.size());
975 std::string str;
976 for (auto addr : addresses) {
977 if (f != nullptr) {
978 (assembler_.get()->*f)(addr);
979 }
980 std::string base = fmt;
981
982 std::string addr_string = (this->*GetAName)(addr);
983 size_t addr_index;
984 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
985 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
986 }
987
988 if (str.size() > 0) {
989 str += "\n";
990 }
991 str += base;
992 }
993 // Add a newline at the end.
994 str += "\n";
995 return str;
996 }
997
998 template <typename AddrType>
999 std::string RepeatTemplatedMemImm(void (Ass::*f)(const AddrType&, const Imm&),
1000 size_t imm_bytes,
1001 const std::vector<AddrType> addresses,
1002 std::string (AssemblerTest::*GetAName)(const AddrType&),
1003 const std::string& fmt) {
1004 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1005 WarnOnCombinations(addresses.size() * imms.size());
1006 std::string str;
1007 for (auto addr : addresses) {
1008 for (int64_t imm : imms) {
1009 Imm new_imm = CreateImmediate(imm);
1010 if (f != nullptr) {
1011 (assembler_.get()->*f)(addr, new_imm);
1012 }
1013 std::string base = fmt;
1014
1015 std::string addr_string = (this->*GetAName)(addr);
1016 size_t addr_index;
1017 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1018 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1019 }
1020
1021 size_t imm_index = base.find(IMM_TOKEN);
1022 if (imm_index != std::string::npos) {
1023 std::ostringstream sreg;
1024 sreg << imm;
1025 std::string imm_string = sreg.str();
1026 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1027 }
1028
1029 if (str.size() > 0) {
1030 str += "\n";
1031 }
1032 str += base;
1033 }
1034 }
1035 // Add a newline at the end.
1036 str += "\n";
1037 return str;
1038 }
1039
1040 template <typename RegType, typename AddrType>
1041 std::string RepeatTemplatedRegMem(void (Ass::*f)(RegType, const AddrType&),
1042 const std::vector<RegType*> registers,
1043 const std::vector<AddrType> addresses,
1044 std::string (AssemblerTest::*GetRName)(const RegType&),
1045 std::string (AssemblerTest::*GetAName)(const AddrType&),
1046 const std::string& fmt) {
1047 WarnOnCombinations(addresses.size() * registers.size());
1048 std::string str;
1049 for (auto reg : registers) {
1050 for (auto addr : addresses) {
1051 if (f != nullptr) {
1052 (assembler_.get()->*f)(*reg, addr);
1053 }
1054 std::string base = fmt;
1055
1056 std::string reg_string = (this->*GetRName)(*reg);
1057 size_t reg_index;
1058 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1059 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1060 }
1061
1062 std::string addr_string = (this->*GetAName)(addr);
1063 size_t addr_index;
1064 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1065 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1066 }
1067
1068 if (str.size() > 0) {
1069 str += "\n";
1070 }
1071 str += base;
1072 }
1073 }
1074 // Add a newline at the end.
1075 str += "\n";
1076 return str;
1077 }
1078
1079 template <typename AddrType, typename RegType>
1080 std::string RepeatTemplatedMemReg(void (Ass::*f)(const AddrType&, RegType),
1081 const std::vector<AddrType> addresses,
1082 const std::vector<RegType*> registers,
1083 std::string (AssemblerTest::*GetAName)(const AddrType&),
1084 std::string (AssemblerTest::*GetRName)(const RegType&),
1085 const std::string& fmt) {
1086 WarnOnCombinations(addresses.size() * registers.size());
1087 std::string str;
1088 for (auto addr : addresses) {
1089 for (auto reg : registers) {
1090 if (f != nullptr) {
1091 (assembler_.get()->*f)(addr, *reg);
1092 }
1093 std::string base = fmt;
1094
1095 std::string addr_string = (this->*GetAName)(addr);
1096 size_t addr_index;
1097 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1098 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1099 }
1100
1101 std::string reg_string = (this->*GetRName)(*reg);
1102 size_t reg_index;
1103 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1104 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1105 }
1106
1107 if (str.size() > 0) {
1108 str += "\n";
1109 }
1110 str += base;
1111 }
1112 }
1113 // Add a newline at the end.
1114 str += "\n";
1115 return str;
1116 }
1117
1118 //
1119 // Register repeats.
1120 //
1121
Andreas Gampe851df202014-11-12 14:05:46 -08001122 template <typename RegType>
1123 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
1124 const std::vector<RegType*> registers,
1125 std::string (AssemblerTest::*GetName)(const RegType&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001126 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -08001127 std::string str;
1128 for (auto reg : registers) {
Aart Bik5dafb3c2017-09-13 13:10:12 -07001129 if (f != nullptr) {
1130 (assembler_.get()->*f)(*reg);
1131 }
Andreas Gampe851df202014-11-12 14:05:46 -08001132 std::string base = fmt;
1133
1134 std::string reg_string = (this->*GetName)(*reg);
1135 size_t reg_index;
1136 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1137 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1138 }
1139
1140 if (str.size() > 0) {
1141 str += "\n";
1142 }
1143 str += base;
1144 }
1145 // Add a newline at the end.
1146 str += "\n";
1147 return str;
1148 }
1149
1150 template <typename Reg1, typename Reg2>
1151 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
1152 const std::vector<Reg1*> reg1_registers,
1153 const std::vector<Reg2*> reg2_registers,
1154 std::string (AssemblerTest::*GetName1)(const Reg1&),
1155 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001156 const std::string& fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001157 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
1158
Andreas Gampe851df202014-11-12 14:05:46 -08001159 std::string str;
1160 for (auto reg1 : reg1_registers) {
1161 for (auto reg2 : reg2_registers) {
Aart Bik5dafb3c2017-09-13 13:10:12 -07001162 if (f != nullptr) {
1163 (assembler_.get()->*f)(*reg1, *reg2);
1164 }
Andreas Gampe851df202014-11-12 14:05:46 -08001165 std::string base = fmt;
1166
1167 std::string reg1_string = (this->*GetName1)(*reg1);
1168 size_t reg1_index;
1169 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1170 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1171 }
1172
1173 std::string reg2_string = (this->*GetName2)(*reg2);
1174 size_t reg2_index;
1175 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1176 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1177 }
1178
1179 if (str.size() > 0) {
1180 str += "\n";
1181 }
1182 str += base;
1183 }
1184 }
1185 // Add a newline at the end.
1186 str += "\n";
1187 return str;
1188 }
1189
Chris Larsen51417632015-10-02 13:24:25 -07001190 template <typename Reg1, typename Reg2>
1191 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
1192 const std::vector<Reg1*> reg1_registers,
1193 const std::vector<Reg2*> reg2_registers,
1194 std::string (AssemblerTest::*GetName1)(const Reg1&),
1195 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001196 const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -07001197 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
1198
1199 std::string str;
1200 for (auto reg1 : reg1_registers) {
1201 for (auto reg2 : reg2_registers) {
1202 if (reg1 == reg2) continue;
Aart Bik5dafb3c2017-09-13 13:10:12 -07001203 if (f != nullptr) {
1204 (assembler_.get()->*f)(*reg1, *reg2);
1205 }
Chris Larsen51417632015-10-02 13:24:25 -07001206 std::string base = fmt;
1207
1208 std::string reg1_string = (this->*GetName1)(*reg1);
1209 size_t reg1_index;
1210 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1211 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1212 }
1213
1214 std::string reg2_string = (this->*GetName2)(*reg2);
1215 size_t reg2_index;
1216 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1217 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1218 }
1219
1220 if (str.size() > 0) {
1221 str += "\n";
1222 }
1223 str += base;
1224 }
1225 }
1226 // Add a newline at the end.
1227 str += "\n";
1228 return str;
1229 }
1230
Chris Larsendbce0d72015-09-17 13:34:00 -07001231 template <typename Reg1, typename Reg2, typename Reg3>
1232 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
1233 const std::vector<Reg1*> reg1_registers,
1234 const std::vector<Reg2*> reg2_registers,
1235 const std::vector<Reg3*> reg3_registers,
1236 std::string (AssemblerTest::*GetName1)(const Reg1&),
1237 std::string (AssemblerTest::*GetName2)(const Reg2&),
1238 std::string (AssemblerTest::*GetName3)(const Reg3&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001239 const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -07001240 std::string str;
1241 for (auto reg1 : reg1_registers) {
1242 for (auto reg2 : reg2_registers) {
1243 for (auto reg3 : reg3_registers) {
Aart Bik5dafb3c2017-09-13 13:10:12 -07001244 if (f != nullptr) {
1245 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
1246 }
Chris Larsendbce0d72015-09-17 13:34:00 -07001247 std::string base = fmt;
1248
1249 std::string reg1_string = (this->*GetName1)(*reg1);
1250 size_t reg1_index;
1251 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1252 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1253 }
1254
1255 std::string reg2_string = (this->*GetName2)(*reg2);
1256 size_t reg2_index;
1257 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1258 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1259 }
1260
1261 std::string reg3_string = (this->*GetName3)(*reg3);
1262 size_t reg3_index;
1263 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
1264 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
1265 }
1266
1267 if (str.size() > 0) {
1268 str += "\n";
1269 }
1270 str += base;
1271 }
1272 }
1273 }
1274 // Add a newline at the end.
1275 str += "\n";
1276 return str;
1277 }
1278
Mark Mendellfb8d2792015-03-31 22:16:59 -04001279 template <typename Reg1, typename Reg2>
1280 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
1281 const std::vector<Reg1*> reg1_registers,
1282 const std::vector<Reg2*> reg2_registers,
1283 std::string (AssemblerTest::*GetName1)(const Reg1&),
1284 std::string (AssemblerTest::*GetName2)(const Reg2&),
1285 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001286 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -04001287 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1288 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
1289
1290 std::string str;
1291 for (auto reg1 : reg1_registers) {
1292 for (auto reg2 : reg2_registers) {
1293 for (int64_t imm : imms) {
1294 Imm new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -07001295 if (f != nullptr) {
1296 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
1297 }
Mark Mendellfb8d2792015-03-31 22:16:59 -04001298 std::string base = fmt;
1299
1300 std::string reg1_string = (this->*GetName1)(*reg1);
1301 size_t reg1_index;
1302 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1303 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1304 }
1305
1306 std::string reg2_string = (this->*GetName2)(*reg2);
1307 size_t reg2_index;
1308 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1309 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1310 }
1311
1312 size_t imm_index = base.find(IMM_TOKEN);
1313 if (imm_index != std::string::npos) {
1314 std::ostringstream sreg;
1315 sreg << imm;
1316 std::string imm_string = sreg.str();
1317 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1318 }
1319
1320 if (str.size() > 0) {
1321 str += "\n";
1322 }
1323 str += base;
1324 }
1325 }
1326 }
1327 // Add a newline at the end.
1328 str += "\n";
1329 return str;
1330 }
1331
Aart Bikcaa31e72017-09-14 17:08:50 -07001332 std::string GetAddrName(const Addr& addr) {
1333 std::ostringstream saddr;
1334 saddr << addr;
1335 return saddr.str();
1336 }
1337
Andreas Gampe851df202014-11-12 14:05:46 -08001338 template <RegisterView kRegView>
1339 std::string GetRegName(const Reg& reg) {
1340 std::ostringstream sreg;
1341 switch (kRegView) {
1342 case RegisterView::kUsePrimaryName:
1343 sreg << reg;
1344 break;
1345
1346 case RegisterView::kUseSecondaryName:
1347 sreg << GetSecondaryRegisterName(reg);
1348 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -07001349
1350 case RegisterView::kUseTertiaryName:
1351 sreg << GetTertiaryRegisterName(reg);
1352 break;
1353
1354 case RegisterView::kUseQuaternaryName:
1355 sreg << GetQuaternaryRegisterName(reg);
1356 break;
Andreas Gampe851df202014-11-12 14:05:46 -08001357 }
1358 return sreg.str();
1359 }
1360
1361 std::string GetFPRegName(const FPReg& reg) {
1362 std::ostringstream sreg;
1363 sreg << reg;
1364 return sreg.str();
1365 }
1366
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001367 std::string GetVecRegName(const VecReg& reg) {
1368 std::ostringstream sreg;
1369 sreg << reg;
1370 return sreg.str();
1371 }
1372
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001373 // If the assembly file needs a header, return it in a sub-class.
1374 virtual const char* GetAssemblyHeader() {
1375 return nullptr;
1376 }
1377
1378 void WarnOnCombinations(size_t count) {
1379 if (count > kWarnManyCombinationsThreshold) {
1380 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1381 }
1382 }
1383
Aart Bikcaa31e72017-09-14 17:08:50 -07001384 static constexpr const char* ADDRESS_TOKEN = "{mem}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001385 static constexpr const char* REG_TOKEN = "{reg}";
1386 static constexpr const char* REG1_TOKEN = "{reg1}";
1387 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -07001388 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001389 static constexpr const char* IMM_TOKEN = "{imm}";
1390
1391 private:
Andreas Gampe851df202014-11-12 14:05:46 -08001392 template <RegisterView kRegView>
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001393 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1394 size_t imm_bytes,
1395 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -08001396 const std::vector<Reg*> registers = GetRegisters();
1397 std::string str;
1398 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001399
1400 WarnOnCombinations(registers.size() * imms.size());
1401
Andreas Gampe851df202014-11-12 14:05:46 -08001402 for (auto reg : registers) {
1403 for (int64_t imm : imms) {
1404 Imm new_imm = CreateImmediate(imm);
Aart Bik5dafb3c2017-09-13 13:10:12 -07001405 if (f != nullptr) {
1406 (assembler_.get()->*f)(*reg, new_imm);
1407 }
Andreas Gampe851df202014-11-12 14:05:46 -08001408 std::string base = fmt;
1409
1410 std::string reg_string = GetRegName<kRegView>(*reg);
1411 size_t reg_index;
1412 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1413 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1414 }
1415
1416 size_t imm_index = base.find(IMM_TOKEN);
1417 if (imm_index != std::string::npos) {
1418 std::ostringstream sreg;
1419 sreg << imm;
1420 std::string imm_string = sreg.str();
1421 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1422 }
1423
1424 if (str.size() > 0) {
1425 str += "\n";
1426 }
1427 str += base;
1428 }
1429 }
1430 // Add a newline at the end.
1431 str += "\n";
1432 return str;
1433 }
1434
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001435 // Override this to pad the code with NOPs to a certain size if needed.
1436 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1437 }
1438
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001439 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001440 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001441 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -07001442 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001443 MemoryRegion code(&(*data)[0], data->size());
1444 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001445 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001446 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001447 }
1448
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001449 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -08001450
Vladimir Marko93205e32016-04-13 11:59:46 +01001451 ArenaPool pool_;
1452 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -07001453 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001454 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -07001455
Andreas Gampe851df202014-11-12 14:05:46 -08001456 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001457};
1458
1459} // namespace art
1460
1461#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_