Home | History | Annotate | Download | only in utils
      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:
     48   Ass* GetAssembler() {
     49     return assembler_.get();
     50   }
     51 
     52   typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
     53 
     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.
     59   void DriverStr(std::string assembly_string, std::string test_name) {
     60     DriverWrapper(assembly_string, test_name);
     61   }
     62 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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>
    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>
    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>
    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>
    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>
    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>
    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 
    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 
    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 
    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>
    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 
    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 
    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 
    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 
    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.
    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 
    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.
    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.
    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.
    450   virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
    451     UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
    452     UNREACHABLE();
    453   }
    454 
    455   std::string GetRegisterName(const Reg& reg) {
    456     return GetRegName<RegisterView::kUsePrimaryName>(reg);
    457   }
    458 
    459  protected:
    460   explicit AssemblerTest() {}
    461 
    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 
    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.
    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.
    491   virtual std::string GetAssemblerCmdName() {
    492     return "as";
    493   }
    494 
    495   // Switches to the assembler command. Default none.
    496   virtual std::string GetAssemblerParameters() {
    497     return "";
    498   }
    499 
    500   // Get the name of the objdump, e.g., "objdump" by default.
    501   virtual std::string GetObjdumpCmdName() {
    502     return "objdump";
    503   }
    504 
    505   // Switches to the objdump command. Default is " -h".
    506   virtual std::string GetObjdumpParameters() {
    507     return " -h";
    508   }
    509 
    510   // Get the name of the objdump, e.g., "objdump" by default.
    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>
    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>
    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>
    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>
    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>
    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>
    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 
    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.
    852   virtual const char* GetAssemblyHeader() {
    853     return nullptr;
    854   }
    855 
    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>
    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.
    910   virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
    911   }
    912 
    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