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