blob: ef53d7237c70247f504e3bb7ff6271226b2aac79 [file] [log] [blame]
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
18#define ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
19
20#include "assembler.h"
21
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070022#include <sys/stat.h>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070023
24#include <cstdio>
25#include <cstdlib>
26#include <fstream>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070027#include <iterator>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028
29#include "assembler_test_base.h"
30#include "common_runtime_test.h" // For ScratchFile
Andreas Gampe5a4fa822014-03-31 16:50:12 -070031
32namespace art {
33
Andreas Gampe851df202014-11-12 14:05:46 -080034// Helper for a constexpr string length.
35constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
36 return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
37}
38
Andreas Gampe849cc5e2014-11-18 13:46:46 -080039enum class RegisterView { // private
40 kUsePrimaryName,
Chao-ying Fud23840d2015-04-07 16:03:04 -070041 kUseSecondaryName,
42 kUseTertiaryName,
43 kUseQuaternaryName,
Andreas Gampe849cc5e2014-11-18 13:46:46 -080044};
45
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +000046// For use in the template as the default type to get a nonvector registers version.
47struct NoVectorRegs {};
48
49template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs>
Andreas Gampe5a4fa822014-03-31 16:50:12 -070050class AssemblerTest : public testing::Test {
51 public:
52 Ass* GetAssembler() {
53 return assembler_.get();
54 }
55
Andreas Gampe851df202014-11-12 14:05:46 -080056 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070057
Andreas Gampe2e965ac2016-11-03 17:24:15 -070058 void DriverFn(TestFn f, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070059 DriverWrapper(f(this, assembler_.get()), test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070060 }
61
62 // This driver assumes the assembler has already been called.
Andreas Gampe2e965ac2016-11-03 17:24:15 -070063 void DriverStr(const std::string& assembly_string, const std::string& test_name) {
Andreas Gampe03b9ee42015-04-24 21:41:45 -070064 DriverWrapper(assembly_string, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070065 }
66
Andreas Gampe2e965ac2016-11-03 17:24:15 -070067 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080068 return RepeatTemplatedRegister<Reg>(f,
69 GetRegisters(),
70 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
71 fmt);
72 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070073
Andreas Gampe2e965ac2016-11-03 17:24:15 -070074 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080075 return RepeatTemplatedRegister<Reg>(f,
76 GetRegisters(),
77 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
78 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -070079 }
80
Andreas Gampe2e965ac2016-11-03 17:24:15 -070081 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -080082 return RepeatTemplatedRegisters<Reg, Reg>(f,
83 GetRegisters(),
84 GetRegisters(),
85 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
86 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
87 fmt);
88 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -070089
Andreas Gampe2e965ac2016-11-03 17:24:15 -070090 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -070091 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
92 GetRegisters(),
93 GetRegisters(),
94 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
95 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
96 fmt);
97 }
98
Andreas Gampe2e965ac2016-11-03 17:24:15 -070099 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800100 return RepeatTemplatedRegisters<Reg, Reg>(f,
101 GetRegisters(),
102 GetRegisters(),
103 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
104 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
105 fmt);
106 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700107
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700108 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700109 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
110 GetRegisters(),
111 GetRegisters(),
112 GetRegisters(),
113 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
114 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
115 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
116 fmt);
117 }
118
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700119 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Chao-ying Fud23840d2015-04-07 16:03:04 -0700120 return RepeatTemplatedRegisters<Reg, Reg>(f,
121 GetRegisters(),
122 GetRegisters(),
123 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
124 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
125 fmt);
126 }
127
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700128 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800129 return RepeatTemplatedRegisters<Reg, Reg>(f,
130 GetRegisters(),
131 GetRegisters(),
132 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
133 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
134 fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700135 }
136
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700137 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800138 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700139 }
140
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700141 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800142 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
143 }
144
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200145 template <typename Reg1, typename Reg2, typename ImmType>
146 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
147 int imm_bits,
148 const std::vector<Reg1*> reg1_registers,
149 const std::vector<Reg2*> reg2_registers,
150 std::string (AssemblerTest::*GetName1)(const Reg1&),
151 std::string (AssemblerTest::*GetName2)(const Reg2&),
Chris Larsene3660592016-11-09 11:13:42 -0800152 const std::string& fmt,
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000153 int bias = 0,
154 int multiplier = 1) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700155 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800156 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Chris Larsendbce0d72015-09-17 13:34:00 -0700157
158 for (auto reg1 : reg1_registers) {
159 for (auto reg2 : reg2_registers) {
160 for (int64_t imm : imms) {
161 ImmType new_imm = CreateImmediate(imm);
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000162 (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700163 std::string base = fmt;
164
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200165 std::string reg1_string = (this->*GetName1)(*reg1);
Chris Larsendbce0d72015-09-17 13:34:00 -0700166 size_t reg1_index;
167 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
168 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
169 }
170
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200171 std::string reg2_string = (this->*GetName2)(*reg2);
Chris Larsendbce0d72015-09-17 13:34:00 -0700172 size_t reg2_index;
173 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
174 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
175 }
176
177 size_t imm_index = base.find(IMM_TOKEN);
178 if (imm_index != std::string::npos) {
179 std::ostringstream sreg;
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000180 sreg << imm * multiplier + bias;
Chris Larsendbce0d72015-09-17 13:34:00 -0700181 std::string imm_string = sreg.str();
182 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
183 }
184
185 if (str.size() > 0) {
186 str += "\n";
187 }
188 str += base;
189 }
190 }
191 }
192 // Add a newline at the end.
193 str += "\n";
194 return str;
195 }
196
Chris Larsene3660592016-11-09 11:13:42 -0800197 template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
198 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
199 int imm_bits,
200 const std::vector<Reg1*> reg1_registers,
201 const std::vector<Reg2*> reg2_registers,
202 const std::vector<Reg3*> reg3_registers,
203 std::string (AssemblerTest::*GetName1)(const Reg1&),
204 std::string (AssemblerTest::*GetName2)(const Reg2&),
205 std::string (AssemblerTest::*GetName3)(const Reg3&),
206 std::string fmt,
207 int bias) {
208 std::string str;
209 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
210
211 for (auto reg1 : reg1_registers) {
212 for (auto reg2 : reg2_registers) {
213 for (auto reg3 : reg3_registers) {
214 for (int64_t imm : imms) {
215 ImmType new_imm = CreateImmediate(imm);
216 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
217 std::string base = fmt;
218
219 std::string reg1_string = (this->*GetName1)(*reg1);
220 size_t reg1_index;
221 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
222 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
223 }
224
225 std::string reg2_string = (this->*GetName2)(*reg2);
226 size_t reg2_index;
227 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
228 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
229 }
230
231 std::string reg3_string = (this->*GetName3)(*reg3);
232 size_t reg3_index;
233 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
234 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
235 }
236
237 size_t imm_index = base.find(IMM_TOKEN);
238 if (imm_index != std::string::npos) {
239 std::ostringstream sreg;
240 sreg << imm + bias;
241 std::string imm_string = sreg.str();
242 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
243 }
244
245 if (str.size() > 0) {
246 str += "\n";
247 }
248 str += base;
249 }
250 }
251 }
252 }
253 // Add a newline at the end.
254 str += "\n";
255 return str;
256 }
257
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800258 template <typename ImmType, typename Reg1, typename Reg2>
259 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
260 const std::vector<Reg1*> reg1_registers,
261 const std::vector<Reg2*> reg2_registers,
262 std::string (AssemblerTest::*GetName1)(const Reg1&),
263 std::string (AssemblerTest::*GetName2)(const Reg2&),
264 int imm_bits,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700265 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800266 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
267
268 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
269
270 std::string str;
271 for (auto reg1 : reg1_registers) {
272 for (auto reg2 : reg2_registers) {
273 for (int64_t imm : imms) {
274 ImmType new_imm = CreateImmediate(imm);
275 (assembler_.get()->*f)(new_imm, *reg1, *reg2);
276 std::string base = fmt;
277
278 std::string reg1_string = (this->*GetName1)(*reg1);
279 size_t reg1_index;
280 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
281 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
282 }
283
284 std::string reg2_string = (this->*GetName2)(*reg2);
285 size_t reg2_index;
286 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
287 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
288 }
289
290 size_t imm_index = base.find(IMM_TOKEN);
291 if (imm_index != std::string::npos) {
292 std::ostringstream sreg;
293 sreg << imm;
294 std::string imm_string = sreg.str();
295 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
296 }
297
298 if (str.size() > 0) {
299 str += "\n";
300 }
301 str += base;
302 }
303 }
304 }
305 // Add a newline at the end.
306 str += "\n";
307 return str;
308 }
309
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200310 template <typename RegType, typename ImmType>
311 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800312 int imm_bits,
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200313 const std::vector<RegType*> registers,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800314 std::string (AssemblerTest::*GetName)(const RegType&),
Chris Larsene3660592016-11-09 11:13:42 -0800315 const std::string& fmt,
316 int bias) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200317 std::string str;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800318 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200319
320 for (auto reg : registers) {
321 for (int64_t imm : imms) {
322 ImmType new_imm = CreateImmediate(imm);
Chris Larsene3660592016-11-09 11:13:42 -0800323 (assembler_.get()->*f)(*reg, new_imm + bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200324 std::string base = fmt;
325
326 std::string reg_string = (this->*GetName)(*reg);
327 size_t reg_index;
328 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
329 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
330 }
331
332 size_t imm_index = base.find(IMM_TOKEN);
333 if (imm_index != std::string::npos) {
334 std::ostringstream sreg;
Chris Larsene3660592016-11-09 11:13:42 -0800335 sreg << imm + bias;
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200336 std::string imm_string = sreg.str();
337 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
338 }
339
340 if (str.size() > 0) {
341 str += "\n";
342 }
343 str += base;
344 }
345 }
346 // Add a newline at the end.
347 str += "\n";
348 return str;
349 }
350
351 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800352 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
353 int imm_bits,
354 const std::string& fmt,
355 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200356 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
357 imm_bits,
358 GetRegisters(),
359 GetRegisters(),
360 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
361 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800362 fmt,
363 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200364 }
365
366 template <typename ImmType>
Chris Larsene3660592016-11-09 11:13:42 -0800367 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
368 int imm_bits,
369 const std::string& fmt,
370 int bias = 0) {
371 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
372 imm_bits,
373 GetRegisters(),
374 GetRegisters(),
375 GetRegisters(),
376 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
377 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
378 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
379 fmt,
380 bias);
381 }
382
383 template <typename ImmType>
384 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200385 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
386 imm_bits,
387 GetRegisters(),
388 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800389 fmt,
390 bias);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200391 }
392
393 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700394 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
395 int imm_bits,
Chris Larsene3660592016-11-09 11:13:42 -0800396 const std::string& fmt,
397 int bias = 0) {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200398 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
399 imm_bits,
400 GetFPRegisters(),
401 GetRegisters(),
402 &AssemblerTest::GetFPRegName,
403 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
Chris Larsene3660592016-11-09 11:13:42 -0800404 fmt,
405 bias);
Chris Larsendbce0d72015-09-17 13:34:00 -0700406 }
407
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700408 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800409 return RepeatTemplatedRegisters<FPReg, FPReg>(f,
410 GetFPRegisters(),
411 GetFPRegisters(),
412 &AssemblerTest::GetFPRegName,
413 &AssemblerTest::GetFPRegName,
414 fmt);
415 }
416
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700417 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700418 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
419 GetFPRegisters(),
420 GetFPRegisters(),
421 GetFPRegisters(),
422 &AssemblerTest::GetFPRegName,
423 &AssemblerTest::GetFPRegName,
424 &AssemblerTest::GetFPRegName,
425 fmt);
426 }
427
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700428 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700429 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
430 f,
431 GetFPRegisters(),
432 GetFPRegisters(),
433 GetRegisters(),
434 &AssemblerTest::GetFPRegName,
435 &AssemblerTest::GetFPRegName,
436 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
437 fmt);
438 }
439
Chris Larsendbce0d72015-09-17 13:34:00 -0700440 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
441 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700442 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400443 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
Chris Larsendbce0d72015-09-17 13:34:00 -0700444 GetFPRegisters(),
445 GetFPRegisters(),
446 &AssemblerTest::GetFPRegName,
447 &AssemblerTest::GetFPRegName,
448 imm_bytes,
449 fmt);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400450 }
451
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800452 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700453 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
454 int imm_bits,
455 const std::string& fmt) {
Alexey Frunzea8aaf5a2016-06-27 14:48:20 -0700456 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
457 imm_bits,
458 GetFPRegisters(),
459 GetFPRegisters(),
460 &AssemblerTest::GetFPRegName,
461 &AssemblerTest::GetFPRegName,
462 fmt);
463 }
464
465 template <typename ImmType>
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700466 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
467 int imm_bits,
468 const std::string& fmt) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800469 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
470 GetFPRegisters(),
471 GetFPRegisters(),
472 &AssemblerTest::GetFPRegName,
473 &AssemblerTest::GetFPRegName,
474 imm_bits,
475 fmt);
476 }
477
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700478 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800479 return RepeatTemplatedRegisters<FPReg, Reg>(f,
480 GetFPRegisters(),
481 GetRegisters(),
482 &AssemblerTest::GetFPRegName,
483 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
484 fmt);
485 }
486
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700487 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800488 return RepeatTemplatedRegisters<FPReg, Reg>(f,
489 GetFPRegisters(),
490 GetRegisters(),
491 &AssemblerTest::GetFPRegName,
492 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
493 fmt);
494 }
495
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700496 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800497 return RepeatTemplatedRegisters<Reg, FPReg>(f,
498 GetRegisters(),
499 GetFPRegisters(),
500 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
501 &AssemblerTest::GetFPRegName,
502 fmt);
503 }
504
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700505 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800506 return RepeatTemplatedRegisters<Reg, FPReg>(f,
507 GetRegisters(),
508 GetFPRegisters(),
509 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
510 &AssemblerTest::GetFPRegName,
511 fmt);
512 }
513
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700514 std::string RepeatI(void (Ass::*f)(const Imm&),
515 size_t imm_bytes,
516 const std::string& fmt,
Andreas Gampe851df202014-11-12 14:05:46 -0800517 bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700518 std::string str;
Andreas Gampe851df202014-11-12 14:05:46 -0800519 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800520
521 WarnOnCombinations(imms.size());
522
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700523 for (int64_t imm : imms) {
Ian Rogerscf7f1912014-10-22 22:06:39 -0700524 Imm new_imm = CreateImmediate(imm);
525 (assembler_.get()->*f)(new_imm);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700526 std::string base = fmt;
527
Andreas Gampe851df202014-11-12 14:05:46 -0800528 size_t imm_index = base.find(IMM_TOKEN);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700529 if (imm_index != std::string::npos) {
530 std::ostringstream sreg;
531 sreg << imm;
532 std::string imm_string = sreg.str();
Andreas Gampe851df202014-11-12 14:05:46 -0800533 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700534 }
535
536 if (str.size() > 0) {
537 str += "\n";
538 }
539 str += base;
540 }
541 // Add a newline at the end.
542 str += "\n";
543 return str;
544 }
545
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000546 std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
547 return RepeatTemplatedRegisters<VecReg, VecReg>(f,
548 GetVectorRegisters(),
549 GetVectorRegisters(),
550 &AssemblerTest::GetVecRegName,
551 &AssemblerTest::GetVecRegName,
552 fmt);
553 }
554
555 std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
556 return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
557 GetVectorRegisters(),
558 GetVectorRegisters(),
559 GetVectorRegisters(),
560 &AssemblerTest::GetVecRegName,
561 &AssemblerTest::GetVecRegName,
562 &AssemblerTest::GetVecRegName,
563 fmt);
564 }
565
566 std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
567 return RepeatTemplatedRegisters<VecReg, Reg>(
568 f,
569 GetVectorRegisters(),
570 GetRegisters(),
571 &AssemblerTest::GetVecRegName,
572 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
573 fmt);
574 }
575
576 template <typename ImmType>
Goran Jakovljevic3f444032017-03-31 14:38:20 +0200577 std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
578 int imm_bits,
579 std::string fmt,
580 int bias = 0) {
581 return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
582 imm_bits,
583 GetVectorRegisters(),
584 &AssemblerTest::GetVecRegName,
585 fmt,
586 bias);
587 }
588
589 template <typename ImmType>
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000590 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
591 int imm_bits,
592 const std::string& fmt,
593 int bias = 0,
594 int multiplier = 1) {
595 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
596 f,
597 imm_bits,
598 GetVectorRegisters(),
599 GetRegisters(),
600 &AssemblerTest::GetVecRegName,
601 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
602 fmt,
603 bias,
604 multiplier);
605 }
606
607 template <typename ImmType>
608 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
609 int imm_bits,
610 const std::string& fmt,
611 int bias = 0) {
612 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
613 imm_bits,
614 GetVectorRegisters(),
615 GetVectorRegisters(),
616 &AssemblerTest::GetVecRegName,
617 &AssemblerTest::GetVecRegName,
618 fmt,
619 bias);
620 }
621
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700622 // This is intended to be run as a test.
623 bool CheckTools() {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700624 return test_helper_->CheckTools();
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700625 }
626
Andreas Gampe851df202014-11-12 14:05:46 -0800627 // The following functions are public so that TestFn can use them...
628
629 virtual std::vector<Reg*> GetRegisters() = 0;
630
631 virtual std::vector<FPReg*> GetFPRegisters() {
632 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
633 UNREACHABLE();
634 }
635
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +0000636 virtual std::vector<VecReg*> GetVectorRegisters() {
637 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
638 UNREACHABLE();
639 }
640
Andreas Gampe851df202014-11-12 14:05:46 -0800641 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
642 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
643 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
644 UNREACHABLE();
645 }
646
Chao-ying Fud23840d2015-04-07 16:03:04 -0700647 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
648 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
649 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
650 UNREACHABLE();
651 }
652
653 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
654 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
655 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
656 UNREACHABLE();
657 }
658
Calin Juravle9aec02f2014-11-18 23:06:35 +0000659 std::string GetRegisterName(const Reg& reg) {
660 return GetRegName<RegisterView::kUsePrimaryName>(reg);
661 }
662
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700663 protected:
Andreas Gampe851df202014-11-12 14:05:46 -0800664 explicit AssemblerTest() {}
665
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700666 void SetUp() OVERRIDE {
Vladimir Marko93205e32016-04-13 11:59:46 +0100667 arena_.reset(new ArenaAllocator(&pool_));
Chris Larsen3add9cb2016-04-14 14:01:33 -0700668 assembler_.reset(CreateAssembler(arena_.get()));
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700669 test_helper_.reset(
670 new AssemblerTestInfrastructure(GetArchitectureString(),
671 GetAssemblerCmdName(),
672 GetAssemblerParameters(),
673 GetObjdumpCmdName(),
674 GetObjdumpParameters(),
675 GetDisassembleCmdName(),
676 GetDisassembleParameters(),
677 GetAssemblyHeader()));
Andreas Gampeb40c6a72014-05-02 14:25:12 -0700678
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700679 SetUpHelpers();
680 }
681
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700682 void TearDown() OVERRIDE {
Andreas Gampe03b9ee42015-04-24 21:41:45 -0700683 test_helper_.reset(); // Clean up the helper.
Vladimir Marko93205e32016-04-13 11:59:46 +0100684 assembler_.reset();
685 arena_.reset();
Andreas Gampe7747c8d2014-08-06 14:53:03 -0700686 }
687
Chris Larsen3add9cb2016-04-14 14:01:33 -0700688 // Override this to set up any architecture-specific things, e.g., CPU revision.
689 virtual Ass* CreateAssembler(ArenaAllocator* arena) {
690 return new (arena) Ass(arena);
691 }
692
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700693 // Override this to set up any architecture-specific things, e.g., register vectors.
694 virtual void SetUpHelpers() {}
695
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700696 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
697 virtual std::string GetArchitectureString() = 0;
698
699 // Get the name of the assembler, e.g., "as" by default.
700 virtual std::string GetAssemblerCmdName() {
701 return "as";
702 }
703
704 // Switches to the assembler command. Default none.
705 virtual std::string GetAssemblerParameters() {
706 return "";
707 }
708
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700709 // Get the name of the objdump, e.g., "objdump" by default.
710 virtual std::string GetObjdumpCmdName() {
711 return "objdump";
712 }
713
714 // Switches to the objdump command. Default is " -h".
715 virtual std::string GetObjdumpParameters() {
716 return " -h";
717 }
718
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700719 // Get the name of the objdump, e.g., "objdump" by default.
720 virtual std::string GetDisassembleCmdName() {
721 return "objdump";
722 }
723
724 // Switches to the objdump command. As it's a binary, one needs to push the architecture and
725 // such to objdump, so it's architecture-specific and there is no default.
726 virtual std::string GetDisassembleParameters() = 0;
727
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700728 // Create a couple of immediate values up to the number of bytes given.
Andreas Gampe851df202014-11-12 14:05:46 -0800729 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700730 std::vector<int64_t> res;
731 res.push_back(0);
Andreas Gampe851df202014-11-12 14:05:46 -0800732 if (!as_uint) {
733 res.push_back(-1);
734 } else {
735 res.push_back(0xFF);
736 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700737 res.push_back(0x12);
738 if (imm_bytes >= 2) {
739 res.push_back(0x1234);
Andreas Gampe851df202014-11-12 14:05:46 -0800740 if (!as_uint) {
741 res.push_back(-0x1234);
742 } else {
743 res.push_back(0xFFFF);
744 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700745 if (imm_bytes >= 4) {
746 res.push_back(0x12345678);
Andreas Gampe851df202014-11-12 14:05:46 -0800747 if (!as_uint) {
748 res.push_back(-0x12345678);
749 } else {
750 res.push_back(0xFFFFFFFF);
751 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700752 if (imm_bytes >= 6) {
753 res.push_back(0x123456789ABC);
Andreas Gampe851df202014-11-12 14:05:46 -0800754 if (!as_uint) {
755 res.push_back(-0x123456789ABC);
756 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700757 if (imm_bytes >= 8) {
758 res.push_back(0x123456789ABCDEF0);
Andreas Gampe851df202014-11-12 14:05:46 -0800759 if (!as_uint) {
760 res.push_back(-0x123456789ABCDEF0);
761 } else {
762 res.push_back(0xFFFFFFFFFFFFFFFF);
763 }
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700764 }
765 }
766 }
767 }
768 return res;
769 }
770
Chris Larsendbce0d72015-09-17 13:34:00 -0700771 const int kMaxBitsExhaustiveTest = 8;
772
773 // Create a couple of immediate values up to the number of bits given.
774 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
775 CHECK_GT(imm_bits, 0);
776 CHECK_LE(imm_bits, 64);
777 std::vector<int64_t> res;
778
779 if (imm_bits <= kMaxBitsExhaustiveTest) {
780 if (as_uint) {
781 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
782 res.push_back(static_cast<int64_t>(i));
783 }
784 } else {
785 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
786 res.push_back(i);
787 }
788 }
789 } else {
790 if (as_uint) {
791 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
792 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
793 i++) {
794 res.push_back(static_cast<int64_t>(i));
795 }
796 for (int i = 0; i <= imm_bits; i++) {
797 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
798 ((MaxInt<uint64_t>(imm_bits) -
799 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
800 * i / imm_bits);
801 res.push_back(static_cast<int64_t>(j));
802 }
803 } else {
804 for (int i = 0; i <= imm_bits; i++) {
805 int64_t j = MinInt<int64_t>(imm_bits) +
806 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
807 MinInt<int64_t>(imm_bits))
808 * i) / imm_bits);
809 res.push_back(static_cast<int64_t>(j));
810 }
811 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
812 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
813 i++) {
814 res.push_back(static_cast<int64_t>(i));
815 }
816 for (int i = 0; i <= imm_bits; i++) {
817 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
818 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
819 * i / imm_bits);
820 res.push_back(static_cast<int64_t>(j));
821 }
822 }
823 }
824
825 return res;
826 }
827
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700828 // Create an immediate from the specific value.
Ian Rogerscf7f1912014-10-22 22:06:39 -0700829 virtual Imm CreateImmediate(int64_t imm_value) = 0;
Andreas Gampe5a4fa822014-03-31 16:50:12 -0700830
Andreas Gampe851df202014-11-12 14:05:46 -0800831 template <typename RegType>
832 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
833 const std::vector<RegType*> registers,
834 std::string (AssemblerTest::*GetName)(const RegType&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700835 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -0800836 std::string str;
837 for (auto reg : registers) {
838 (assembler_.get()->*f)(*reg);
839 std::string base = fmt;
840
841 std::string reg_string = (this->*GetName)(*reg);
842 size_t reg_index;
843 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
844 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
845 }
846
847 if (str.size() > 0) {
848 str += "\n";
849 }
850 str += base;
851 }
852 // Add a newline at the end.
853 str += "\n";
854 return str;
855 }
856
857 template <typename Reg1, typename Reg2>
858 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
859 const std::vector<Reg1*> reg1_registers,
860 const std::vector<Reg2*> reg2_registers,
861 std::string (AssemblerTest::*GetName1)(const Reg1&),
862 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700863 const std::string& fmt) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800864 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
865
Andreas Gampe851df202014-11-12 14:05:46 -0800866 std::string str;
867 for (auto reg1 : reg1_registers) {
868 for (auto reg2 : reg2_registers) {
869 (assembler_.get()->*f)(*reg1, *reg2);
870 std::string base = fmt;
871
872 std::string reg1_string = (this->*GetName1)(*reg1);
873 size_t reg1_index;
874 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
875 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
876 }
877
878 std::string reg2_string = (this->*GetName2)(*reg2);
879 size_t reg2_index;
880 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
881 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
882 }
883
884 if (str.size() > 0) {
885 str += "\n";
886 }
887 str += base;
888 }
889 }
890 // Add a newline at the end.
891 str += "\n";
892 return str;
893 }
894
Chris Larsen51417632015-10-02 13:24:25 -0700895 template <typename Reg1, typename Reg2>
896 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
897 const std::vector<Reg1*> reg1_registers,
898 const std::vector<Reg2*> reg2_registers,
899 std::string (AssemblerTest::*GetName1)(const Reg1&),
900 std::string (AssemblerTest::*GetName2)(const Reg2&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700901 const std::string& fmt) {
Chris Larsen51417632015-10-02 13:24:25 -0700902 WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
903
904 std::string str;
905 for (auto reg1 : reg1_registers) {
906 for (auto reg2 : reg2_registers) {
907 if (reg1 == reg2) continue;
908 (assembler_.get()->*f)(*reg1, *reg2);
909 std::string base = fmt;
910
911 std::string reg1_string = (this->*GetName1)(*reg1);
912 size_t reg1_index;
913 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
914 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
915 }
916
917 std::string reg2_string = (this->*GetName2)(*reg2);
918 size_t reg2_index;
919 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
920 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
921 }
922
923 if (str.size() > 0) {
924 str += "\n";
925 }
926 str += base;
927 }
928 }
929 // Add a newline at the end.
930 str += "\n";
931 return str;
932 }
933
Chris Larsendbce0d72015-09-17 13:34:00 -0700934 template <typename Reg1, typename Reg2, typename Reg3>
935 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
936 const std::vector<Reg1*> reg1_registers,
937 const std::vector<Reg2*> reg2_registers,
938 const std::vector<Reg3*> reg3_registers,
939 std::string (AssemblerTest::*GetName1)(const Reg1&),
940 std::string (AssemblerTest::*GetName2)(const Reg2&),
941 std::string (AssemblerTest::*GetName3)(const Reg3&),
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700942 const std::string& fmt) {
Chris Larsendbce0d72015-09-17 13:34:00 -0700943 std::string str;
944 for (auto reg1 : reg1_registers) {
945 for (auto reg2 : reg2_registers) {
946 for (auto reg3 : reg3_registers) {
947 (assembler_.get()->*f)(*reg1, *reg2, *reg3);
948 std::string base = fmt;
949
950 std::string reg1_string = (this->*GetName1)(*reg1);
951 size_t reg1_index;
952 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
953 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
954 }
955
956 std::string reg2_string = (this->*GetName2)(*reg2);
957 size_t reg2_index;
958 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
959 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
960 }
961
962 std::string reg3_string = (this->*GetName3)(*reg3);
963 size_t reg3_index;
964 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
965 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
966 }
967
968 if (str.size() > 0) {
969 str += "\n";
970 }
971 str += base;
972 }
973 }
974 }
975 // Add a newline at the end.
976 str += "\n";
977 return str;
978 }
979
Mark Mendellfb8d2792015-03-31 22:16:59 -0400980 template <typename Reg1, typename Reg2>
981 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
982 const std::vector<Reg1*> reg1_registers,
983 const std::vector<Reg2*> reg2_registers,
984 std::string (AssemblerTest::*GetName1)(const Reg1&),
985 std::string (AssemblerTest::*GetName2)(const Reg2&),
986 size_t imm_bytes,
Andreas Gampe2e965ac2016-11-03 17:24:15 -0700987 const std::string& fmt) {
Mark Mendellfb8d2792015-03-31 22:16:59 -0400988 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
989 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
990
991 std::string str;
992 for (auto reg1 : reg1_registers) {
993 for (auto reg2 : reg2_registers) {
994 for (int64_t imm : imms) {
995 Imm new_imm = CreateImmediate(imm);
996 (assembler_.get()->*f)(*reg1, *reg2, new_imm);
997 std::string base = fmt;
998
999 std::string reg1_string = (this->*GetName1)(*reg1);
1000 size_t reg1_index;
1001 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1002 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1003 }
1004
1005 std::string reg2_string = (this->*GetName2)(*reg2);
1006 size_t reg2_index;
1007 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1008 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1009 }
1010
1011 size_t imm_index = base.find(IMM_TOKEN);
1012 if (imm_index != std::string::npos) {
1013 std::ostringstream sreg;
1014 sreg << imm;
1015 std::string imm_string = sreg.str();
1016 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1017 }
1018
1019 if (str.size() > 0) {
1020 str += "\n";
1021 }
1022 str += base;
1023 }
1024 }
1025 }
1026 // Add a newline at the end.
1027 str += "\n";
1028 return str;
1029 }
1030
Andreas Gampe851df202014-11-12 14:05:46 -08001031 template <RegisterView kRegView>
1032 std::string GetRegName(const Reg& reg) {
1033 std::ostringstream sreg;
1034 switch (kRegView) {
1035 case RegisterView::kUsePrimaryName:
1036 sreg << reg;
1037 break;
1038
1039 case RegisterView::kUseSecondaryName:
1040 sreg << GetSecondaryRegisterName(reg);
1041 break;
Chao-ying Fud23840d2015-04-07 16:03:04 -07001042
1043 case RegisterView::kUseTertiaryName:
1044 sreg << GetTertiaryRegisterName(reg);
1045 break;
1046
1047 case RegisterView::kUseQuaternaryName:
1048 sreg << GetQuaternaryRegisterName(reg);
1049 break;
Andreas Gampe851df202014-11-12 14:05:46 -08001050 }
1051 return sreg.str();
1052 }
1053
1054 std::string GetFPRegName(const FPReg& reg) {
1055 std::ostringstream sreg;
1056 sreg << reg;
1057 return sreg.str();
1058 }
1059
Goran Jakovljevic5a9e51d2017-03-16 16:11:43 +00001060 std::string GetVecRegName(const VecReg& reg) {
1061 std::ostringstream sreg;
1062 sreg << reg;
1063 return sreg.str();
1064 }
1065
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001066 // If the assembly file needs a header, return it in a sub-class.
1067 virtual const char* GetAssemblyHeader() {
1068 return nullptr;
1069 }
1070
1071 void WarnOnCombinations(size_t count) {
1072 if (count > kWarnManyCombinationsThreshold) {
1073 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1074 }
1075 }
1076
1077 static constexpr const char* REG_TOKEN = "{reg}";
1078 static constexpr const char* REG1_TOKEN = "{reg1}";
1079 static constexpr const char* REG2_TOKEN = "{reg2}";
Chris Larsendbce0d72015-09-17 13:34:00 -07001080 static constexpr const char* REG3_TOKEN = "{reg3}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001081 static constexpr const char* IMM_TOKEN = "{imm}";
1082
1083 private:
Andreas Gampe851df202014-11-12 14:05:46 -08001084 template <RegisterView kRegView>
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001085 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1086 size_t imm_bytes,
1087 const std::string& fmt) {
Andreas Gampe851df202014-11-12 14:05:46 -08001088 const std::vector<Reg*> registers = GetRegisters();
1089 std::string str;
1090 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001091
1092 WarnOnCombinations(registers.size() * imms.size());
1093
Andreas Gampe851df202014-11-12 14:05:46 -08001094 for (auto reg : registers) {
1095 for (int64_t imm : imms) {
1096 Imm new_imm = CreateImmediate(imm);
1097 (assembler_.get()->*f)(*reg, new_imm);
1098 std::string base = fmt;
1099
1100 std::string reg_string = GetRegName<kRegView>(*reg);
1101 size_t reg_index;
1102 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1103 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1104 }
1105
1106 size_t imm_index = base.find(IMM_TOKEN);
1107 if (imm_index != std::string::npos) {
1108 std::ostringstream sreg;
1109 sreg << imm;
1110 std::string imm_string = sreg.str();
1111 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1112 }
1113
1114 if (str.size() > 0) {
1115 str += "\n";
1116 }
1117 str += base;
1118 }
1119 }
1120 // Add a newline at the end.
1121 str += "\n";
1122 return str;
1123 }
1124
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001125 // Override this to pad the code with NOPs to a certain size if needed.
1126 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1127 }
1128
Andreas Gampe2e965ac2016-11-03 17:24:15 -07001129 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001130 assembler_->FinalizeCode();
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001131 size_t cs = assembler_->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -07001132 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001133 MemoryRegion code(&(*data)[0], data->size());
1134 assembler_->FinalizeInstructions(code);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001135 Pad(*data);
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001136 test_helper_->Driver(*data, assembly_text, test_name);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001137 }
1138
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001139 static constexpr size_t kWarnManyCombinationsThreshold = 500;
Andreas Gampe851df202014-11-12 14:05:46 -08001140
Vladimir Marko93205e32016-04-13 11:59:46 +01001141 ArenaPool pool_;
1142 std::unique_ptr<ArenaAllocator> arena_;
Ian Rogers700a4022014-05-19 16:49:03 -07001143 std::unique_ptr<Ass> assembler_;
Andreas Gampe03b9ee42015-04-24 21:41:45 -07001144 std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
Andreas Gampe7747c8d2014-08-06 14:53:03 -07001145
Andreas Gampe851df202014-11-12 14:05:46 -08001146 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
Andreas Gampe5a4fa822014-03-31 16:50:12 -07001147};
1148
1149} // namespace art
1150
1151#endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_