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 "assembler_test_base.h"
23 #include "common_runtime_test.h"  // For ScratchFile
24 
25 #include <cstdio>
26 #include <cstdlib>
27 #include <fstream>
28 #include <iterator>
29 #include <sys/stat.h>
30 
31 namespace art {
32 
33 // Helper for a constexpr string length.
34 constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
35   return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
36 }
37 
38 enum class RegisterView {  // private
39   kUsePrimaryName,
40   kUseSecondaryName,
41   kUseTertiaryName,
42   kUseQuaternaryName,
43 };
44 
45 // For use in the template as the default type to get a nonvector registers version.
46 struct NoVectorRegs {};
47 
48 template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs>
49 class AssemblerTest : public testing::Test {
50  public:
GetAssembler()51   Ass* GetAssembler() {
52     return assembler_.get();
53   }
54 
55   typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
56 
DriverFn(TestFn f,const std::string & test_name)57   void DriverFn(TestFn f, const std::string& test_name) {
58     DriverWrapper(f(this, assembler_.get()), test_name);
59   }
60 
61   // This driver assumes the assembler has already been called.
DriverStr(const std::string & assembly_string,const std::string & test_name)62   void DriverStr(const std::string& assembly_string, const std::string& test_name) {
63     DriverWrapper(assembly_string, test_name);
64   }
65 
RepeatR(void (Ass::* f)(Reg),const std::string & fmt)66   std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
67     return RepeatTemplatedRegister<Reg>(f,
68         GetRegisters(),
69         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
70         fmt);
71   }
72 
Repeatr(void (Ass::* f)(Reg),const std::string & fmt)73   std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) {
74     return RepeatTemplatedRegister<Reg>(f,
75         GetRegisters(),
76         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
77         fmt);
78   }
79 
RepeatRR(void (Ass::* f)(Reg,Reg),const std::string & fmt)80   std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
81     return RepeatTemplatedRegisters<Reg, Reg>(f,
82         GetRegisters(),
83         GetRegisters(),
84         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
85         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
86         fmt);
87   }
88 
RepeatRRNoDupes(void (Ass::* f)(Reg,Reg),const std::string & fmt)89   std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
90     return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f,
91         GetRegisters(),
92         GetRegisters(),
93         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
94         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
95         fmt);
96   }
97 
Repeatrr(void (Ass::* f)(Reg,Reg),const std::string & fmt)98   std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
99     return RepeatTemplatedRegisters<Reg, Reg>(f,
100         GetRegisters(),
101         GetRegisters(),
102         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
103         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
104         fmt);
105   }
106 
RepeatRRR(void (Ass::* f)(Reg,Reg,Reg),const std::string & fmt)107   std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) {
108     return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
109         GetRegisters(),
110         GetRegisters(),
111         GetRegisters(),
112         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
113         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
114         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
115         fmt);
116   }
117 
Repeatrb(void (Ass::* f)(Reg,Reg),const std::string & fmt)118   std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
119     return RepeatTemplatedRegisters<Reg, Reg>(f,
120         GetRegisters(),
121         GetRegisters(),
122         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
123         &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>,
124         fmt);
125   }
126 
RepeatRr(void (Ass::* f)(Reg,Reg),const std::string & fmt)127   std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) {
128     return RepeatTemplatedRegisters<Reg, Reg>(f,
129         GetRegisters(),
130         GetRegisters(),
131         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
132         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
133         fmt);
134   }
135 
RepeatRI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)136   std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
137     return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
138   }
139 
Repeatri(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)140   std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) {
141     return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
142   }
143 
144   template <typename Reg1, typename Reg2, typename ImmType>
145   std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType),
146                                               int imm_bits,
147                                               const std::vector<Reg1*> reg1_registers,
148                                               const std::vector<Reg2*> reg2_registers,
149                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
150                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
151                                               const std::string& fmt,
152                                               int bias = 0,
153                                               int multiplier = 1) {
154     std::string str;
155     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
156 
157     for (auto reg1 : reg1_registers) {
158       for (auto reg2 : reg2_registers) {
159         for (int64_t imm : imms) {
160           ImmType new_imm = CreateImmediate(imm);
161           (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
162           std::string base = fmt;
163 
164           std::string reg1_string = (this->*GetName1)(*reg1);
165           size_t reg1_index;
166           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
167             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
168           }
169 
170           std::string reg2_string = (this->*GetName2)(*reg2);
171           size_t reg2_index;
172           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
173             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
174           }
175 
176           size_t imm_index = base.find(IMM_TOKEN);
177           if (imm_index != std::string::npos) {
178             std::ostringstream sreg;
179             sreg << imm * multiplier + bias;
180             std::string imm_string = sreg.str();
181             base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
182           }
183 
184           if (str.size() > 0) {
185             str += "\n";
186           }
187           str += base;
188         }
189       }
190     }
191     // Add a newline at the end.
192     str += "\n";
193     return str;
194   }
195 
196   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)197   std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType),
198                                               int imm_bits,
199                                               const std::vector<Reg1*> reg1_registers,
200                                               const std::vector<Reg2*> reg2_registers,
201                                               const std::vector<Reg3*> reg3_registers,
202                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
203                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
204                                               std::string (AssemblerTest::*GetName3)(const Reg3&),
205                                               std::string fmt,
206                                               int bias) {
207     std::string str;
208     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
209 
210     for (auto reg1 : reg1_registers) {
211       for (auto reg2 : reg2_registers) {
212         for (auto reg3 : reg3_registers) {
213           for (int64_t imm : imms) {
214             ImmType new_imm = CreateImmediate(imm);
215             (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias);
216             std::string base = fmt;
217 
218             std::string reg1_string = (this->*GetName1)(*reg1);
219             size_t reg1_index;
220             while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
221               base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
222             }
223 
224             std::string reg2_string = (this->*GetName2)(*reg2);
225             size_t reg2_index;
226             while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
227               base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
228             }
229 
230             std::string reg3_string = (this->*GetName3)(*reg3);
231             size_t reg3_index;
232             while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
233               base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
234             }
235 
236             size_t imm_index = base.find(IMM_TOKEN);
237             if (imm_index != std::string::npos) {
238               std::ostringstream sreg;
239               sreg << imm + bias;
240               std::string imm_string = sreg.str();
241               base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
242             }
243 
244             if (str.size() > 0) {
245               str += "\n";
246             }
247             str += base;
248           }
249         }
250       }
251     }
252     // Add a newline at the end.
253     str += "\n";
254     return str;
255   }
256 
257   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)258   std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2),
259                                               const std::vector<Reg1*> reg1_registers,
260                                               const std::vector<Reg2*> reg2_registers,
261                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
262                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
263                                               int imm_bits,
264                                               const std::string& fmt) {
265     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
266 
267     WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
268 
269     std::string str;
270     for (auto reg1 : reg1_registers) {
271       for (auto reg2 : reg2_registers) {
272         for (int64_t imm : imms) {
273           ImmType new_imm = CreateImmediate(imm);
274           (assembler_.get()->*f)(new_imm, *reg1, *reg2);
275           std::string base = fmt;
276 
277           std::string reg1_string = (this->*GetName1)(*reg1);
278           size_t reg1_index;
279           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
280             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
281           }
282 
283           std::string reg2_string = (this->*GetName2)(*reg2);
284           size_t reg2_index;
285           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
286             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
287           }
288 
289           size_t imm_index = base.find(IMM_TOKEN);
290           if (imm_index != std::string::npos) {
291             std::ostringstream sreg;
292             sreg << imm;
293             std::string imm_string = sreg.str();
294             base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
295           }
296 
297           if (str.size() > 0) {
298             str += "\n";
299           }
300           str += base;
301         }
302       }
303     }
304     // Add a newline at the end.
305     str += "\n";
306     return str;
307   }
308 
309   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)310   std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
311                                              int imm_bits,
312                                              const std::vector<RegType*> registers,
313                                              std::string (AssemblerTest::*GetName)(const RegType&),
314                                              const std::string& fmt,
315                                              int bias) {
316     std::string str;
317     std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
318 
319     for (auto reg : registers) {
320       for (int64_t imm : imms) {
321         ImmType new_imm = CreateImmediate(imm);
322         (assembler_.get()->*f)(*reg, new_imm + bias);
323         std::string base = fmt;
324 
325         std::string reg_string = (this->*GetName)(*reg);
326         size_t reg_index;
327         while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
328           base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
329         }
330 
331         size_t imm_index = base.find(IMM_TOKEN);
332         if (imm_index != std::string::npos) {
333           std::ostringstream sreg;
334           sreg << imm + bias;
335           std::string imm_string = sreg.str();
336           base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
337         }
338 
339         if (str.size() > 0) {
340           str += "\n";
341         }
342         str += base;
343       }
344     }
345     // Add a newline at the end.
346     str += "\n";
347     return str;
348   }
349 
350   template <typename ImmType>
351   std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
352                          int imm_bits,
353                          const std::string& fmt,
354                          int bias = 0) {
355     return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f,
356         imm_bits,
357         GetRegisters(),
358         GetRegisters(),
359         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
360         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
361         fmt,
362         bias);
363   }
364 
365   template <typename ImmType>
366   std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType),
367                           int imm_bits,
368                           const std::string& fmt,
369                           int bias = 0) {
370     return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f,
371         imm_bits,
372         GetRegisters(),
373         GetRegisters(),
374         GetRegisters(),
375         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
376         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
377         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
378         fmt,
379         bias);
380   }
381 
382   template <typename ImmType>
383   std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) {
384     return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f,
385         imm_bits,
386         GetRegisters(),
387         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
388         fmt,
389         bias);
390   }
391 
392   template <typename ImmType>
393   std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType),
394                          int imm_bits,
395                          const std::string& fmt,
396                          int bias = 0) {
397     return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f,
398         imm_bits,
399         GetFPRegisters(),
400         GetRegisters(),
401         &AssemblerTest::GetFPRegName,
402         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
403         fmt,
404         bias);
405   }
406 
RepeatFF(void (Ass::* f)(FPReg,FPReg),const std::string & fmt)407   std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) {
408     return RepeatTemplatedRegisters<FPReg, FPReg>(f,
409                                                   GetFPRegisters(),
410                                                   GetFPRegisters(),
411                                                   &AssemblerTest::GetFPRegName,
412                                                   &AssemblerTest::GetFPRegName,
413                                                   fmt);
414   }
415 
RepeatFFF(void (Ass::* f)(FPReg,FPReg,FPReg),const std::string & fmt)416   std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) {
417     return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
418                                                          GetFPRegisters(),
419                                                          GetFPRegisters(),
420                                                          GetFPRegisters(),
421                                                          &AssemblerTest::GetFPRegName,
422                                                          &AssemblerTest::GetFPRegName,
423                                                          &AssemblerTest::GetFPRegName,
424                                                          fmt);
425   }
426 
RepeatFFR(void (Ass::* f)(FPReg,FPReg,Reg),const std::string & fmt)427   std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
428     return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
429         f,
430         GetFPRegisters(),
431         GetFPRegisters(),
432         GetRegisters(),
433         &AssemblerTest::GetFPRegName,
434         &AssemblerTest::GetFPRegName,
435         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
436         fmt);
437   }
438 
RepeatFFI(void (Ass::* f)(FPReg,FPReg,const Imm &),size_t imm_bytes,const std::string & fmt)439   std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
440                         size_t imm_bytes,
441                         const std::string& fmt) {
442     return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
443                                                      GetFPRegisters(),
444                                                      GetFPRegisters(),
445                                                      &AssemblerTest::GetFPRegName,
446                                                      &AssemblerTest::GetFPRegName,
447                                                      imm_bytes,
448                                                      fmt);
449   }
450 
451   template <typename ImmType>
RepeatFFIb(void (Ass::* f)(FPReg,FPReg,ImmType),int imm_bits,const std::string & fmt)452   std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType),
453                          int imm_bits,
454                          const std::string& fmt) {
455     return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
456                                                                   imm_bits,
457                                                                   GetFPRegisters(),
458                                                                   GetFPRegisters(),
459                                                                   &AssemblerTest::GetFPRegName,
460                                                                   &AssemblerTest::GetFPRegName,
461                                                                   fmt);
462   }
463 
464   template <typename ImmType>
RepeatIbFF(void (Ass::* f)(ImmType,FPReg,FPReg),int imm_bits,const std::string & fmt)465   std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg),
466                          int imm_bits,
467                          const std::string& fmt) {
468     return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
469                                                                   GetFPRegisters(),
470                                                                   GetFPRegisters(),
471                                                                   &AssemblerTest::GetFPRegName,
472                                                                   &AssemblerTest::GetFPRegName,
473                                                                   imm_bits,
474                                                                   fmt);
475   }
476 
RepeatFR(void (Ass::* f)(FPReg,Reg),const std::string & fmt)477   std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
478     return RepeatTemplatedRegisters<FPReg, Reg>(f,
479         GetFPRegisters(),
480         GetRegisters(),
481         &AssemblerTest::GetFPRegName,
482         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
483         fmt);
484   }
485 
RepeatFr(void (Ass::* f)(FPReg,Reg),const std::string & fmt)486   std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
487     return RepeatTemplatedRegisters<FPReg, Reg>(f,
488         GetFPRegisters(),
489         GetRegisters(),
490         &AssemblerTest::GetFPRegName,
491         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
492         fmt);
493   }
494 
RepeatRF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)495   std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
496     return RepeatTemplatedRegisters<Reg, FPReg>(f,
497         GetRegisters(),
498         GetFPRegisters(),
499         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
500         &AssemblerTest::GetFPRegName,
501         fmt);
502   }
503 
RepeatrF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)504   std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) {
505     return RepeatTemplatedRegisters<Reg, FPReg>(f,
506         GetRegisters(),
507         GetFPRegisters(),
508         &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
509         &AssemblerTest::GetFPRegName,
510         fmt);
511   }
512 
513   std::string RepeatI(void (Ass::*f)(const Imm&),
514                       size_t imm_bytes,
515                       const std::string& fmt,
516                       bool as_uint = false) {
517     std::string str;
518     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
519 
520     WarnOnCombinations(imms.size());
521 
522     for (int64_t imm : imms) {
523       Imm new_imm = CreateImmediate(imm);
524       (assembler_.get()->*f)(new_imm);
525       std::string base = fmt;
526 
527       size_t imm_index = base.find(IMM_TOKEN);
528       if (imm_index != std::string::npos) {
529         std::ostringstream sreg;
530         sreg << imm;
531         std::string imm_string = sreg.str();
532         base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
533       }
534 
535       if (str.size() > 0) {
536         str += "\n";
537       }
538       str += base;
539     }
540     // Add a newline at the end.
541     str += "\n";
542     return str;
543   }
544 
RepeatVV(void (Ass::* f)(VecReg,VecReg),const std::string & fmt)545   std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
546     return RepeatTemplatedRegisters<VecReg, VecReg>(f,
547                                                     GetVectorRegisters(),
548                                                     GetVectorRegisters(),
549                                                     &AssemblerTest::GetVecRegName,
550                                                     &AssemblerTest::GetVecRegName,
551                                                     fmt);
552   }
553 
RepeatVVV(void (Ass::* f)(VecReg,VecReg,VecReg),const std::string & fmt)554   std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
555     return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
556                                                             GetVectorRegisters(),
557                                                             GetVectorRegisters(),
558                                                             GetVectorRegisters(),
559                                                             &AssemblerTest::GetVecRegName,
560                                                             &AssemblerTest::GetVecRegName,
561                                                             &AssemblerTest::GetVecRegName,
562                                                             fmt);
563   }
564 
RepeatVR(void (Ass::* f)(VecReg,Reg),const std::string & fmt)565   std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
566     return RepeatTemplatedRegisters<VecReg, Reg>(
567         f,
568         GetVectorRegisters(),
569         GetRegisters(),
570         &AssemblerTest::GetVecRegName,
571         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
572         fmt);
573   }
574 
575   template <typename ImmType>
576   std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
577                         int imm_bits,
578                         std::string fmt,
579                         int bias = 0) {
580     return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
581                                                            imm_bits,
582                                                            GetVectorRegisters(),
583                                                            &AssemblerTest::GetVecRegName,
584                                                            fmt,
585                                                            bias);
586   }
587 
588   template <typename ImmType>
589   std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
590                          int imm_bits,
591                          const std::string& fmt,
592                          int bias = 0,
593                          int multiplier = 1) {
594     return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
595         f,
596         imm_bits,
597         GetVectorRegisters(),
598         GetRegisters(),
599         &AssemblerTest::GetVecRegName,
600         &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
601         fmt,
602         bias,
603         multiplier);
604   }
605 
606   template <typename ImmType>
607   std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
608                          int imm_bits,
609                          const std::string& fmt,
610                          int bias = 0) {
611     return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
612                                                                     imm_bits,
613                                                                     GetVectorRegisters(),
614                                                                     GetVectorRegisters(),
615                                                                     &AssemblerTest::GetVecRegName,
616                                                                     &AssemblerTest::GetVecRegName,
617                                                                     fmt,
618                                                                     bias);
619   }
620 
621   // This is intended to be run as a test.
CheckTools()622   bool CheckTools() {
623     return test_helper_->CheckTools();
624   }
625 
626   // The following functions are public so that TestFn can use them...
627 
628   virtual std::vector<Reg*> GetRegisters() = 0;
629 
GetFPRegisters()630   virtual std::vector<FPReg*> GetFPRegisters() {
631     UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
632     UNREACHABLE();
633   }
634 
GetVectorRegisters()635   virtual std::vector<VecReg*> GetVectorRegisters() {
636     UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
637     UNREACHABLE();
638   }
639 
640   // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
GetSecondaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)641   virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
642     UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
643     UNREACHABLE();
644   }
645 
646   // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems.
GetTertiaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)647   virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
648     UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers";
649     UNREACHABLE();
650   }
651 
652   // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems.
GetQuaternaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)653   virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
654     UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
655     UNREACHABLE();
656   }
657 
GetRegisterName(const Reg & reg)658   std::string GetRegisterName(const Reg& reg) {
659     return GetRegName<RegisterView::kUsePrimaryName>(reg);
660   }
661 
662  protected:
AssemblerTest()663   explicit AssemblerTest() {}
664 
SetUp()665   void SetUp() OVERRIDE {
666     arena_.reset(new ArenaAllocator(&pool_));
667     assembler_.reset(CreateAssembler(arena_.get()));
668     test_helper_.reset(
669         new AssemblerTestInfrastructure(GetArchitectureString(),
670                                         GetAssemblerCmdName(),
671                                         GetAssemblerParameters(),
672                                         GetObjdumpCmdName(),
673                                         GetObjdumpParameters(),
674                                         GetDisassembleCmdName(),
675                                         GetDisassembleParameters(),
676                                         GetAssemblyHeader()));
677 
678     SetUpHelpers();
679   }
680 
TearDown()681   void TearDown() OVERRIDE {
682     test_helper_.reset();  // Clean up the helper.
683     assembler_.reset();
684     arena_.reset();
685   }
686 
687   // Override this to set up any architecture-specific things, e.g., CPU revision.
CreateAssembler(ArenaAllocator * arena)688   virtual Ass* CreateAssembler(ArenaAllocator* arena) {
689     return new (arena) Ass(arena);
690   }
691 
692   // Override this to set up any architecture-specific things, e.g., register vectors.
SetUpHelpers()693   virtual void SetUpHelpers() {}
694 
695   // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
696   virtual std::string GetArchitectureString() = 0;
697 
698   // Get the name of the assembler, e.g., "as" by default.
GetAssemblerCmdName()699   virtual std::string GetAssemblerCmdName() {
700     return "as";
701   }
702 
703   // Switches to the assembler command. Default none.
GetAssemblerParameters()704   virtual std::string GetAssemblerParameters() {
705     return "";
706   }
707 
708   // Get the name of the objdump, e.g., "objdump" by default.
GetObjdumpCmdName()709   virtual std::string GetObjdumpCmdName() {
710     return "objdump";
711   }
712 
713   // Switches to the objdump command. Default is " -h".
GetObjdumpParameters()714   virtual std::string GetObjdumpParameters() {
715     return " -h";
716   }
717 
718   // Get the name of the objdump, e.g., "objdump" by default.
GetDisassembleCmdName()719   virtual std::string GetDisassembleCmdName() {
720     return "objdump";
721   }
722 
723   // Switches to the objdump command. As it's a binary, one needs to push the architecture and
724   // such to objdump, so it's architecture-specific and there is no default.
725   virtual std::string GetDisassembleParameters() = 0;
726 
727   // Create a couple of immediate values up to the number of bytes given.
728   virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
729     std::vector<int64_t> res;
730     res.push_back(0);
731     if (!as_uint) {
732       res.push_back(-1);
733     } else {
734       res.push_back(0xFF);
735     }
736     res.push_back(0x12);
737     if (imm_bytes >= 2) {
738       res.push_back(0x1234);
739       if (!as_uint) {
740         res.push_back(-0x1234);
741       } else {
742         res.push_back(0xFFFF);
743       }
744       if (imm_bytes >= 4) {
745         res.push_back(0x12345678);
746         if (!as_uint) {
747           res.push_back(-0x12345678);
748         } else {
749           res.push_back(0xFFFFFFFF);
750         }
751         if (imm_bytes >= 6) {
752           res.push_back(0x123456789ABC);
753           if (!as_uint) {
754             res.push_back(-0x123456789ABC);
755           }
756           if (imm_bytes >= 8) {
757             res.push_back(0x123456789ABCDEF0);
758             if (!as_uint) {
759               res.push_back(-0x123456789ABCDEF0);
760             } else {
761               res.push_back(0xFFFFFFFFFFFFFFFF);
762             }
763           }
764         }
765       }
766     }
767     return res;
768   }
769 
770   const int kMaxBitsExhaustiveTest = 8;
771 
772   // Create a couple of immediate values up to the number of bits given.
773   virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
774     CHECK_GT(imm_bits, 0);
775     CHECK_LE(imm_bits, 64);
776     std::vector<int64_t> res;
777 
778     if (imm_bits <= kMaxBitsExhaustiveTest) {
779       if (as_uint) {
780         for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
781           res.push_back(static_cast<int64_t>(i));
782         }
783       } else {
784         for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
785           res.push_back(i);
786         }
787       }
788     } else {
789       if (as_uint) {
790         for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
791              i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
792              i++) {
793           res.push_back(static_cast<int64_t>(i));
794         }
795         for (int i = 0; i <= imm_bits; i++) {
796           uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
797                        ((MaxInt<uint64_t>(imm_bits) -
798                         (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
799                         * i / imm_bits);
800           res.push_back(static_cast<int64_t>(j));
801         }
802       } else {
803         for (int i = 0; i <= imm_bits; i++) {
804           int64_t j = MinInt<int64_t>(imm_bits) +
805                       ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
806                          MinInt<int64_t>(imm_bits))
807                         * i) / imm_bits);
808           res.push_back(static_cast<int64_t>(j));
809         }
810         for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
811              i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
812              i++) {
813           res.push_back(static_cast<int64_t>(i));
814         }
815         for (int i = 0; i <= imm_bits; i++) {
816           int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
817                       ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
818                        * i / imm_bits);
819           res.push_back(static_cast<int64_t>(j));
820         }
821       }
822     }
823 
824     return res;
825   }
826 
827   // Create an immediate from the specific value.
828   virtual Imm CreateImmediate(int64_t imm_value) = 0;
829 
830   template <typename RegType>
RepeatTemplatedRegister(void (Ass::* f)(RegType),const std::vector<RegType * > registers,std::string (AssemblerTest::* GetName)(const RegType &),const std::string & fmt)831   std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
832                                       const std::vector<RegType*> registers,
833                                       std::string (AssemblerTest::*GetName)(const RegType&),
834                                       const std::string& fmt) {
835     std::string str;
836     for (auto reg : registers) {
837       (assembler_.get()->*f)(*reg);
838       std::string base = fmt;
839 
840       std::string reg_string = (this->*GetName)(*reg);
841       size_t reg_index;
842       if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
843         base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
844       }
845 
846       if (str.size() > 0) {
847         str += "\n";
848       }
849       str += base;
850     }
851     // Add a newline at the end.
852     str += "\n";
853     return str;
854   }
855 
856   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)857   std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
858                                        const std::vector<Reg1*> reg1_registers,
859                                        const std::vector<Reg2*> reg2_registers,
860                                        std::string (AssemblerTest::*GetName1)(const Reg1&),
861                                        std::string (AssemblerTest::*GetName2)(const Reg2&),
862                                        const std::string& fmt) {
863     WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
864 
865     std::string str;
866     for (auto reg1 : reg1_registers) {
867       for (auto reg2 : reg2_registers) {
868         (assembler_.get()->*f)(*reg1, *reg2);
869         std::string base = fmt;
870 
871         std::string reg1_string = (this->*GetName1)(*reg1);
872         size_t reg1_index;
873         while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
874           base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
875         }
876 
877         std::string reg2_string = (this->*GetName2)(*reg2);
878         size_t reg2_index;
879         while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
880           base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
881         }
882 
883         if (str.size() > 0) {
884           str += "\n";
885         }
886         str += base;
887       }
888     }
889     // Add a newline at the end.
890     str += "\n";
891     return str;
892   }
893 
894   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)895   std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2),
896                                               const std::vector<Reg1*> reg1_registers,
897                                               const std::vector<Reg2*> reg2_registers,
898                                               std::string (AssemblerTest::*GetName1)(const Reg1&),
899                                               std::string (AssemblerTest::*GetName2)(const Reg2&),
900                                               const std::string& fmt) {
901     WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
902 
903     std::string str;
904     for (auto reg1 : reg1_registers) {
905       for (auto reg2 : reg2_registers) {
906         if (reg1 == reg2) continue;
907         (assembler_.get()->*f)(*reg1, *reg2);
908         std::string base = fmt;
909 
910         std::string reg1_string = (this->*GetName1)(*reg1);
911         size_t reg1_index;
912         while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
913           base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
914         }
915 
916         std::string reg2_string = (this->*GetName2)(*reg2);
917         size_t reg2_index;
918         while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
919           base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
920         }
921 
922         if (str.size() > 0) {
923           str += "\n";
924         }
925         str += base;
926       }
927     }
928     // Add a newline at the end.
929     str += "\n";
930     return str;
931   }
932 
933   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)934   std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
935                                        const std::vector<Reg1*> reg1_registers,
936                                        const std::vector<Reg2*> reg2_registers,
937                                        const std::vector<Reg3*> reg3_registers,
938                                        std::string (AssemblerTest::*GetName1)(const Reg1&),
939                                        std::string (AssemblerTest::*GetName2)(const Reg2&),
940                                        std::string (AssemblerTest::*GetName3)(const Reg3&),
941                                        const std::string& fmt) {
942     std::string str;
943     for (auto reg1 : reg1_registers) {
944       for (auto reg2 : reg2_registers) {
945         for (auto reg3 : reg3_registers) {
946           (assembler_.get()->*f)(*reg1, *reg2, *reg3);
947           std::string base = fmt;
948 
949           std::string reg1_string = (this->*GetName1)(*reg1);
950           size_t reg1_index;
951           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
952             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
953           }
954 
955           std::string reg2_string = (this->*GetName2)(*reg2);
956           size_t reg2_index;
957           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
958             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
959           }
960 
961           std::string reg3_string = (this->*GetName3)(*reg3);
962           size_t reg3_index;
963           while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
964             base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
965           }
966 
967           if (str.size() > 0) {
968             str += "\n";
969           }
970           str += base;
971         }
972       }
973     }
974     // Add a newline at the end.
975     str += "\n";
976     return str;
977   }
978 
979   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)980   std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
981                                           const std::vector<Reg1*> reg1_registers,
982                                           const std::vector<Reg2*> reg2_registers,
983                                           std::string (AssemblerTest::*GetName1)(const Reg1&),
984                                           std::string (AssemblerTest::*GetName2)(const Reg2&),
985                                           size_t imm_bytes,
986                                           const std::string& fmt) {
987     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
988     WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size());
989 
990     std::string str;
991     for (auto reg1 : reg1_registers) {
992       for (auto reg2 : reg2_registers) {
993         for (int64_t imm : imms) {
994           Imm new_imm = CreateImmediate(imm);
995           (assembler_.get()->*f)(*reg1, *reg2, new_imm);
996           std::string base = fmt;
997 
998           std::string reg1_string = (this->*GetName1)(*reg1);
999           size_t reg1_index;
1000           while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
1001             base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
1002           }
1003 
1004           std::string reg2_string = (this->*GetName2)(*reg2);
1005           size_t reg2_index;
1006           while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
1007             base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
1008           }
1009 
1010           size_t imm_index = base.find(IMM_TOKEN);
1011           if (imm_index != std::string::npos) {
1012             std::ostringstream sreg;
1013             sreg << imm;
1014             std::string imm_string = sreg.str();
1015             base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1016           }
1017 
1018           if (str.size() > 0) {
1019             str += "\n";
1020           }
1021           str += base;
1022         }
1023       }
1024     }
1025     // Add a newline at the end.
1026     str += "\n";
1027     return str;
1028   }
1029 
1030   template <RegisterView kRegView>
GetRegName(const Reg & reg)1031   std::string GetRegName(const Reg& reg) {
1032     std::ostringstream sreg;
1033     switch (kRegView) {
1034       case RegisterView::kUsePrimaryName:
1035         sreg << reg;
1036         break;
1037 
1038       case RegisterView::kUseSecondaryName:
1039         sreg << GetSecondaryRegisterName(reg);
1040         break;
1041 
1042       case RegisterView::kUseTertiaryName:
1043         sreg << GetTertiaryRegisterName(reg);
1044         break;
1045 
1046       case RegisterView::kUseQuaternaryName:
1047         sreg << GetQuaternaryRegisterName(reg);
1048         break;
1049     }
1050     return sreg.str();
1051   }
1052 
GetFPRegName(const FPReg & reg)1053   std::string GetFPRegName(const FPReg& reg) {
1054     std::ostringstream sreg;
1055     sreg << reg;
1056     return sreg.str();
1057   }
1058 
GetVecRegName(const VecReg & reg)1059   std::string GetVecRegName(const VecReg& reg) {
1060     std::ostringstream sreg;
1061     sreg << reg;
1062     return sreg.str();
1063   }
1064 
1065   // If the assembly file needs a header, return it in a sub-class.
GetAssemblyHeader()1066   virtual const char* GetAssemblyHeader() {
1067     return nullptr;
1068   }
1069 
WarnOnCombinations(size_t count)1070   void WarnOnCombinations(size_t count) {
1071     if (count > kWarnManyCombinationsThreshold) {
1072       GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
1073     }
1074   }
1075 
1076   static constexpr const char* REG_TOKEN = "{reg}";
1077   static constexpr const char* REG1_TOKEN = "{reg1}";
1078   static constexpr const char* REG2_TOKEN = "{reg2}";
1079   static constexpr const char* REG3_TOKEN = "{reg3}";
1080   static constexpr const char* IMM_TOKEN = "{imm}";
1081 
1082  private:
1083   template <RegisterView kRegView>
RepeatRegisterImm(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)1084   std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&),
1085                                 size_t imm_bytes,
1086                                 const std::string& fmt) {
1087     const std::vector<Reg*> registers = GetRegisters();
1088     std::string str;
1089     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
1090 
1091     WarnOnCombinations(registers.size() * imms.size());
1092 
1093     for (auto reg : registers) {
1094       for (int64_t imm : imms) {
1095         Imm new_imm = CreateImmediate(imm);
1096         (assembler_.get()->*f)(*reg, new_imm);
1097         std::string base = fmt;
1098 
1099         std::string reg_string = GetRegName<kRegView>(*reg);
1100         size_t reg_index;
1101         while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
1102           base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
1103         }
1104 
1105         size_t imm_index = base.find(IMM_TOKEN);
1106         if (imm_index != std::string::npos) {
1107           std::ostringstream sreg;
1108           sreg << imm;
1109           std::string imm_string = sreg.str();
1110           base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
1111         }
1112 
1113         if (str.size() > 0) {
1114           str += "\n";
1115         }
1116         str += base;
1117       }
1118     }
1119     // Add a newline at the end.
1120     str += "\n";
1121     return str;
1122   }
1123 
1124   // Override this to pad the code with NOPs to a certain size if needed.
Pad(std::vector<uint8_t> & data ATTRIBUTE_UNUSED)1125   virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
1126   }
1127 
DriverWrapper(const std::string & assembly_text,const std::string & test_name)1128   void DriverWrapper(const std::string& assembly_text, const std::string& test_name) {
1129     assembler_->FinalizeCode();
1130     size_t cs = assembler_->CodeSize();
1131     std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
1132     MemoryRegion code(&(*data)[0], data->size());
1133     assembler_->FinalizeInstructions(code);
1134     Pad(*data);
1135     test_helper_->Driver(*data, assembly_text, test_name);
1136   }
1137 
1138   static constexpr size_t kWarnManyCombinationsThreshold = 500;
1139 
1140   ArenaPool pool_;
1141   std::unique_ptr<ArenaAllocator> arena_;
1142   std::unique_ptr<Ass> assembler_;
1143   std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
1144 
1145   DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
1146 };
1147 
1148 }  // namespace art
1149 
1150 #endif  // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_
1151