1/*
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,
25         typename Reg,
26         typename FPReg,
27         typename Imm,
28         typename SOp,
29         typename Cond,
30         typename SetCc>
31class 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) {
103        after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
104      }
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) {
168    return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(),
169        &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) {
194        after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
195      }
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) {
280        after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
281      }
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) {
346        after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
347      }
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) {
410        after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
411      }
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) {
466        after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
467      }
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
520  virtual std::vector<SetCc>& GetSetCcs() = 0;
521  virtual std::string GetSetCcString(SetCc s) = 0;
522
523  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}";
546  static constexpr const char* SET_CC_TOKEN = "{s}";
547  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_
556