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