blob: 5c4875951b430d5b49a2b59f4fc8eca087ee1fda [file] [log] [blame]
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
18#define ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
19
20#include "assembler.h"
21
Andreas Gampe03b9ee42015-04-24 21:41:45 -070022#include "assembler_test_base.h"
Andreas Gampeb40c6a72014-05-02 14:25:12 -070023#include "common_runtime_test.h" // For ScratchFile
Andreas Gampe5a4fa822014-03-31 16:50:12 -070024
25#include <cstdio>
26#include <cstdlib>
27#include <fstream>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070028#include <iterator>
29#include <sys/stat.h>
30
31namespace art {
32
Andreas Gampe851df202014-11-12 14:05:46 -080033// Helper for a constexpr string length.
34constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
35 return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
36}
37
Andreas Gampe849cc5e2014-11-18 13:46:46 -080038enum class RegisterView { // private
39 kUsePrimaryName,
Chao-ying Fud23840d2015-04-07 16:03:04 -070040 kUseSecondaryName,
41 kUseTertiaryName,
42 kUseQuaternaryName,
Andreas Gampe849cc5e2014-11-18 13:46:46 -080043};
44
Andreas Gampe851df202014-11-12 14:05:46 -080045template<typename Ass, typename Reg, typename FPReg, typename Imm>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070046class AssemblerTest : public testing::Test {
47 public:
48 Ass* GetAssembler() {
49 return assembler_.get();
50 }
51
Andreas Gampe851df202014-11-12 14:05:46 -080052 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070053
Andreas Gampe2e965ac2016-11-03 17:24:15 -070054 void DriverFn(TestFn f, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070055 DriverWrapper(f(this, assembler_.get()), test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070056 }
57
58 // This driver assumes the assembler has already been called.
Andreas Gampe2e965ac2016-11-03 17:24:15 -070059 void DriverStr(const std::string& assembly_string, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070060 DriverWrapper(assembly_string, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070061 }
62
Andreas Gampe2e965ac2016-11-03 17:24:15 -070063 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080064 return RepeatTemplatedRegister<Reg>(f,
65 GetRegisters(),
66 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
67 fmt);
68 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070069
Andreas Gampe2e965ac2016-11-03 17:24:15 -070070 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080071 return RepeatTemplatedRegister<Reg>(f,
72 GetRegisters(),
73 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
74 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070075 }
76
Andreas Gampe2e965ac2016-11-03 17:24:15 -070077 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080078 return RepeatTemplatedRegisters<Reg, Reg>(f,
79 GetRegisters(),
80 GetRegisters(),
81 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
82 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
83 fmt);
84 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070085
Andreas Gampe2e965ac2016-11-03 17:24:15 -070086 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -070087 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
88 GetRegisters(),
89 GetRegisters(),
90 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
91 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
92 fmt);
93 }
94
Andreas Gampe2e965ac2016-11-03 17:24:15 -070095 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080096 return RepeatTemplatedRegisters<Reg, Reg>(f,
97 GetRegisters(),
98 GetRegisters(),
99 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
100 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
101 fmt);
102 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700103
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700104 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700105 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
106 GetRegisters(),
107 GetRegisters(),
108 GetRegisters(),
109 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
110 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
111 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
112 fmt);
113 }
114
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700115 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chao-ying Fud23840d2015-04-07 16:03:04 -0700116 return RepeatTemplatedRegisters<Reg, Reg>(f,
117 GetRegisters(),
118 GetRegisters(),
119 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
120 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
121 fmt);
122 }
123
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700124 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800125 return RepeatTemplatedRegisters<Reg, Reg>(f,
126 GetRegisters(),
127 GetRegisters(),
128 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
129 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
130 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700131 }
132
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700133 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800134 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700135 }
136
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700137 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800138 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
139 }
140
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200141 template <typename Reg1, typename Reg2, typename ImmType>
142 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
143 int imm_bits,
144 const std::vector<Reg1*> reg1_registers,
145 const std::vector<Reg2*> reg2_registers,
146 std::string (AssemblerTest::*GetName1)(const Reg1&),
147 std::string (AssemblerTest::*GetName2)(const Reg2&),
Chris Larsene3660592016-11-09 11:13:42 -0800148 const std::string& fmt,
149 int bias = 0) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700150 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800151 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Chris Larsendbce0d72015-09-17 13:34:00 -0700152
153 for (auto reg1 : reg1_registers) {
154 for (auto reg2 : reg2_registers) {
155 for (int64_t imm : imms) {
156 ImmType new_imm = CreateImmediate(imm);
Chris Larsene3660592016-11-09 11:13:42 -0800157 (assembler_.get()->*f)(*reg1, *reg2, new_imm + bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700158 std::string base = fmt;
159
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200160 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700161 size_t reg1_index;
162 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
163 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
164 }
165
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200166 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700167 size_t reg2_index;
168 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
169 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
170 }
171
172 size_t imm_index = base.find(IMM_TOKEN);
173 if (imm_index != std::string::npos) {
174 std::ostringstream sreg;
Chris Larsene3660592016-11-09 11:13:42 -0800175 sreg << imm + bias;
Chris Larsendbce0d72015-09-17 13:34:00 -0700176 std::string imm_string = sreg.str();
177 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
178 }
179
180 if (str.size() > 0) {
181 str += "\n";
182 }
183 str += base;
184 }
185 }
186 }
187 // Add a newline at the end.
188 str += "\n";
189 return str;
190 }
191
Chris Larsene3660592016-11-09 11:13:42 -0800192 template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
193 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
194 int imm_bits,
195 const std::vector<Reg1*> reg1_registers,
196 const std::vector<Reg2*> reg2_registers,
197 const std::vector<Reg3*> reg3_registers,
198 std::string (AssemblerTest::*GetName1)(const Reg1&),
199 std::string (AssemblerTest::*GetName2)(const Reg2&),
200 std::string (AssemblerTest::*GetName3)(const Reg3&),
201 std::string fmt,
202 int bias) {
203 std::string str;
204 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
205
206 for (auto reg1 : reg1_registers) {
207 for (auto reg2 : reg2_registers) {
208 for (auto reg3 : reg3_registers) {
209 for (int64_t imm : imms) {
210 ImmType new_imm = CreateImmediate(imm);
211 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
212 std::string base = fmt;
213
214 std::string reg1_string = (this->*GetName1)(*reg1);
215 size_t reg1_index;
216 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
217 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
218 }
219
220 std::string reg2_string = (this->*GetName2)(*reg2);
221 size_t reg2_index;
222 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
223 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
224 }
225
226 std::string reg3_string = (this->*GetName3)(*reg3);
227 size_t reg3_index;
228 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
229 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
230 }
231
232 size_t imm_index = base.find(IMM_TOKEN);
233 if (imm_index != std::string::npos) {
234 std::ostringstream sreg;
235 sreg << imm + bias;
236 std::string imm_string = sreg.str();
237 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
238 }
239
240 if (str.size() > 0) {
241 str += "\n";
242 }
243 str += base;
244 }
245 }
246 }
247 }
248 // Add a newline at the end.
249 str += "\n";
250 return str;
251 }
252
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800253 template <typename ImmType, typename Reg1, typename Reg2>
254 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
255 const std::vector<Reg1*> reg1_registers,
256 const std::vector<Reg2*> reg2_registers,
257 std::string (AssemblerTest::*GetName1)(const Reg1&),
258 std::string (AssemblerTest::*GetName2)(const Reg2&),
259 int imm_bits,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700260 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800261 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
262
263 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
264
265 std::string str;
266 for (auto reg1 : reg1_registers) {
267 for (auto reg2 : reg2_registers) {
268 for (int64_t imm : imms) {
269 ImmType new_imm = CreateImmediate(imm);
270 (assembler_.get()->*f)(new_imm, *reg1, *reg2);
271 std::string base = fmt;
272
273 std::string reg1_string = (this->*GetName1)(*reg1);
274 size_t reg1_index;
275 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
276 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
277 }
278
279 std::string reg2_string = (this->*GetName2)(*reg2);
280 size_t reg2_index;
281 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
282 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
283 }
284
285 size_t imm_index = base.find(IMM_TOKEN);
286 if (imm_index != std::string::npos) {
287 std::ostringstream sreg;
288 sreg << imm;
289 std::string imm_string = sreg.str();
290 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
291 }
292
293 if (str.size() > 0) {
294 str += "\n";
295 }
296 str += base;
297 }
298 }
299 }
300 // Add a newline at the end.
301 str += "\n";
302 return str;
303 }
304
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200305 template <typename RegType, typename ImmType>
306 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800307 int imm_bits,
308 const std::vector<Reg*> registers,
309 std::string (AssemblerTest::*GetName)(const RegType&),
Chris Larsene3660592016-11-09 11:13:42 -0800310 const std::string& fmt,
311 int bias) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200312 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800313 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200314
315 for (auto reg : registers) {
316 for (int64_t imm : imms) {
317 ImmType new_imm = CreateImmediate(imm);
Chris Larsene3660592016-11-09 11:13:42 -0800318 (assembler_.get()->*f)(*reg, new_imm + bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200319 std::string base = fmt;
320
321 std::string reg_string = (this->*GetName)(*reg);
322 size_t reg_index;
323 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
324 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
325 }
326
327 size_t imm_index = base.find(IMM_TOKEN);
328 if (imm_index != std::string::npos) {
329 std::ostringstream sreg;
Chris Larsene3660592016-11-09 11:13:42 -0800330 sreg << imm + bias;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200331 std::string imm_string = sreg.str();
332 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
333 }
334
335 if (str.size() > 0) {
336 str += "\n";
337 }
338 str += base;
339 }
340 }
341 // Add a newline at the end.
342 str += "\n";
343 return str;
344 }
345
346 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800347 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
348 int imm_bits,
349 const std::string& fmt,
350 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200351 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
352 imm_bits,
353 GetRegisters(),
354 GetRegisters(),
355 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
356 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800357 fmt,
358 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200359 }
360
361 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800362 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
363 int imm_bits,
364 const std::string& fmt,
365 int bias = 0) {
366 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
367 imm_bits,
368 GetRegisters(),
369 GetRegisters(),
370 GetRegisters(),
371 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
372 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
373 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
374 fmt,
375 bias);
376 }
377
378 template <typename ImmType>
379 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200380 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
381 imm_bits,
382 GetRegisters(),
383 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800384 fmt,
385 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200386 }
387
388 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700389 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
390 int imm_bits,
Chris Larsene3660592016-11-09 11:13:42 -0800391 const std::string& fmt,
392 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200393 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
394 imm_bits,
395 GetFPRegisters(),
396 GetRegisters(),
397 &AssemblerTest::GetFPRegName,
398 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800399 fmt,
400 bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700401 }
402
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700403 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800404 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
405 GetFPRegisters(),
406 GetFPRegisters(),
407 &AssemblerTest::GetFPRegName,
408 &AssemblerTest::GetFPRegName,
409 fmt);
410 }
411
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700412 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700413 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
414 GetFPRegisters(),
415 GetFPRegisters(),
416 GetFPRegisters(),
417 &AssemblerTest::GetFPRegName,
418 &AssemblerTest::GetFPRegName,
419 &AssemblerTest::GetFPRegName,
420 fmt);
421 }
422
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700423 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700424 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
425 f,
426 GetFPRegisters(),
427 GetFPRegisters(),
428 GetRegisters(),
429 &AssemblerTest::GetFPRegName,
430 &AssemblerTest::GetFPRegName,
431 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
432 fmt);
433 }
434
Chris Larsendbce0d72015-09-17 13:34:00 -0700435 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
436 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700437 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400438 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700439 GetFPRegisters(),
440 GetFPRegisters(),
441 &AssemblerTest::GetFPRegName,
442 &AssemblerTest::GetFPRegName,
443 imm_bytes,
444 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400445 }
446
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800447 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700448 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
449 int imm_bits,
450 const std::string& fmt) {
Alexey Frunzea8aaf5a2016-06-27 14:48:20 -0700451 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
452 imm_bits,
453 GetFPRegisters(),
454 GetFPRegisters(),
455 &AssemblerTest::GetFPRegName,
456 &AssemblerTest::GetFPRegName,
457 fmt);
458 }
459
460 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700461 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
462 int imm_bits,
463 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800464 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
465 GetFPRegisters(),
466 GetFPRegisters(),
467 &AssemblerTest::GetFPRegName,
468 &AssemblerTest::GetFPRegName,
469 imm_bits,
470 fmt);
471 }
472
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700473 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800474 return RepeatTemplatedRegisters<FPReg, Reg>(f,
475 GetFPRegisters(),
476 GetRegisters(),
477 &AssemblerTest::GetFPRegName,
478 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
479 fmt);
480 }
481
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700482 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800483 return RepeatTemplatedRegisters<FPReg, Reg>(f,
484 GetFPRegisters(),
485 GetRegisters(),
486 &AssemblerTest::GetFPRegName,
487 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
488 fmt);
489 }
490
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700491 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800492 return RepeatTemplatedRegisters<Reg, FPReg>(f,
493 GetRegisters(),
494 GetFPRegisters(),
495 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
496 &AssemblerTest::GetFPRegName,
497 fmt);
498 }
499
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700500 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800501 return RepeatTemplatedRegisters<Reg, FPReg>(f,
502 GetRegisters(),
503 GetFPRegisters(),
504 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
505 &AssemblerTest::GetFPRegName,
506 fmt);
507 }
508
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700509 std::string RepeatI(void (Ass::*f)(const Imm&),
510 size_t imm_bytes,
511 const std::string& fmt,
Andreas Gampe851df202014-11-12 14:05:46 -0800512 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700513 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800514 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800515
516 WarnOnCombinations(imms.size());
517
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700518 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700519 Imm new_imm = CreateImmediate(imm);
520 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700521 std::string base = fmt;
522
Andreas Gampe851df202014-11-12 14:05:46 -0800523 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700524 if (imm_index != std::string::npos) {
525 std::ostringstream sreg;
526 sreg << imm;
527 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800528 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700529 }
530
531 if (str.size() > 0) {
532 str += "\n";
533 }
534 str += base;
535 }
536 // Add a newline at the end.
537 str += "\n";
538 return str;
539 }
540
541 // This is intended to be run as a test.
542 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700543 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700544 }
545
Andreas Gampe851df202014-11-12 14:05:46 -0800546 // The following functions are public so that TestFn can use them...
547
548 virtual std::vector<Reg*> GetRegisters() = 0;
549
550 virtual std::vector<FPReg*> GetFPRegisters() {
551 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
552 UNREACHABLE();
553 }
554
555 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
556 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
557 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
558 UNREACHABLE();
559 }
560
Chao-ying Fud23840d2015-04-07 16:03:04 -0700561 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
562 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
563 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
564 UNREACHABLE();
565 }
566
567 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
568 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
569 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
570 UNREACHABLE();
571 }
572
Calin Juravle9aec02f2014-11-18 23:06:35 +0000573 std::string GetRegisterName(const Reg& reg) {
574 return GetRegName<RegisterView::kUsePrimaryName>(reg);
575 }
576
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700577 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800578 explicit AssemblerTest() {}
579
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700580 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100581 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700582 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700583 test_helper_.reset(
584 new AssemblerTestInfrastructure(GetArchitectureString(),
585 GetAssemblerCmdName(),
586 GetAssemblerParameters(),
587 GetObjdumpCmdName(),
588 GetObjdumpParameters(),
589 GetDisassembleCmdName(),
590 GetDisassembleParameters(),
591 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700592
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700593 SetUpHelpers();
594 }
595
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700596 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700597 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100598 assembler_.reset();
599 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700600 }
601
Chris Larsen3add9cb2016-04-14 14:01:33 -0700602 // Override this to set up any architecture-specific things, e.g., CPU revision.
603 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
604 return new (arena) Ass(arena);
605 }
606
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700607 // Override this to set up any architecture-specific things, e.g., register vectors.
608 virtual void SetUpHelpers() {}
609
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700610 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
611 virtual std::string GetArchitectureString() = 0;
612
613 // Get the name of the assembler, e.g., "as" by default.
614 virtual std::string GetAssemblerCmdName() {
615 return "as";
616 }
617
618 // Switches to the assembler command. Default none.
619 virtual std::string GetAssemblerParameters() {
620 return "";
621 }
622
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700623 // Get the name of the objdump, e.g., "objdump" by default.
624 virtual std::string GetObjdumpCmdName() {
625 return "objdump";
626 }
627
628 // Switches to the objdump command. Default is " -h".
629 virtual std::string GetObjdumpParameters() {
630 return " -h";
631 }
632
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700633 // Get the name of the objdump, e.g., "objdump" by default.
634 virtual std::string GetDisassembleCmdName() {
635 return "objdump";
636 }
637
638 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
639 // such to objdump, so it's architecture-specific and there is no default.
640 virtual std::string GetDisassembleParameters() = 0;
641
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700642 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800643 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700644 std::vector<int64_t> res;
645 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800646 if (!as_uint) {
647 res.push_back(-1);
648 } else {
649 res.push_back(0xFF);
650 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700651 res.push_back(0x12);
652 if (imm_bytes >= 2) {
653 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800654 if (!as_uint) {
655 res.push_back(-0x1234);
656 } else {
657 res.push_back(0xFFFF);
658 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700659 if (imm_bytes >= 4) {
660 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800661 if (!as_uint) {
662 res.push_back(-0x12345678);
663 } else {
664 res.push_back(0xFFFFFFFF);
665 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700666 if (imm_bytes >= 6) {
667 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800668 if (!as_uint) {
669 res.push_back(-0x123456789ABC);
670 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700671 if (imm_bytes >= 8) {
672 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800673 if (!as_uint) {
674 res.push_back(-0x123456789ABCDEF0);
675 } else {
676 res.push_back(0xFFFFFFFFFFFFFFFF);
677 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700678 }
679 }
680 }
681 }
682 return res;
683 }
684
Chris Larsendbce0d72015-09-17 13:34:00 -0700685 const int kMaxBitsExhaustiveTest = 8;
686
687 // Create a couple of immediate values up to the number of bits given.
688 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
689 CHECK_GT(imm_bits, 0);
690 CHECK_LE(imm_bits, 64);
691 std::vector<int64_t> res;
692
693 if (imm_bits <= kMaxBitsExhaustiveTest) {
694 if (as_uint) {
695 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
696 res.push_back(static_cast<int64_t>(i));
697 }
698 } else {
699 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
700 res.push_back(i);
701 }
702 }
703 } else {
704 if (as_uint) {
705 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
706 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
707 i++) {
708 res.push_back(static_cast<int64_t>(i));
709 }
710 for (int i = 0; i <= imm_bits; i++) {
711 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
712 ((MaxInt<uint64_t>(imm_bits) -
713 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
714 * i / imm_bits);
715 res.push_back(static_cast<int64_t>(j));
716 }
717 } else {
718 for (int i = 0; i <= imm_bits; i++) {
719 int64_t j = MinInt<int64_t>(imm_bits) +
720 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
721 MinInt<int64_t>(imm_bits))
722 * i) / imm_bits);
723 res.push_back(static_cast<int64_t>(j));
724 }
725 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
726 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
727 i++) {
728 res.push_back(static_cast<int64_t>(i));
729 }
730 for (int i = 0; i <= imm_bits; i++) {
731 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
732 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
733 * i / imm_bits);
734 res.push_back(static_cast<int64_t>(j));
735 }
736 }
737 }
738
739 return res;
740 }
741
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700742 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700743 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700744
Andreas Gampe851df202014-11-12 14:05:46 -0800745 template <typename RegType>
746 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
747 const std::vector<RegType*> registers,
748 std::string (AssemblerTest::*GetName)(const RegType&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700749 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800750 std::string str;
751 for (auto reg : registers) {
752 (assembler_.get()->*f)(*reg);
753 std::string base = fmt;
754
755 std::string reg_string = (this->*GetName)(*reg);
756 size_t reg_index;
757 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
758 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
759 }
760
761 if (str.size() > 0) {
762 str += "\n";
763 }
764 str += base;
765 }
766 // Add a newline at the end.
767 str += "\n";
768 return str;
769 }
770
771 template <typename Reg1, typename Reg2>
772 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
773 const std::vector<Reg1*> reg1_registers,
774 const std::vector<Reg2*> reg2_registers,
775 std::string (AssemblerTest::*GetName1)(const Reg1&),
776 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700777 const std::string& fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800778 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
779
Andreas Gampe851df202014-11-12 14:05:46 -0800780 std::string str;
781 for (auto reg1 : reg1_registers) {
782 for (auto reg2 : reg2_registers) {
783 (assembler_.get()->*f)(*reg1, *reg2);
784 std::string base = fmt;
785
786 std::string reg1_string = (this->*GetName1)(*reg1);
787 size_t reg1_index;
788 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
789 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
790 }
791
792 std::string reg2_string = (this->*GetName2)(*reg2);
793 size_t reg2_index;
794 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
795 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
796 }
797
798 if (str.size() > 0) {
799 str += "\n";
800 }
801 str += base;
802 }
803 }
804 // Add a newline at the end.
805 str += "\n";
806 return str;
807 }
808
Chris Larsen51417632015-10-02 13:24:25 -0700809 template <typename Reg1, typename Reg2>
810 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
811 const std::vector<Reg1*> reg1_registers,
812 const std::vector<Reg2*> reg2_registers,
813 std::string (AssemblerTest::*GetName1)(const Reg1&),
814 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700815 const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -0700816 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
817
818 std::string str;
819 for (auto reg1 : reg1_registers) {
820 for (auto reg2 : reg2_registers) {
821 if (reg1 == reg2) continue;
822 (assembler_.get()->*f)(*reg1, *reg2);
823 std::string base = fmt;
824
825 std::string reg1_string = (this->*GetName1)(*reg1);
826 size_t reg1_index;
827 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
828 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
829 }
830
831 std::string reg2_string = (this->*GetName2)(*reg2);
832 size_t reg2_index;
833 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
834 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
835 }
836
837 if (str.size() > 0) {
838 str += "\n";
839 }
840 str += base;
841 }
842 }
843 // Add a newline at the end.
844 str += "\n";
845 return str;
846 }
847
Chris Larsendbce0d72015-09-17 13:34:00 -0700848 template <typename Reg1, typename Reg2, typename Reg3>
849 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
850 const std::vector<Reg1*> reg1_registers,
851 const std::vector<Reg2*> reg2_registers,
852 const std::vector<Reg3*> reg3_registers,
853 std::string (AssemblerTest::*GetName1)(const Reg1&),
854 std::string (AssemblerTest::*GetName2)(const Reg2&),
855 std::string (AssemblerTest::*GetName3)(const Reg3&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700856 const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700857 std::string str;
858 for (auto reg1 : reg1_registers) {
859 for (auto reg2 : reg2_registers) {
860 for (auto reg3 : reg3_registers) {
861 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
862 std::string base = fmt;
863
864 std::string reg1_string = (this->*GetName1)(*reg1);
865 size_t reg1_index;
866 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
867 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
868 }
869
870 std::string reg2_string = (this->*GetName2)(*reg2);
871 size_t reg2_index;
872 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
873 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
874 }
875
876 std::string reg3_string = (this->*GetName3)(*reg3);
877 size_t reg3_index;
878 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
879 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
880 }
881
882 if (str.size() > 0) {
883 str += "\n";
884 }
885 str += base;
886 }
887 }
888 }
889 // Add a newline at the end.
890 str += "\n";
891 return str;
892 }
893
Mark Mendellfb8d2792015-03-31 22:16:59 -0400894 template <typename Reg1, typename Reg2>
895 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
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&),
900 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700901 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400902 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
903 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
904
905 std::string str;
906 for (auto reg1 : reg1_registers) {
907 for (auto reg2 : reg2_registers) {
908 for (int64_t imm : imms) {
909 Imm new_imm = CreateImmediate(imm);
910 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
911 std::string base = fmt;
912
913 std::string reg1_string = (this->*GetName1)(*reg1);
914 size_t reg1_index;
915 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
916 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
917 }
918
919 std::string reg2_string = (this->*GetName2)(*reg2);
920 size_t reg2_index;
921 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
922 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
923 }
924
925 size_t imm_index = base.find(IMM_TOKEN);
926 if (imm_index != std::string::npos) {
927 std::ostringstream sreg;
928 sreg << imm;
929 std::string imm_string = sreg.str();
930 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
931 }
932
933 if (str.size() > 0) {
934 str += "\n";
935 }
936 str += base;
937 }
938 }
939 }
940 // Add a newline at the end.
941 str += "\n";
942 return str;
943 }
944
Andreas Gampe851df202014-11-12 14:05:46 -0800945 template <RegisterView kRegView>
946 std::string GetRegName(const Reg& reg) {
947 std::ostringstream sreg;
948 switch (kRegView) {
949 case RegisterView::kUsePrimaryName:
950 sreg << reg;
951 break;
952
953 case RegisterView::kUseSecondaryName:
954 sreg << GetSecondaryRegisterName(reg);
955 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -0700956
957 case RegisterView::kUseTertiaryName:
958 sreg << GetTertiaryRegisterName(reg);
959 break;
960
961 case RegisterView::kUseQuaternaryName:
962 sreg << GetQuaternaryRegisterName(reg);
963 break;
Andreas Gampe851df202014-11-12 14:05:46 -0800964 }
965 return sreg.str();
966 }
967
968 std::string GetFPRegName(const FPReg& reg) {
969 std::ostringstream sreg;
970 sreg << reg;
971 return sreg.str();
972 }
973
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800974 // If the assembly file needs a header, return it in a sub-class.
975 virtual const char* GetAssemblyHeader() {
976 return nullptr;
977 }
978
979 void WarnOnCombinations(size_t count) {
980 if (count > kWarnManyCombinationsThreshold) {
981 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
982 }
983 }
984
985 static constexpr const char* REG_TOKEN = "{reg}";
986 static constexpr const char* REG1_TOKEN = "{reg1}";
987 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -0700988 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800989 static constexpr const char* IMM_TOKEN = "{imm}";
990
991 private:
Andreas Gampe851df202014-11-12 14:05:46 -0800992 template <RegisterView kRegView>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700993 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
994 size_t imm_bytes,
995 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800996 const std::vector<Reg*> registers = GetRegisters();
997 std::string str;
998 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800999
1000 WarnOnCombinations(registers.size() * imms.size());
1001
Andreas Gampe851df202014-11-12 14:05:46 -08001002 for (auto reg : registers) {
1003 for (int64_t imm : imms) {
1004 Imm new_imm = CreateImmediate(imm);
1005 (assembler_.get()->*f)(*reg, new_imm);
1006 std::string base = fmt;
1007
1008 std::string reg_string = GetRegName<kRegView>(*reg);
1009 size_t reg_index;
1010 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1011 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1012 }
1013
1014 size_t imm_index = base.find(IMM_TOKEN);
1015 if (imm_index != std::string::npos) {
1016 std::ostringstream sreg;
1017 sreg << imm;
1018 std::string imm_string = sreg.str();
1019 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1020 }
1021
1022 if (str.size() > 0) {
1023 str += "\n";
1024 }
1025 str += base;
1026 }
1027 }
1028 // Add a newline at the end.
1029 str += "\n";
1030 return str;
1031 }
1032
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001033 // Override this to pad the code with NOPs to a certain size if needed.
1034 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1035 }
1036
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001037 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001038 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001039 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -07001040 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001041 MemoryRegion code(&(*data)[0], data->size());
1042 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001043 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001044 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001045 }
1046
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001047 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -08001048
Vladimir Marko93205e32016-04-13 11:59:46 +01001049 ArenaPool pool_;
1050 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -07001051 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001052 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -07001053
Andreas Gampe851df202014-11-12 14:05:46 -08001054 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001055};
1056
1057} // namespace art
1058
1059#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_