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_ASSEMBLER_TEST_H_
18 #define ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
19 
20 #include "assembler.h"
21 
22 #include <sys/stat.h>
23 
24 #include <cstdio>
25 #include <cstdlib>
26 #include <fstream>
27 #include <iterator>
28 
29 #include "base/malloc_arena_pool.h"
30 #include "assembler_test_base.h"
31 #include "common_runtime_test.h"  // For ScratchFile
32 
33 namespace art {
34 
35 // Helper for a constexpr string length.
36 constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
37   return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
38 }
39 
40 enum class RegisterView {  // private
41   kUsePrimaryName,
42   kUseSecondaryName,
43   kUseTertiaryName,
44   kUseQuaternaryName,
45 };
46 
47 // For use in the template as the default type to get a nonvector registers version.
48 struct NoVectorRegs {};
49 
50 template<typename Ass,
51          typename Addr,
52          typename Reg,
53          typename FPReg,
54          typename Imm,
55          typename VecReg = NoVectorRegs>
56 class AssemblerTest : public AssemblerTestBase {
57  public:
GetAssembler()58   Ass* GetAssembler() {
59     return assembler_.get();
60   }
61 
62   typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
63 
DriverFn(TestFn f,const std::string & test_name)64   void DriverFn(TestFn f, const std::string& test_name) {
65     DriverWrapper(f(this, assembler_.get()), test_name);
66   }
67 
68   // This driver assumes the assembler has already been called.
DriverStr(const std::string & assembly_string,const std::string & test_name)69   void DriverStr(const std::string& assembly_string, const std::string& test_name) {
70     DriverWrapper(assembly_string, test_name);
71   }
72 
73   //
74   // Register repeats.
75   //
76 
RepeatR(void (Ass::* f)(Reg),const std::string & fmt)77   std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
78     return RepeatTemplatedRegister<Reg>(f,
79         GetRegisters(),
80         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
81         fmt);
82   }
83 
Repeatr(void (Ass::* f)(Reg),const std::string & fmt)84   std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
85     return RepeatTemplatedRegister<Reg>(f,
86         GetRegisters(),
87         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
88         fmt);
89   }
90 
RepeatRR(void (Ass::* f)(Reg,Reg),const std::string & fmt)91   std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
92     return RepeatTemplatedRegisters<Reg, Reg>(f,
93         GetRegisters(),
94         GetRegisters(),
95         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
96         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
97         fmt);
98   }
99 
RepeatRRNoDupes(void (Ass::* f)(Reg,Reg),const std::string & fmt)100   std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
101     return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
102         GetRegisters(),
103         GetRegisters(),
104         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
105         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
106         fmt);
107   }
108 
Repeatrr(void (Ass::* f)(Reg,Reg),const std::string & fmt)109   std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
110     return RepeatTemplatedRegisters<Reg, Reg>(f,
111         GetRegisters(),
112         GetRegisters(),
113         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
114         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
115         fmt);
116   }
117 
Repeatww(void (Ass::* f)(Reg,Reg),const std::string & fmt)118   std::string Repeatww(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
119     return RepeatTemplatedRegisters<Reg, Reg>(f,
120         GetRegisters(),
121         GetRegisters(),
122         &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
123         &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
124         fmt);
125   }
126 
Repeatbb(void (Ass::* f)(Reg,Reg),const std::string & fmt)127   std::string Repeatbb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
128     return RepeatTemplatedRegisters<Reg, Reg>(f,
129         GetRegisters(),
130         GetRegisters(),
131         &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
132         &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
133         fmt);
134   }
135 
RepeatRRR(void (Ass::* f)(Reg,Reg,Reg),const std::string & fmt)136   std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
137     return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
138         GetRegisters(),
139         GetRegisters(),
140         GetRegisters(),
141         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
142         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
143         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
144         fmt);
145   }
146 
Repeatrb(void (Ass::* f)(Reg,Reg),const std::string & fmt)147   std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
148     return RepeatTemplatedRegisters<Reg, Reg>(f,
149         GetRegisters(),
150         GetRegisters(),
151         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
152         &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
153         fmt);
154   }
155 
RepeatRr(void (Ass::* f)(Reg,Reg),const std::string & fmt)156   std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
157     return RepeatTemplatedRegisters<Reg, Reg>(f,
158         GetRegisters(),
159         GetRegisters(),
160         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
161         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
162         fmt);
163   }
164 
RepeatRI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)165   std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
166     return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
167   }
168 
RepeatrI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)169   std::string RepeatrI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
170     return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
171   }
172 
RepeatwI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)173   std::string RepeatwI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
174     return RepeatRegisterImm<RegisterView::kUseTertiaryName>(f, imm_bytes, fmt);
175   }
176 
RepeatbI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)177   std::string RepeatbI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
178     return RepeatRegisterImm<RegisterView::kUseQuaternaryName>(f, imm_bytes, fmt);
179   }
180 
181   template <typename Reg1, typename Reg2, typename ImmType>
182   std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
183                                               int imm_bits,
184                                               const std::vector<Reg1*> reg1_registers,
185                                               const std::vector<Reg2*> reg2_registers,
186                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
187                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
188                                               const std::string& fmt,
189                                               int bias = 0,
190                                               int multiplier = 1) {
191     std::string str;
192     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
193 
194     for (auto reg1 : reg1_registers) {
195       for (auto reg2 : reg2_registers) {
196         for (int64_t imm : imms) {
197           ImmType new_imm = CreateImmediate(imm);
198           if (f != nullptr) {
199             (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
200           }
201           std::string base = fmt;
202 
203           std::string reg1_string = (this->*GetName1)(*reg1);
204           size_t reg1_index;
205           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
206             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
207           }
208 
209           std::string reg2_string = (this->*GetName2)(*reg2);
210           size_t reg2_index;
211           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
212             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
213           }
214 
215           size_t imm_index = base.find(IMM_TOKEN);
216           if (imm_index != std::string::npos) {
217             std::ostringstream sreg;
218             sreg << imm * multiplier + bias;
219             std::string imm_string = sreg.str();
220             base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
221           }
222 
223           if (str.size() > 0) {
224             str += "\n";
225           }
226           str += base;
227         }
228       }
229     }
230     // Add a newline at the end.
231     str += "\n";
232     return str;
233   }
234 
235   template <typename Reg1, typename Reg2, typename Reg3, typename ImmType>
RepeatTemplatedRegistersImmBits(void (Ass::* f)(Reg1,Reg2,Reg3,ImmType),int imm_bits,const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,const std::vector<Reg3 * > reg3_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),std::string (AssemblerTest::* GetName3)(const Reg3 &),std::string fmt,int bias)236   std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
237                                               int imm_bits,
238                                               const std::vector<Reg1*> reg1_registers,
239                                               const std::vector<Reg2*> reg2_registers,
240                                               const std::vector<Reg3*> reg3_registers,
241                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
242                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
243                                               std::string (AssemblerTest::*GetName3)(const Reg3&),
244                                               std::string fmt,
245                                               int bias) {
246     std::string str;
247     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
248 
249     for (auto reg1 : reg1_registers) {
250       for (auto reg2 : reg2_registers) {
251         for (auto reg3 : reg3_registers) {
252           for (int64_t imm : imms) {
253             ImmType new_imm = CreateImmediate(imm);
254             if (f != nullptr) {
255               (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
256             }
257             std::string base = fmt;
258 
259             std::string reg1_string = (this->*GetName1)(*reg1);
260             size_t reg1_index;
261             while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
262               base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
263             }
264 
265             std::string reg2_string = (this->*GetName2)(*reg2);
266             size_t reg2_index;
267             while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
268               base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
269             }
270 
271             std::string reg3_string = (this->*GetName3)(*reg3);
272             size_t reg3_index;
273             while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
274               base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
275             }
276 
277             size_t imm_index = base.find(IMM_TOKEN);
278             if (imm_index != std::string::npos) {
279               std::ostringstream sreg;
280               sreg << imm + bias;
281               std::string imm_string = sreg.str();
282               base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
283             }
284 
285             if (str.size() > 0) {
286               str += "\n";
287             }
288             str += base;
289           }
290         }
291       }
292     }
293     // Add a newline at the end.
294     str += "\n";
295     return str;
296   }
297 
298   template <typename ImmType, typename Reg1, typename Reg2>
RepeatTemplatedImmBitsRegisters(void (Ass::* f)(ImmType,Reg1,Reg2),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),int imm_bits,const std::string & fmt)299   std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
300                                               const std::vector<Reg1*> reg1_registers,
301                                               const std::vector<Reg2*> reg2_registers,
302                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
303                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
304                                               int imm_bits,
305                                               const std::string& fmt) {
306     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
307 
308     WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
309 
310     std::string str;
311     for (auto reg1 : reg1_registers) {
312       for (auto reg2 : reg2_registers) {
313         for (int64_t imm : imms) {
314           ImmType new_imm = CreateImmediate(imm);
315           if (f != nullptr) {
316             (assembler_.get()->*f)(new_imm, *reg1, *reg2);
317           }
318           std::string base = fmt;
319 
320           std::string reg1_string = (this->*GetName1)(*reg1);
321           size_t reg1_index;
322           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
323             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
324           }
325 
326           std::string reg2_string = (this->*GetName2)(*reg2);
327           size_t reg2_index;
328           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
329             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
330           }
331 
332           size_t imm_index = base.find(IMM_TOKEN);
333           if (imm_index != std::string::npos) {
334             std::ostringstream sreg;
335             sreg << imm;
336             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     }
347     // Add a newline at the end.
348     str += "\n";
349     return str;
350   }
351 
352   template <typename RegType, typename ImmType>
RepeatTemplatedRegisterImmBits(void (Ass::* f)(RegType,ImmType),int imm_bits,const std::vector<RegType * > registers,std::string (AssemblerTest::* GetName)(const RegType &),const std::string & fmt,int bias)353   std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
354                                              int imm_bits,
355                                              const std::vector<RegType*> registers,
356                                              std::string (AssemblerTest::*GetName)(const RegType&),
357                                              const std::string& fmt,
358                                              int bias) {
359     std::string str;
360     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
361 
362     for (auto reg : registers) {
363       for (int64_t imm : imms) {
364         ImmType new_imm = CreateImmediate(imm);
365         if (f != nullptr) {
366           (assembler_.get()->*f)(*reg, new_imm + bias);
367         }
368         std::string base = fmt;
369 
370         std::string reg_string = (this->*GetName)(*reg);
371         size_t reg_index;
372         while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
373           base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
374         }
375 
376         size_t imm_index = base.find(IMM_TOKEN);
377         if (imm_index != std::string::npos) {
378           std::ostringstream sreg;
379           sreg << imm + bias;
380           std::string imm_string = sreg.str();
381           base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
382         }
383 
384         if (str.size() > 0) {
385           str += "\n";
386         }
387         str += base;
388       }
389     }
390     // Add a newline at the end.
391     str += "\n";
392     return str;
393   }
394 
395   template <typename ImmType>
396   std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
397                          int imm_bits,
398                          const std::string& fmt,
399                          int bias = 0) {
400     return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
401         imm_bits,
402         GetRegisters(),
403         GetRegisters(),
404         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
405         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
406         fmt,
407         bias);
408   }
409 
410   template <typename ImmType>
411   std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
412                           int imm_bits,
413                           const std::string& fmt,
414                           int bias = 0) {
415     return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
416         imm_bits,
417         GetRegisters(),
418         GetRegisters(),
419         GetRegisters(),
420         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
421         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
422         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
423         fmt,
424         bias);
425   }
426 
427   template <typename ImmType>
428   std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
429     return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
430         imm_bits,
431         GetRegisters(),
432         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
433         fmt,
434         bias);
435   }
436 
437   template <typename ImmType>
438   std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
439                          int imm_bits,
440                          const std::string& fmt,
441                          int bias = 0) {
442     return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
443         imm_bits,
444         GetFPRegisters(),
445         GetRegisters(),
446         &AssemblerTest::GetFPRegName,
447         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
448         fmt,
449         bias);
450   }
451 
RepeatFF(void (Ass::* f)(FPReg,FPReg),const std::string & fmt)452   std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
453     return RepeatTemplatedRegisters<FPReg, FPReg>(f,
454                                                   GetFPRegisters(),
455                                                   GetFPRegisters(),
456                                                   &AssemblerTest::GetFPRegName,
457                                                   &AssemblerTest::GetFPRegName,
458                                                   fmt);
459   }
460 
RepeatFFF(void (Ass::* f)(FPReg,FPReg,FPReg),const std::string & fmt)461   std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
462     return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
463                                                          GetFPRegisters(),
464                                                          GetFPRegisters(),
465                                                          GetFPRegisters(),
466                                                          &AssemblerTest::GetFPRegName,
467                                                          &AssemblerTest::GetFPRegName,
468                                                          &AssemblerTest::GetFPRegName,
469                                                          fmt);
470   }
471 
RepeatFFR(void (Ass::* f)(FPReg,FPReg,Reg),const std::string & fmt)472   std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
473     return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
474         f,
475         GetFPRegisters(),
476         GetFPRegisters(),
477         GetRegisters(),
478         &AssemblerTest::GetFPRegName,
479         &AssemblerTest::GetFPRegName,
480         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
481         fmt);
482   }
483 
RepeatFFI(void (Ass::* f)(FPReg,FPReg,const Imm &),size_t imm_bytes,const std::string & fmt)484   std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
485                         size_t imm_bytes,
486                         const std::string& fmt) {
487     return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
488                                                      GetFPRegisters(),
489                                                      GetFPRegisters(),
490                                                      &AssemblerTest::GetFPRegName,
491                                                      &AssemblerTest::GetFPRegName,
492                                                      imm_bytes,
493                                                      fmt);
494   }
495 
496   template <typename ImmType>
RepeatFFIb(void (Ass::* f)(FPReg,FPReg,ImmType),int imm_bits,const std::string & fmt)497   std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
498                          int imm_bits,
499                          const std::string& fmt) {
500     return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
501                                                                   imm_bits,
502                                                                   GetFPRegisters(),
503                                                                   GetFPRegisters(),
504                                                                   &AssemblerTest::GetFPRegName,
505                                                                   &AssemblerTest::GetFPRegName,
506                                                                   fmt);
507   }
508 
509   template <typename ImmType>
RepeatIbFF(void (Ass::* f)(ImmType,FPReg,FPReg),int imm_bits,const std::string & fmt)510   std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
511                          int imm_bits,
512                          const std::string& fmt) {
513     return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
514                                                                   GetFPRegisters(),
515                                                                   GetFPRegisters(),
516                                                                   &AssemblerTest::GetFPRegName,
517                                                                   &AssemblerTest::GetFPRegName,
518                                                                   imm_bits,
519                                                                   fmt);
520   }
521 
RepeatFR(void (Ass::* f)(FPReg,Reg),const std::string & fmt)522   std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
523     return RepeatTemplatedRegisters<FPReg, Reg>(f,
524         GetFPRegisters(),
525         GetRegisters(),
526         &AssemblerTest::GetFPRegName,
527         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
528         fmt);
529   }
530 
RepeatFr(void (Ass::* f)(FPReg,Reg),const std::string & fmt)531   std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
532     return RepeatTemplatedRegisters<FPReg, Reg>(f,
533         GetFPRegisters(),
534         GetRegisters(),
535         &AssemblerTest::GetFPRegName,
536         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
537         fmt);
538   }
539 
RepeatRF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)540   std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
541     return RepeatTemplatedRegisters<Reg, FPReg>(f,
542         GetRegisters(),
543         GetFPRegisters(),
544         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
545         &AssemblerTest::GetFPRegName,
546         fmt);
547   }
548 
RepeatrF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)549   std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
550     return RepeatTemplatedRegisters<Reg, FPReg>(f,
551         GetRegisters(),
552         GetFPRegisters(),
553         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
554         &AssemblerTest::GetFPRegName,
555         fmt);
556   }
557 
558   std::string RepeatI(void (Ass::*f)(const Imm&),
559                       size_t imm_bytes,
560                       const std::string& fmt,
561                       bool as_uint = false) {
562     std::string str;
563     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
564 
565     WarnOnCombinations(imms.size());
566 
567     for (int64_t imm : imms) {
568       Imm new_imm = CreateImmediate(imm);
569       if (f != nullptr) {
570         (assembler_.get()->*f)(new_imm);
571       }
572       std::string base = fmt;
573 
574       size_t imm_index = base.find(IMM_TOKEN);
575       if (imm_index != std::string::npos) {
576         std::ostringstream sreg;
577         sreg << imm;
578         std::string imm_string = sreg.str();
579         base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
580       }
581 
582       if (str.size() > 0) {
583         str += "\n";
584       }
585       str += base;
586     }
587     // Add a newline at the end.
588     str += "\n";
589     return str;
590   }
591 
RepeatVV(void (Ass::* f)(VecReg,VecReg),const std::string & fmt)592   std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
593     return RepeatTemplatedRegisters<VecReg, VecReg>(f,
594                                                     GetVectorRegisters(),
595                                                     GetVectorRegisters(),
596                                                     &AssemblerTest::GetVecRegName,
597                                                     &AssemblerTest::GetVecRegName,
598                                                     fmt);
599   }
600 
RepeatVVV(void (Ass::* f)(VecReg,VecReg,VecReg),const std::string & fmt)601   std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
602     return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
603                                                             GetVectorRegisters(),
604                                                             GetVectorRegisters(),
605                                                             GetVectorRegisters(),
606                                                             &AssemblerTest::GetVecRegName,
607                                                             &AssemblerTest::GetVecRegName,
608                                                             &AssemblerTest::GetVecRegName,
609                                                             fmt);
610   }
611 
RepeatVR(void (Ass::* f)(VecReg,Reg),const std::string & fmt)612   std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
613     return RepeatTemplatedRegisters<VecReg, Reg>(
614         f,
615         GetVectorRegisters(),
616         GetRegisters(),
617         &AssemblerTest::GetVecRegName,
618         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
619         fmt);
620   }
621 
622   template <typename ImmType>
623   std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
624                         int imm_bits,
625                         std::string fmt,
626                         int bias = 0) {
627     return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
628                                                            imm_bits,
629                                                            GetVectorRegisters(),
630                                                            &AssemblerTest::GetVecRegName,
631                                                            fmt,
632                                                            bias);
633   }
634 
635   template <typename ImmType>
636   std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
637                          int imm_bits,
638                          const std::string& fmt,
639                          int bias = 0,
640                          int multiplier = 1) {
641     return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
642         f,
643         imm_bits,
644         GetVectorRegisters(),
645         GetRegisters(),
646         &AssemblerTest::GetVecRegName,
647         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
648         fmt,
649         bias,
650         multiplier);
651   }
652 
653   template <typename ImmType>
654   std::string RepeatRVIb(void (Ass::*f)(Reg, VecReg, ImmType),
655                          int imm_bits,
656                          const std::string& fmt,
657                          int bias = 0,
658                          int multiplier = 1) {
659     return RepeatTemplatedRegistersImmBits<Reg, VecReg, ImmType>(
660         f,
661         imm_bits,
662         GetRegisters(),
663         GetVectorRegisters(),
664         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
665         &AssemblerTest::GetVecRegName,
666         fmt,
667         bias,
668         multiplier);
669   }
670 
671   template <typename ImmType>
672   std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
673                          int imm_bits,
674                          const std::string& fmt,
675                          int bias = 0) {
676     return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
677                                                                     imm_bits,
678                                                                     GetVectorRegisters(),
679                                                                     GetVectorRegisters(),
680                                                                     &AssemblerTest::GetVecRegName,
681                                                                     &AssemblerTest::GetVecRegName,
682                                                                     fmt,
683                                                                     bias);
684   }
685 
686   // The following functions are public so that TestFn can use them...
687 
688   // Returns a vector of address used by any of the repeat methods
689   // involving an "A" (e.g. RepeatA).
690   virtual std::vector<Addr> GetAddresses() = 0;
691 
692   // Returns a vector of registers used by any of the repeat methods
693   // involving an "R" (e.g. RepeatR).
694   virtual std::vector<Reg*> GetRegisters() = 0;
695 
696   // Returns a vector of fp-registers used by any of the repeat methods
697   // involving an "F" (e.g. RepeatFF).
GetFPRegisters()698   virtual std::vector<FPReg*> GetFPRegisters() {
699     UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
700     UNREACHABLE();
701   }
702 
703   // Returns a vector of dedicated simd-registers used by any of the repeat
704   // methods involving an "V" (e.g. RepeatVV).
GetVectorRegisters()705   virtual std::vector<VecReg*> GetVectorRegisters() {
706     UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
707     UNREACHABLE();
708   }
709 
710   // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
GetSecondaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)711   virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
712     UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
713     UNREACHABLE();
714   }
715 
716   // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
GetTertiaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)717   virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
718     UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
719     UNREACHABLE();
720   }
721 
722   // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
GetQuaternaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)723   virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
724     UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
725     UNREACHABLE();
726   }
727 
GetRegisterName(const Reg & reg)728   std::string GetRegisterName(const Reg& reg) {
729     return GetRegName<RegisterView::kUsePrimaryName>(reg);
730   }
731 
732  protected:
AssemblerTest()733   AssemblerTest() {}
734 
SetUp()735   void SetUp() override {
736     AssemblerTestBase::SetUp();
737     allocator_.reset(new ArenaAllocator(&pool_));
738     assembler_.reset(CreateAssembler(allocator_.get()));
739     SetUpHelpers();
740   }
741 
TearDown()742   void TearDown() override {
743     AssemblerTestBase::TearDown();
744     assembler_.reset();
745     allocator_.reset();
746   }
747 
748   // Override this to set up any architecture-specific things, e.g., CPU revision.
CreateAssembler(ArenaAllocator * allocator)749   virtual Ass* CreateAssembler(ArenaAllocator* allocator) {
750     return new (allocator) Ass(allocator);
751   }
752 
753   // Override this to set up any architecture-specific things, e.g., register vectors.
SetUpHelpers()754   virtual void SetUpHelpers() {}
755 
756   // Create a couple of immediate values up to the number of bytes given.
757   virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
758     std::vector<int64_t> res;
759     res.push_back(0);
760     if (!as_uint) {
761       res.push_back(-1);
762     } else {
763       res.push_back(0xFF);
764     }
765     res.push_back(0x12);
766     if (imm_bytes >= 2) {
767       res.push_back(0x1234);
768       if (!as_uint) {
769         res.push_back(-0x1234);
770       } else {
771         res.push_back(0xFFFF);
772       }
773       if (imm_bytes >= 4) {
774         res.push_back(0x12345678);
775         if (!as_uint) {
776           res.push_back(-0x12345678);
777         } else {
778           res.push_back(0xFFFFFFFF);
779         }
780         if (imm_bytes >= 6) {
781           res.push_back(0x123456789ABC);
782           if (!as_uint) {
783             res.push_back(-0x123456789ABC);
784           }
785           if (imm_bytes >= 8) {
786             res.push_back(0x123456789ABCDEF0);
787             if (!as_uint) {
788               res.push_back(-0x123456789ABCDEF0);
789             } else {
790               res.push_back(0xFFFFFFFFFFFFFFFF);
791             }
792           }
793         }
794       }
795     }
796     return res;
797   }
798 
799   const int kMaxBitsExhaustiveTest = 8;
800 
801   // Create a couple of immediate values up to the number of bits given.
802   virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
803     CHECK_GT(imm_bits, 0);
804     CHECK_LE(imm_bits, 64);
805     std::vector<int64_t> res;
806 
807     if (imm_bits <= kMaxBitsExhaustiveTest) {
808       if (as_uint) {
809         for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
810           res.push_back(static_cast<int64_t>(i));
811         }
812       } else {
813         for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
814           res.push_back(i);
815         }
816       }
817     } else {
818       if (as_uint) {
819         for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
820              i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
821              i++) {
822           res.push_back(static_cast<int64_t>(i));
823         }
824         for (int i = 0; i <= imm_bits; i++) {
825           uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
826                        ((MaxInt<uint64_t>(imm_bits) -
827                         (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
828                         * i / imm_bits);
829           res.push_back(static_cast<int64_t>(j));
830         }
831       } else {
832         for (int i = 0; i <= imm_bits; i++) {
833           int64_t j = MinInt<int64_t>(imm_bits) +
834                       ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
835                          MinInt<int64_t>(imm_bits))
836                         * i) / imm_bits);
837           res.push_back(static_cast<int64_t>(j));
838         }
839         for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
840              i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
841              i++) {
842           res.push_back(static_cast<int64_t>(i));
843         }
844         for (int i = 0; i <= imm_bits; i++) {
845           int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
846                       ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
847                        * i / imm_bits);
848           res.push_back(static_cast<int64_t>(j));
849         }
850       }
851     }
852 
853     return res;
854   }
855 
856   // Create an immediate from the specific value.
857   virtual Imm CreateImmediate(int64_t imm_value) = 0;
858 
859   //
860   // Addresses repeats.
861   //
862 
863   // Repeats over addresses provided by fixture.
RepeatA(void (Ass::* f)(const Addr &),const std::string & fmt)864   std::string RepeatA(void (Ass::*f)(const Addr&), const std::string& fmt) {
865     return RepeatA(f, GetAddresses(), fmt);
866   }
867 
868   // Variant that takes explicit vector of addresss
869   // (to test restricted addressing modes set).
RepeatA(void (Ass::* f)(const Addr &),const std::vector<Addr> & a,const std::string & fmt)870   std::string RepeatA(void (Ass::*f)(const Addr&),
871                       const std::vector<Addr>& a,
872                       const std::string& fmt) {
873     return RepeatTemplatedMem<Addr>(f, a, &AssemblerTest::GetAddrName, fmt);
874   }
875 
876   // Repeats over addresses and immediates provided by fixture.
RepeatAI(void (Ass::* f)(const Addr &,const Imm &),size_t imm_bytes,const std::string & fmt)877   std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&),
878                        size_t imm_bytes,
879                        const std::string& fmt) {
880     return RepeatAI(f, imm_bytes, GetAddresses(), fmt);
881   }
882 
883   // Variant that takes explicit vector of addresss
884   // (to test restricted addressing modes set).
RepeatAI(void (Ass::* f)(const Addr &,const Imm &),size_t imm_bytes,const std::vector<Addr> & a,const std::string & fmt)885   std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&),
886                        size_t imm_bytes,
887                        const std::vector<Addr>& a,
888                        const std::string& fmt) {
889     return RepeatTemplatedMemImm<Addr>(f, imm_bytes, a, &AssemblerTest::GetAddrName, fmt);
890   }
891 
892   // Repeats over registers and addresses provided by fixture.
RepeatRA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)893   std::string RepeatRA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
894     return RepeatRA(f, GetAddresses(), fmt);
895   }
896 
897   // Variant that takes explicit vector of addresss
898   // (to test restricted addressing modes set).
RepeatRA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)899   std::string RepeatRA(void (Ass::*f)(Reg, const Addr&),
900                        const std::vector<Addr>& a,
901                        const std::string& fmt) {
902     return RepeatTemplatedRegMem<Reg, Addr>(
903         f,
904         GetRegisters(),
905         a,
906         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
907         &AssemblerTest::GetAddrName,
908         fmt);
909   }
910 
911   // Repeats over secondary registers and addresses provided by fixture.
RepeatrA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)912   std::string RepeatrA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
913     return RepeatrA(f, GetAddresses(), fmt);
914   }
915 
916   // Variant that takes explicit vector of addresss
917   // (to test restricted addressing modes set).
RepeatrA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)918   std::string RepeatrA(void (Ass::*f)(Reg, const Addr&),
919                        const std::vector<Addr>& a,
920                        const std::string& fmt) {
921     return RepeatTemplatedRegMem<Reg, Addr>(
922         f,
923         GetRegisters(),
924         a,
925         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
926         &AssemblerTest::GetAddrName,
927         fmt);
928   }
929 
930   // Repeats over tertiary registers and addresses provided by fixture.
RepeatwA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)931   std::string RepeatwA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
932     return RepeatwA(f, GetAddresses(), fmt);
933   }
934 
935   // Variant that takes explicit vector of addresss
936   // (to test restricted addressing modes set).
RepeatwA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)937   std::string RepeatwA(void (Ass::*f)(Reg, const Addr&),
938                        const std::vector<Addr>& a,
939                        const std::string& fmt) {
940     return RepeatTemplatedRegMem<Reg, Addr>(
941         f,
942         GetRegisters(),
943         a,
944         &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
945         &AssemblerTest::GetAddrName,
946         fmt);
947   }
948 
949   // Repeats over quaternary registers and addresses provided by fixture.
RepeatbA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)950   std::string RepeatbA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
951     return RepeatbA(f, GetAddresses(), fmt);
952   }
953 
954   // Variant that takes explicit vector of addresss
955   // (to test restricted addressing modes set).
RepeatbA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)956   std::string RepeatbA(void (Ass::*f)(Reg, const Addr&),
957                        const std::vector<Addr>& a,
958                        const std::string& fmt) {
959     return RepeatTemplatedRegMem<Reg, Addr>(
960         f,
961         GetRegisters(),
962         a,
963         &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
964         &AssemblerTest::GetAddrName,
965         fmt);
966   }
967 
968   // Repeats over fp-registers and addresses provided by fixture.
RepeatFA(void (Ass::* f)(FPReg,const Addr &),const std::string & fmt)969   std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&), const std::string& fmt) {
970     return RepeatFA(f, GetAddresses(), fmt);
971   }
972 
973   // Variant that takes explicit vector of addresss
974   // (to test restricted addressing modes set).
RepeatFA(void (Ass::* f)(FPReg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)975   std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&),
976                        const std::vector<Addr>& a,
977                        const std::string& fmt) {
978     return RepeatTemplatedRegMem<FPReg, Addr>(
979         f,
980         GetFPRegisters(),
981         a,
982         &AssemblerTest::GetFPRegName,
983         &AssemblerTest::GetAddrName,
984         fmt);
985   }
986 
987   // Repeats over addresses and registers provided by fixture.
RepeatAR(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)988   std::string RepeatAR(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
989     return RepeatAR(f, GetAddresses(), fmt);
990   }
991 
992   // Variant that takes explicit vector of addresss
993   // (to test restricted addressing modes set).
RepeatAR(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)994   std::string RepeatAR(void (Ass::*f)(const Addr&, Reg),
995                        const std::vector<Addr>& a,
996                        const std::string& fmt) {
997     return RepeatTemplatedMemReg<Addr, Reg>(
998         f,
999         a,
1000         GetRegisters(),
1001         &AssemblerTest::GetAddrName,
1002         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
1003         fmt);
1004   }
1005 
1006   // Repeats over addresses and secondary registers provided by fixture.
RepeatAr(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1007   std::string RepeatAr(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
1008     return RepeatAr(f, GetAddresses(), fmt);
1009   }
1010 
1011   // Variant that takes explicit vector of addresss
1012   // (to test restricted addressing modes set).
RepeatAr(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1013   std::string RepeatAr(void (Ass::*f)(const Addr&, Reg),
1014                        const std::vector<Addr>& a,
1015                        const std::string& fmt) {
1016     return RepeatTemplatedMemReg<Addr, Reg>(
1017         f,
1018         a,
1019         GetRegisters(),
1020         &AssemblerTest::GetAddrName,
1021         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
1022         fmt);
1023   }
1024 
1025   // Repeats over addresses and tertiary registers provided by fixture.
RepeatAw(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1026   std::string RepeatAw(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
1027     return RepeatAw(f, GetAddresses(), fmt);
1028   }
1029 
1030   // Variant that takes explicit vector of addresss
1031   // (to test restricted addressing modes set).
RepeatAw(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1032   std::string RepeatAw(void (Ass::*f)(const Addr&, Reg),
1033                        const std::vector<Addr>& a,
1034                        const std::string& fmt) {
1035     return RepeatTemplatedMemReg<Addr, Reg>(
1036         f,
1037         a,
1038         GetRegisters(),
1039         &AssemblerTest::GetAddrName,
1040         &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>,
1041         fmt);
1042   }
1043 
1044   // Repeats over addresses and quaternary registers provided by fixture.
RepeatAb(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1045   std::string RepeatAb(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
1046     return RepeatAb(f, GetAddresses(), fmt);
1047   }
1048 
1049   // Variant that takes explicit vector of addresss
1050   // (to test restricted addressing modes set).
RepeatAb(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1051   std::string RepeatAb(void (Ass::*f)(const Addr&, Reg),
1052                        const std::vector<Addr>& a,
1053                        const std::string& fmt) {
1054     return RepeatTemplatedMemReg<Addr, Reg>(
1055         f,
1056         a,
1057         GetRegisters(),
1058         &AssemblerTest::GetAddrName,
1059         &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
1060         fmt);
1061   }
1062 
1063   // Repeats over addresses and fp-registers provided by fixture.
RepeatAF(void (Ass::* f)(const Addr &,FPReg),const std::string & fmt)1064   std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg), const std::string& fmt) {
1065     return RepeatAF(f, GetAddresses(), fmt);
1066   }
1067 
1068   // Variant that takes explicit vector of addresss
1069   // (to test restricted addressing modes set).
RepeatAF(void (Ass::* f)(const Addr &,FPReg),const std::vector<Addr> & a,const std::string & fmt)1070   std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg),
1071                        const std::vector<Addr>& a,
1072                        const std::string& fmt) {
1073     return RepeatTemplatedMemReg<Addr, FPReg>(
1074         f,
1075         a,
1076         GetFPRegisters(),
1077         &AssemblerTest::GetAddrName,
1078         &AssemblerTest::GetFPRegName,
1079         fmt);
1080   }
1081 
1082   template <typename AddrType>
RepeatTemplatedMem(void (Ass::* f)(const AddrType &),const std::vector<AddrType> addresses,std::string (AssemblerTest::* GetAName)(const AddrType &),const std::string & fmt)1083   std::string RepeatTemplatedMem(void (Ass::*f)(const AddrType&),
1084                                  const std::vector<AddrType> addresses,
1085                                  std::string (AssemblerTest::*GetAName)(const AddrType&),
1086                                  const std::string& fmt) {
1087     WarnOnCombinations(addresses.size());
1088     std::string str;
1089     for (auto addr : addresses) {
1090       if (f != nullptr) {
1091         (assembler_.get()->*f)(addr);
1092       }
1093       std::string base = fmt;
1094 
1095       std::string addr_string = (this->*GetAName)(addr);
1096       size_t addr_index;
1097       if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1098         base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1099       }
1100 
1101       if (str.size() > 0) {
1102         str += "\n";
1103       }
1104       str += base;
1105     }
1106     // Add a newline at the end.
1107     str += "\n";
1108     return str;
1109   }
1110 
1111   template <typename AddrType>
RepeatTemplatedMemImm(void (Ass::* f)(const AddrType &,const Imm &),size_t imm_bytes,const std::vector<AddrType> addresses,std::string (AssemblerTest::* GetAName)(const AddrType &),const std::string & fmt)1112   std::string RepeatTemplatedMemImm(void (Ass::*f)(const AddrType&, const Imm&),
1113                                     size_t imm_bytes,
1114                                     const std::vector<AddrType> addresses,
1115                                     std::string (AssemblerTest::*GetAName)(const AddrType&),
1116                                     const std::string& fmt) {
1117     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1118     WarnOnCombinations(addresses.size() * imms.size());
1119     std::string str;
1120     for (auto addr : addresses) {
1121       for (int64_t imm : imms) {
1122         Imm new_imm = CreateImmediate(imm);
1123         if (f != nullptr) {
1124           (assembler_.get()->*f)(addr, new_imm);
1125         }
1126         std::string base = fmt;
1127 
1128         std::string addr_string = (this->*GetAName)(addr);
1129         size_t addr_index;
1130         if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1131           base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1132         }
1133 
1134         size_t imm_index = base.find(IMM_TOKEN);
1135         if (imm_index != std::string::npos) {
1136           std::ostringstream sreg;
1137           sreg << imm;
1138           std::string imm_string = sreg.str();
1139           base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1140         }
1141 
1142         if (str.size() > 0) {
1143           str += "\n";
1144         }
1145         str += base;
1146       }
1147     }
1148     // Add a newline at the end.
1149     str += "\n";
1150     return str;
1151   }
1152 
1153   template <typename RegType, typename AddrType>
RepeatTemplatedRegMem(void (Ass::* f)(RegType,const AddrType &),const std::vector<RegType * > registers,const std::vector<AddrType> addresses,std::string (AssemblerTest::* GetRName)(const RegType &),std::string (AssemblerTest::* GetAName)(const AddrType &),const std::string & fmt)1154   std::string RepeatTemplatedRegMem(void (Ass::*f)(RegType, const AddrType&),
1155                                     const std::vector<RegType*> registers,
1156                                     const std::vector<AddrType> addresses,
1157                                     std::string (AssemblerTest::*GetRName)(const RegType&),
1158                                     std::string (AssemblerTest::*GetAName)(const AddrType&),
1159                                     const std::string& fmt) {
1160     WarnOnCombinations(addresses.size() * registers.size());
1161     std::string str;
1162     for (auto reg : registers) {
1163       for (auto addr : addresses) {
1164         if (f != nullptr) {
1165           (assembler_.get()->*f)(*reg, addr);
1166         }
1167         std::string base = fmt;
1168 
1169         std::string reg_string = (this->*GetRName)(*reg);
1170         size_t reg_index;
1171         if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1172           base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1173         }
1174 
1175         std::string addr_string = (this->*GetAName)(addr);
1176         size_t addr_index;
1177         if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1178           base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1179         }
1180 
1181         if (str.size() > 0) {
1182           str += "\n";
1183         }
1184         str += base;
1185       }
1186     }
1187     // Add a newline at the end.
1188     str += "\n";
1189     return str;
1190   }
1191 
1192   template <typename AddrType, typename RegType>
RepeatTemplatedMemReg(void (Ass::* f)(const AddrType &,RegType),const std::vector<AddrType> addresses,const std::vector<RegType * > registers,std::string (AssemblerTest::* GetAName)(const AddrType &),std::string (AssemblerTest::* GetRName)(const RegType &),const std::string & fmt)1193   std::string RepeatTemplatedMemReg(void (Ass::*f)(const AddrType&, RegType),
1194                                     const std::vector<AddrType> addresses,
1195                                     const std::vector<RegType*> registers,
1196                                     std::string (AssemblerTest::*GetAName)(const AddrType&),
1197                                     std::string (AssemblerTest::*GetRName)(const RegType&),
1198                                     const std::string& fmt) {
1199     WarnOnCombinations(addresses.size() * registers.size());
1200     std::string str;
1201     for (auto addr : addresses) {
1202       for (auto reg : registers) {
1203         if (f != nullptr) {
1204           (assembler_.get()->*f)(addr, *reg);
1205         }
1206         std::string base = fmt;
1207 
1208         std::string addr_string = (this->*GetAName)(addr);
1209         size_t addr_index;
1210         if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
1211           base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
1212         }
1213 
1214         std::string reg_string = (this->*GetRName)(*reg);
1215         size_t reg_index;
1216         if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1217           base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1218         }
1219 
1220         if (str.size() > 0) {
1221           str += "\n";
1222         }
1223         str += base;
1224       }
1225     }
1226     // Add a newline at the end.
1227     str += "\n";
1228     return str;
1229   }
1230 
1231   //
1232   // Register repeats.
1233   //
1234 
1235   template <typename RegType>
RepeatTemplatedRegister(void (Ass::* f)(RegType),const std::vector<RegType * > registers,std::string (AssemblerTest::* GetName)(const RegType &),const std::string & fmt)1236   std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
1237                                       const std::vector<RegType*> registers,
1238                                       std::string (AssemblerTest::*GetName)(const RegType&),
1239                                       const std::string& fmt) {
1240     std::string str;
1241     for (auto reg : registers) {
1242       if (f != nullptr) {
1243         (assembler_.get()->*f)(*reg);
1244       }
1245       std::string base = fmt;
1246 
1247       std::string reg_string = (this->*GetName)(*reg);
1248       size_t reg_index;
1249       if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1250         base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1251       }
1252 
1253       if (str.size() > 0) {
1254         str += "\n";
1255       }
1256       str += base;
1257     }
1258     // Add a newline at the end.
1259     str += "\n";
1260     return str;
1261   }
1262 
1263   template <typename Reg1, typename Reg2>
RepeatTemplatedRegisters(void (Ass::* f)(Reg1,Reg2),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),const std::string & fmt)1264   std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
1265                                        const std::vector<Reg1*> reg1_registers,
1266                                        const std::vector<Reg2*> reg2_registers,
1267                                        std::string (AssemblerTest::*GetName1)(const Reg1&),
1268                                        std::string (AssemblerTest::*GetName2)(const Reg2&),
1269                                        const std::string& fmt) {
1270     WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
1271 
1272     std::string str;
1273     for (auto reg1 : reg1_registers) {
1274       for (auto reg2 : reg2_registers) {
1275         if (f != nullptr) {
1276           (assembler_.get()->*f)(*reg1, *reg2);
1277         }
1278         std::string base = fmt;
1279 
1280         std::string reg1_string = (this->*GetName1)(*reg1);
1281         size_t reg1_index;
1282         while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1283           base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1284         }
1285 
1286         std::string reg2_string = (this->*GetName2)(*reg2);
1287         size_t reg2_index;
1288         while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1289           base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1290         }
1291 
1292         if (str.size() > 0) {
1293           str += "\n";
1294         }
1295         str += base;
1296       }
1297     }
1298     // Add a newline at the end.
1299     str += "\n";
1300     return str;
1301   }
1302 
1303   template <typename Reg1, typename Reg2>
RepeatTemplatedRegistersNoDupes(void (Ass::* f)(Reg1,Reg2),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),const std::string & fmt)1304   std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
1305                                               const std::vector<Reg1*> reg1_registers,
1306                                               const std::vector<Reg2*> reg2_registers,
1307                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
1308                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
1309                                               const std::string& fmt) {
1310     WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
1311 
1312     std::string str;
1313     for (auto reg1 : reg1_registers) {
1314       for (auto reg2 : reg2_registers) {
1315         if (reg1 == reg2) continue;
1316         if (f != nullptr) {
1317           (assembler_.get()->*f)(*reg1, *reg2);
1318         }
1319         std::string base = fmt;
1320 
1321         std::string reg1_string = (this->*GetName1)(*reg1);
1322         size_t reg1_index;
1323         while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1324           base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1325         }
1326 
1327         std::string reg2_string = (this->*GetName2)(*reg2);
1328         size_t reg2_index;
1329         while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1330           base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1331         }
1332 
1333         if (str.size() > 0) {
1334           str += "\n";
1335         }
1336         str += base;
1337       }
1338     }
1339     // Add a newline at the end.
1340     str += "\n";
1341     return str;
1342   }
1343 
1344   template <typename Reg1, typename Reg2, typename Reg3>
RepeatTemplatedRegisters(void (Ass::* f)(Reg1,Reg2,Reg3),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,const std::vector<Reg3 * > reg3_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),std::string (AssemblerTest::* GetName3)(const Reg3 &),const std::string & fmt)1345   std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
1346                                        const std::vector<Reg1*> reg1_registers,
1347                                        const std::vector<Reg2*> reg2_registers,
1348                                        const std::vector<Reg3*> reg3_registers,
1349                                        std::string (AssemblerTest::*GetName1)(const Reg1&),
1350                                        std::string (AssemblerTest::*GetName2)(const Reg2&),
1351                                        std::string (AssemblerTest::*GetName3)(const Reg3&),
1352                                        const std::string& fmt) {
1353     std::string str;
1354     for (auto reg1 : reg1_registers) {
1355       for (auto reg2 : reg2_registers) {
1356         for (auto reg3 : reg3_registers) {
1357           if (f != nullptr) {
1358             (assembler_.get()->*f)(*reg1, *reg2, *reg3);
1359           }
1360           std::string base = fmt;
1361 
1362           std::string reg1_string = (this->*GetName1)(*reg1);
1363           size_t reg1_index;
1364           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1365             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1366           }
1367 
1368           std::string reg2_string = (this->*GetName2)(*reg2);
1369           size_t reg2_index;
1370           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1371             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1372           }
1373 
1374           std::string reg3_string = (this->*GetName3)(*reg3);
1375           size_t reg3_index;
1376           while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
1377             base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
1378           }
1379 
1380           if (str.size() > 0) {
1381             str += "\n";
1382           }
1383           str += base;
1384         }
1385       }
1386     }
1387     // Add a newline at the end.
1388     str += "\n";
1389     return str;
1390   }
1391 
1392   template <typename Reg1, typename Reg2>
RepeatTemplatedRegistersImm(void (Ass::* f)(Reg1,Reg2,const Imm &),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),size_t imm_bytes,const std::string & fmt)1393   std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
1394                                           const std::vector<Reg1*> reg1_registers,
1395                                           const std::vector<Reg2*> reg2_registers,
1396                                           std::string (AssemblerTest::*GetName1)(const Reg1&),
1397                                           std::string (AssemblerTest::*GetName2)(const Reg2&),
1398                                           size_t imm_bytes,
1399                                           const std::string& fmt) {
1400     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1401     WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
1402 
1403     std::string str;
1404     for (auto reg1 : reg1_registers) {
1405       for (auto reg2 : reg2_registers) {
1406         for (int64_t imm : imms) {
1407           Imm new_imm = CreateImmediate(imm);
1408           if (f != nullptr) {
1409             (assembler_.get()->*f)(*reg1, *reg2, new_imm);
1410           }
1411           std::string base = fmt;
1412 
1413           std::string reg1_string = (this->*GetName1)(*reg1);
1414           size_t reg1_index;
1415           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1416             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1417           }
1418 
1419           std::string reg2_string = (this->*GetName2)(*reg2);
1420           size_t reg2_index;
1421           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1422             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1423           }
1424 
1425           size_t imm_index = base.find(IMM_TOKEN);
1426           if (imm_index != std::string::npos) {
1427             std::ostringstream sreg;
1428             sreg << imm;
1429             std::string imm_string = sreg.str();
1430             base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1431           }
1432 
1433           if (str.size() > 0) {
1434             str += "\n";
1435           }
1436           str += base;
1437         }
1438       }
1439     }
1440     // Add a newline at the end.
1441     str += "\n";
1442     return str;
1443   }
1444 
GetAddrName(const Addr & addr)1445   std::string GetAddrName(const Addr& addr) {
1446     std::ostringstream saddr;
1447     saddr << addr;
1448     return saddr.str();
1449   }
1450 
1451   template <RegisterView kRegView>
GetRegName(const Reg & reg)1452   std::string GetRegName(const Reg& reg) {
1453     std::ostringstream sreg;
1454     switch (kRegView) {
1455       case RegisterView::kUsePrimaryName:
1456         sreg << reg;
1457         break;
1458 
1459       case RegisterView::kUseSecondaryName:
1460         sreg << GetSecondaryRegisterName(reg);
1461         break;
1462 
1463       case RegisterView::kUseTertiaryName:
1464         sreg << GetTertiaryRegisterName(reg);
1465         break;
1466 
1467       case RegisterView::kUseQuaternaryName:
1468         sreg << GetQuaternaryRegisterName(reg);
1469         break;
1470     }
1471     return sreg.str();
1472   }
1473 
GetFPRegName(const FPReg & reg)1474   std::string GetFPRegName(const FPReg& reg) {
1475     std::ostringstream sreg;
1476     sreg << reg;
1477     return sreg.str();
1478   }
1479 
GetVecRegName(const VecReg & reg)1480   std::string GetVecRegName(const VecReg& reg) {
1481     std::ostringstream sreg;
1482     sreg << reg;
1483     return sreg.str();
1484   }
1485 
WarnOnCombinations(size_t count)1486   void WarnOnCombinations(size_t count) {
1487     if (count > kWarnManyCombinationsThreshold) {
1488       GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1489     }
1490   }
1491 
1492   static constexpr const char* ADDRESS_TOKEN = "{mem}";
1493   static constexpr const char* REG_TOKEN = "{reg}";
1494   static constexpr const char* REG1_TOKEN = "{reg1}";
1495   static constexpr const char* REG2_TOKEN = "{reg2}";
1496   static constexpr const char* REG3_TOKEN = "{reg3}";
1497   static constexpr const char* IMM_TOKEN = "{imm}";
1498 
1499  private:
1500   template <RegisterView kRegView>
RepeatRegisterImm(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)1501   std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1502                                 size_t imm_bytes,
1503                                 const std::string& fmt) {
1504     const std::vector<Reg*> registers = GetRegisters();
1505     std::string str;
1506     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1507 
1508     WarnOnCombinations(registers.size() * imms.size());
1509 
1510     for (auto reg : registers) {
1511       for (int64_t imm : imms) {
1512         Imm new_imm = CreateImmediate(imm);
1513         if (f != nullptr) {
1514           (assembler_.get()->*f)(*reg, new_imm);
1515         }
1516         std::string base = fmt;
1517 
1518         std::string reg_string = GetRegName<kRegView>(*reg);
1519         size_t reg_index;
1520         while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1521           base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1522         }
1523 
1524         size_t imm_index = base.find(IMM_TOKEN);
1525         if (imm_index != std::string::npos) {
1526           std::ostringstream sreg;
1527           sreg << imm;
1528           std::string imm_string = sreg.str();
1529           base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1530         }
1531 
1532         if (str.size() > 0) {
1533           str += "\n";
1534         }
1535         str += base;
1536       }
1537     }
1538     // Add a newline at the end.
1539     str += "\n";
1540     return str;
1541   }
1542 
1543   // Override this to pad the code with NOPs to a certain size if needed.
Pad(std::vector<uint8_t> & data ATTRIBUTE_UNUSED)1544   virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1545   }
1546 
DriverWrapper(const std::string & assembly_text,const std::string & test_name)1547   void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
1548     assembler_->FinalizeCode();
1549     size_t cs = assembler_->CodeSize();
1550     std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
1551     MemoryRegion code(&(*data)[0], data->size());
1552     assembler_->FinalizeInstructions(code);
1553     Pad(*data);
1554     Driver(*data, assembly_text, test_name);
1555   }
1556 
1557   static constexpr size_t kWarnManyCombinationsThreshold = 500;
1558 
1559   MallocArenaPool pool_;
1560   std::unique_ptr<ArenaAllocator> allocator_;
1561   std::unique_ptr<Ass> assembler_;
1562 
1563   DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
1564 };
1565 
1566 }  // namespace art
1567 
1568 #endif  // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
1569