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 // 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:
     51   Ass* GetAssembler() {
     52     return assembler_.get();
     53   }
     54 
     55   typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
     56 
     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.
     62   void DriverStr(const std::string& assembly_string, const std::string& test_name) {
     63     DriverWrapper(assembly_string, test_name);
     64   }
     65 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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>
    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>
    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>
    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 
    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 
    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 
    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 
    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>
    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>
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    630   virtual std::vector<FPReg*> GetFPRegisters() {
    631     UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
    632     UNREACHABLE();
    633   }
    634 
    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.
    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.
    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.
    653   virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
    654     UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers";
    655     UNREACHABLE();
    656   }
    657 
    658   std::string GetRegisterName(const Reg& reg) {
    659     return GetRegName<RegisterView::kUsePrimaryName>(reg);
    660   }
    661 
    662  protected:
    663   explicit AssemblerTest() {}
    664 
    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 
    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.
    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.
    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.
    699   virtual std::string GetAssemblerCmdName() {
    700     return "as";
    701   }
    702 
    703   // Switches to the assembler command. Default none.
    704   virtual std::string GetAssemblerParameters() {
    705     return "";
    706   }
    707 
    708   // Get the name of the objdump, e.g., "objdump" by default.
    709   virtual std::string GetObjdumpCmdName() {
    710     return "objdump";
    711   }
    712 
    713   // Switches to the objdump command. Default is " -h".
    714   virtual std::string GetObjdumpParameters() {
    715     return " -h";
    716   }
    717 
    718   // Get the name of the objdump, e.g., "objdump" by default.
    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>
    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>
    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>
    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>
    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>
    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>
   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 
   1053   std::string GetFPRegName(const FPReg& reg) {
   1054     std::ostringstream sreg;
   1055     sreg << reg;
   1056     return sreg.str();
   1057   }
   1058 
   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.
   1066   virtual const char* GetAssemblyHeader() {
   1067     return nullptr;
   1068   }
   1069 
   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>
   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.
   1125   virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
   1126   }
   1127 
   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