blob: a85a05e044fdcd8f9755008ab9a2e72fd21cefce [file] [log] [blame]
Andreas Gampe849cc5e2014-11-18 13:46:46 -08001/*
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_ARM_ASSEMBLER_ARM_TEST_H_
18#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
19
20#include "utils/assembler_test.h"
21
22namespace art {
23
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010024template<typename Ass,
25 typename Reg,
26 typename FPReg,
27 typename Imm,
28 typename SOp,
29 typename Cond,
30 typename SetCc>
Andreas Gampe849cc5e2014-11-18 13:46:46 -080031class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> {
32 public:
33 typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base;
34
35 using Base::GetRegisters;
36 using Base::GetRegName;
37 using Base::CreateImmediate;
38 using Base::WarnOnCombinations;
39
40 static constexpr int64_t kFullImmRangeThreshold = 32;
41
42 virtual void FillImmediates(std::vector<Imm>& immediates, int64_t imm_min, int64_t imm_max) {
43 // Small range: do completely.
44 if (imm_max - imm_min <= kFullImmRangeThreshold) {
45 for (int64_t i = imm_min; i <= imm_max; ++i) {
46 immediates.push_back(CreateImmediate(i));
47 }
48 } else {
49 immediates.push_back(CreateImmediate(imm_min));
50 immediates.push_back(CreateImmediate(imm_max));
51 if (imm_min < imm_max - 1) {
52 immediates.push_back(CreateImmediate(imm_min + 1));
53 }
54 if (imm_min < imm_max - 2) {
55 immediates.push_back(CreateImmediate(imm_min + 2));
56 }
57 if (imm_min < imm_max - 3) {
58 immediates.push_back(CreateImmediate(imm_max - 1));
59 }
60 if (imm_min < imm_max - 4) {
61 immediates.push_back(CreateImmediate((imm_min + imm_max) / 2));
62 }
63 }
64 }
65
66 std::string RepeatRRIIC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
67 int64_t imm1_min, int64_t imm1_max,
68 int64_t imm2_min, int64_t imm2_max,
69 std::string fmt) {
70 return RepeatTemplatedRRIIC(f, GetRegisters(), GetRegisters(),
71 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
72 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
73 imm1_min, imm1_max, imm2_min, imm2_max,
74 fmt);
75 }
76
77 template <typename Reg1, typename Reg2>
78 std::string RepeatTemplatedRRIIC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
79 const std::vector<Reg1*> reg1_registers,
80 const std::vector<Reg2*> reg2_registers,
81 std::string (AssemblerArmTest::*GetName1)(const Reg1&),
82 std::string (AssemblerArmTest::*GetName2)(const Reg2&),
83 int64_t imm1_min, int64_t imm1_max,
84 int64_t imm2_min, int64_t imm2_max,
85 std::string fmt) {
86 std::vector<Imm> immediates1;
87 FillImmediates(immediates1, imm1_min, imm1_max);
88 std::vector<Imm> immediates2;
89 FillImmediates(immediates2, imm2_min, imm2_max);
90
91 std::vector<Cond>& cond = GetConditions();
92
93 WarnOnCombinations(cond.size() * immediates1.size() * immediates2.size() *
94 reg1_registers.size() * reg2_registers.size());
95
96 std::ostringstream oss;
97 bool first = true;
98 for (Cond& c : cond) {
99 std::string after_cond = fmt;
100
101 size_t cond_index = after_cond.find(COND_TOKEN);
102 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100103 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800104 }
105
106 for (Imm i : immediates1) {
107 std::string base = after_cond;
108
109 size_t imm1_index = base.find(IMM1_TOKEN);
110 if (imm1_index != std::string::npos) {
111 std::ostringstream sreg;
112 sreg << i;
113 std::string imm_string = sreg.str();
114 base.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
115 }
116
117 for (Imm j : immediates2) {
118 std::string base2 = base;
119
120 size_t imm2_index = base2.find(IMM2_TOKEN);
121 if (imm2_index != std::string::npos) {
122 std::ostringstream sreg;
123 sreg << j;
124 std::string imm_string = sreg.str();
125 base2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
126 }
127
128 for (auto reg1 : reg1_registers) {
129 std::string base3 = base2;
130
131 std::string reg1_string = (this->*GetName1)(*reg1);
132 size_t reg1_index;
133 while ((reg1_index = base3.find(Base::REG1_TOKEN)) != std::string::npos) {
134 base3.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
135 }
136
137 for (auto reg2 : reg2_registers) {
138 std::string base4 = base3;
139
140 std::string reg2_string = (this->*GetName2)(*reg2);
141 size_t reg2_index;
142 while ((reg2_index = base4.find(Base::REG2_TOKEN)) != std::string::npos) {
143 base4.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
144 }
145
146 if (first) {
147 first = false;
148 } else {
149 oss << "\n";
150 }
151 oss << base4;
152
153 (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
154 }
155 }
156 }
157 }
158 }
159 // Add a newline at the end.
160 oss << "\n";
161
162 return oss.str();
163 }
164
165 std::string RepeatRRiiC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
166 std::vector<std::pair<Imm, Imm>>& immediates,
167 std::string fmt) {
Igor Murashkincad2f0a2014-11-21 16:16:53 -0800168 return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(),
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800169 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
170 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
171 immediates, fmt);
172 }
173
174 template <typename Reg1, typename Reg2>
175 std::string RepeatTemplatedRRiiC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
176 const std::vector<Reg1*> reg1_registers,
177 const std::vector<Reg2*> reg2_registers,
178 std::string (AssemblerArmTest::*GetName1)(const Reg1&),
179 std::string (AssemblerArmTest::*GetName2)(const Reg2&),
180 std::vector<std::pair<Imm, Imm>>& immediates,
181 std::string fmt) {
182 std::vector<Cond>& cond = GetConditions();
183
184 WarnOnCombinations(cond.size() * immediates.size() * reg1_registers.size() *
185 reg2_registers.size());
186
187 std::ostringstream oss;
188 bool first = true;
189 for (Cond& c : cond) {
190 std::string after_cond = fmt;
191
192 size_t cond_index = after_cond.find(COND_TOKEN);
193 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100194 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800195 }
196
197 for (std::pair<Imm, Imm>& pair : immediates) {
198 Imm i = pair.first;
199 Imm j = pair.second;
200 std::string after_imm1 = after_cond;
201
202 size_t imm1_index = after_imm1.find(IMM1_TOKEN);
203 if (imm1_index != std::string::npos) {
204 std::ostringstream sreg;
205 sreg << i;
206 std::string imm_string = sreg.str();
207 after_imm1.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
208 }
209
210 std::string after_imm2 = after_imm1;
211
212 size_t imm2_index = after_imm2.find(IMM2_TOKEN);
213 if (imm2_index != std::string::npos) {
214 std::ostringstream sreg;
215 sreg << j;
216 std::string imm_string = sreg.str();
217 after_imm2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
218 }
219
220 for (auto reg1 : reg1_registers) {
221 std::string after_reg1 = after_imm2;
222
223 std::string reg1_string = (this->*GetName1)(*reg1);
224 size_t reg1_index;
225 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
226 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
227 }
228
229 for (auto reg2 : reg2_registers) {
230 std::string after_reg2 = after_reg1;
231
232 std::string reg2_string = (this->*GetName2)(*reg2);
233 size_t reg2_index;
234 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
235 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
236 }
237
238 if (first) {
239 first = false;
240 } else {
241 oss << "\n";
242 }
243 oss << after_reg2;
244
245 (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
246 }
247 }
248 }
249 }
250 // Add a newline at the end.
251 oss << "\n";
252
253 return oss.str();
254 }
255
256 std::string RepeatRRC(void (Ass::*f)(Reg, Reg, Cond), std::string fmt) {
257 return RepeatTemplatedRRC(f, GetRegisters(), GetRegisters(), GetConditions(),
258 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
259 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
260 fmt);
261 }
262
263 template <typename Reg1, typename Reg2>
264 std::string RepeatTemplatedRRC(void (Ass::*f)(Reg1, Reg2, Cond),
265 const std::vector<Reg1*>& reg1_registers,
266 const std::vector<Reg2*>& reg2_registers,
267 const std::vector<Cond>& cond,
268 std::string (AssemblerArmTest::*GetName1)(const Reg1&),
269 std::string (AssemblerArmTest::*GetName2)(const Reg2&),
270 std::string fmt) {
271 WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size());
272
273 std::ostringstream oss;
274 bool first = true;
275 for (const Cond& c : cond) {
276 std::string after_cond = fmt;
277
278 size_t cond_index = after_cond.find(COND_TOKEN);
279 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100280 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800281 }
282
283 for (auto reg1 : reg1_registers) {
284 std::string after_reg1 = after_cond;
285
286 std::string reg1_string = (this->*GetName1)(*reg1);
287 size_t reg1_index;
288 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
289 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
290 }
291
292 for (auto reg2 : reg2_registers) {
293 std::string after_reg2 = after_reg1;
294
295 std::string reg2_string = (this->*GetName2)(*reg2);
296 size_t reg2_index;
297 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
298 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
299 }
300
301 if (first) {
302 first = false;
303 } else {
304 oss << "\n";
305 }
306 oss << after_reg2;
307
308 (Base::GetAssembler()->*f)(*reg1, *reg2, c);
309 }
310 }
311 }
312 // Add a newline at the end.
313 oss << "\n";
314
315 return oss.str();
316 }
317
318 std::string RepeatRRRC(void (Ass::*f)(Reg, Reg, Reg, Cond), std::string fmt) {
319 return RepeatTemplatedRRRC(f, GetRegisters(), GetRegisters(), GetRegisters(), GetConditions(),
320 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
321 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
322 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
323 fmt);
324 }
325
326 template <typename Reg1, typename Reg2, typename Reg3>
327 std::string RepeatTemplatedRRRC(void (Ass::*f)(Reg1, Reg2, Reg3, Cond),
328 const std::vector<Reg1*>& reg1_registers,
329 const std::vector<Reg2*>& reg2_registers,
330 const std::vector<Reg3*>& reg3_registers,
331 const std::vector<Cond>& cond,
332 std::string (AssemblerArmTest::*GetName1)(const Reg1&),
333 std::string (AssemblerArmTest::*GetName2)(const Reg2&),
334 std::string (AssemblerArmTest::*GetName3)(const Reg3&),
335 std::string fmt) {
336 WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() *
337 reg3_registers.size());
338
339 std::ostringstream oss;
340 bool first = true;
341 for (const Cond& c : cond) {
342 std::string after_cond = fmt;
343
344 size_t cond_index = after_cond.find(COND_TOKEN);
345 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100346 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800347 }
348
349 for (auto reg1 : reg1_registers) {
350 std::string after_reg1 = after_cond;
351
352 std::string reg1_string = (this->*GetName1)(*reg1);
353 size_t reg1_index;
354 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
355 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
356 }
357
358 for (auto reg2 : reg2_registers) {
359 std::string after_reg2 = after_reg1;
360
361 std::string reg2_string = (this->*GetName2)(*reg2);
362 size_t reg2_index;
363 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
364 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
365 }
366
367 for (auto reg3 : reg3_registers) {
368 std::string after_reg3 = after_reg2;
369
370 std::string reg3_string = (this->*GetName3)(*reg3);
371 size_t reg3_index;
372 while ((reg3_index = after_reg3.find(REG3_TOKEN)) != std::string::npos) {
373 after_reg3.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
374 }
375
376 if (first) {
377 first = false;
378 } else {
379 oss << "\n";
380 }
381 oss << after_reg3;
382
383 (Base::GetAssembler()->*f)(*reg1, *reg2, *reg3, c);
384 }
385 }
386 }
387 }
388 // Add a newline at the end.
389 oss << "\n";
390
391 return oss.str();
392 }
393
394 template <typename RegT>
395 std::string RepeatTemplatedRSC(void (Ass::*f)(RegT, SOp, Cond),
396 const std::vector<RegT*>& registers,
397 const std::vector<SOp>& shifts,
398 const std::vector<Cond>& cond,
399 std::string (AssemblerArmTest::*GetName)(const RegT&),
400 std::string fmt) {
401 WarnOnCombinations(cond.size() * registers.size() * shifts.size());
402
403 std::ostringstream oss;
404 bool first = true;
405 for (const Cond& c : cond) {
406 std::string after_cond = fmt;
407
408 size_t cond_index = after_cond.find(COND_TOKEN);
409 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100410 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800411 }
412
413 for (const SOp& shift : shifts) {
414 std::string after_shift = after_cond;
415
416 std::string shift_string = GetShiftString(shift);
417 size_t shift_index;
418 while ((shift_index = after_shift.find(Base::SHIFT_TOKEN)) != std::string::npos) {
419 after_shift.replace(shift_index, ConstexprStrLen(Base::SHIFT_TOKEN), shift_string);
420 }
421
422 for (auto reg : registers) {
423 std::string after_reg = after_shift;
424
425 std::string reg_string = (this->*GetName)(*reg);
426 size_t reg_index;
427 while ((reg_index = after_reg.find(Base::REG_TOKEN)) != std::string::npos) {
428 after_reg.replace(reg_index, ConstexprStrLen(Base::REG_TOKEN), reg_string);
429 }
430
431 if (first) {
432 first = false;
433 } else {
434 oss << "\n";
435 }
436 oss << after_reg;
437
438 (Base::GetAssembler()->*f)(*reg, shift, c);
439 }
440 }
441 }
442 // Add a newline at the end.
443 oss << "\n";
444
445 return oss.str();
446 }
447
448 template <typename Reg1, typename Reg2>
449 std::string RepeatTemplatedRRSC(void (Ass::*f)(Reg1, Reg2, const SOp&, Cond),
450 const std::vector<Reg1*>& reg1_registers,
451 const std::vector<Reg2*>& reg2_registers,
452 const std::vector<SOp>& shifts,
453 const std::vector<Cond>& cond,
454 std::string (AssemblerArmTest::*GetName1)(const Reg1&),
455 std::string (AssemblerArmTest::*GetName2)(const Reg2&),
456 std::string fmt) {
457 WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * shifts.size());
458
459 std::ostringstream oss;
460 bool first = true;
461 for (const Cond& c : cond) {
462 std::string after_cond = fmt;
463
464 size_t cond_index = after_cond.find(COND_TOKEN);
465 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100466 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800467 }
468
469 for (const SOp& shift : shifts) {
470 std::string after_shift = after_cond;
471
472 std::string shift_string = GetShiftString(shift);
473 size_t shift_index;
474 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
475 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
476 }
477
478 for (auto reg1 : reg1_registers) {
479 std::string after_reg1 = after_shift;
480
481 std::string reg1_string = (this->*GetName1)(*reg1);
482 size_t reg1_index;
483 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
484 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
485 }
486
487 for (auto reg2 : reg2_registers) {
488 std::string after_reg2 = after_reg1;
489
490 std::string reg2_string = (this->*GetName2)(*reg2);
491 size_t reg2_index;
492 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
493 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
494 }
495
496 if (first) {
497 first = false;
498 } else {
499 oss << "\n";
500 }
501 oss << after_reg2;
502
503 (Base::GetAssembler()->*f)(*reg1, *reg2, shift, c);
504 }
505 }
506 }
507 }
508 // Add a newline at the end.
509 oss << "\n";
510
511 return oss.str();
512 }
513
514 protected:
515 explicit AssemblerArmTest() {}
516
517 virtual std::vector<Cond>& GetConditions() = 0;
518 virtual std::string GetConditionString(Cond c) = 0;
519
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100520 virtual std::vector<SetCc>& GetSetCcs() = 0;
521 virtual std::string GetSetCcString(SetCc s) = 0;
522
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800523 virtual std::vector<SOp>& GetShiftOperands() = 0;
524 virtual std::string GetShiftString(SOp sop) = 0;
525
526 virtual Reg GetPCRegister() = 0;
527 virtual std::vector<Reg*> GetRegistersWithoutPC() {
528 std::vector<Reg*> without_pc = GetRegisters();
529 Reg pc_reg = GetPCRegister();
530
531 for (auto it = without_pc.begin(); it != without_pc.end(); ++it) {
532 if (**it == pc_reg) {
533 without_pc.erase(it);
534 break;
535 }
536 }
537
538 return without_pc;
539 }
540
541 static constexpr const char* IMM1_TOKEN = "{imm1}";
542 static constexpr const char* IMM2_TOKEN = "{imm2}";
543 static constexpr const char* REG3_TOKEN = "{reg3}";
544 static constexpr const char* REG4_TOKEN = "{reg4}";
545 static constexpr const char* COND_TOKEN = "{cond}";
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100546 static constexpr const char* SET_CC_TOKEN = "{s}";
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800547 static constexpr const char* SHIFT_TOKEN = "{shift}";
548
549 private:
550 DISALLOW_COPY_AND_ASSIGN(AssemblerArmTest);
551};
552
553} // namespace art
554
555#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_