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