Home | History | Annotate | Download | only in arm
      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_ARM_ASSEMBLER_ARM_TEST_H_
     18 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
     19 
     20 #include "utils/assembler_test.h"
     21 
     22 namespace art {
     23 
     24 template<typename Ass,
     25          typename Reg,
     26          typename FPReg,
     27          typename Imm,
     28          typename SOp,
     29          typename Cond,
     30          typename SetCc>
     31 class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> {
     32  public:
     33   typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base;
     34 
     35   using Base::GetRegisters;
     36   using Base::GetRegName;
     37   using Base::CreateImmediate;
     38   using Base::WarnOnCombinations;
     39 
     40   static constexpr int64_t kFullImmRangeThreshold = 32;
     41 
     42   virtual void FillImmediates(std::vector<Imm>& immediates, int64_t imm_min, int64_t imm_max) {
     43     // Small range: do completely.
     44     if (imm_max - imm_min <= kFullImmRangeThreshold) {
     45       for (int64_t i = imm_min; i <= imm_max; ++i) {
     46         immediates.push_back(CreateImmediate(i));
     47       }
     48     } else {
     49       immediates.push_back(CreateImmediate(imm_min));
     50       immediates.push_back(CreateImmediate(imm_max));
     51       if (imm_min < imm_max - 1) {
     52         immediates.push_back(CreateImmediate(imm_min + 1));
     53       }
     54       if (imm_min < imm_max - 2) {
     55         immediates.push_back(CreateImmediate(imm_min + 2));
     56       }
     57       if (imm_min < imm_max - 3) {
     58         immediates.push_back(CreateImmediate(imm_max - 1));
     59       }
     60       if (imm_min < imm_max - 4) {
     61         immediates.push_back(CreateImmediate((imm_min + imm_max) / 2));
     62       }
     63     }
     64   }
     65 
     66   std::string RepeatRRIIC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
     67                           int64_t imm1_min, int64_t imm1_max,
     68                           int64_t imm2_min, int64_t imm2_max,
     69                           std::string fmt) {
     70     return RepeatTemplatedRRIIC(f, GetRegisters(), GetRegisters(),
     71                                 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
     72                                 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
     73                                 imm1_min, imm1_max, imm2_min, imm2_max,
     74                                 fmt);
     75   }
     76 
     77   template <typename Reg1, typename Reg2>
     78   std::string RepeatTemplatedRRIIC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
     79                                    const std::vector<Reg1*> reg1_registers,
     80                                    const std::vector<Reg2*> reg2_registers,
     81                                    std::string (AssemblerArmTest::*GetName1)(const Reg1&),
     82                                    std::string (AssemblerArmTest::*GetName2)(const Reg2&),
     83                                    int64_t imm1_min, int64_t imm1_max,
     84                                    int64_t imm2_min, int64_t imm2_max,
     85                                    std::string fmt) {
     86     std::vector<Imm> immediates1;
     87     FillImmediates(immediates1, imm1_min, imm1_max);
     88     std::vector<Imm> immediates2;
     89     FillImmediates(immediates2, imm2_min, imm2_max);
     90 
     91     std::vector<Cond>& cond = GetConditions();
     92 
     93     WarnOnCombinations(cond.size() * immediates1.size() * immediates2.size() *
     94                        reg1_registers.size() * reg2_registers.size());
     95 
     96     std::ostringstream oss;
     97     bool first = true;
     98     for (Cond& c : cond) {
     99       std::string after_cond = fmt;
    100 
    101       size_t cond_index = after_cond.find(COND_TOKEN);
    102       if (cond_index != std::string::npos) {
    103         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    104       }
    105 
    106       for (Imm i : immediates1) {
    107         std::string base = after_cond;
    108 
    109         size_t imm1_index = base.find(IMM1_TOKEN);
    110         if (imm1_index != std::string::npos) {
    111           std::ostringstream sreg;
    112           sreg << i;
    113           std::string imm_string = sreg.str();
    114           base.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
    115         }
    116 
    117         for (Imm j : immediates2) {
    118           std::string base2 = base;
    119 
    120           size_t imm2_index = base2.find(IMM2_TOKEN);
    121           if (imm2_index != std::string::npos) {
    122             std::ostringstream sreg;
    123             sreg << j;
    124             std::string imm_string = sreg.str();
    125             base2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
    126           }
    127 
    128           for (auto reg1 : reg1_registers) {
    129             std::string base3 = base2;
    130 
    131             std::string reg1_string = (this->*GetName1)(*reg1);
    132             size_t reg1_index;
    133             while ((reg1_index = base3.find(Base::REG1_TOKEN)) != std::string::npos) {
    134               base3.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
    135             }
    136 
    137             for (auto reg2 : reg2_registers) {
    138               std::string base4 = base3;
    139 
    140               std::string reg2_string = (this->*GetName2)(*reg2);
    141               size_t reg2_index;
    142               while ((reg2_index = base4.find(Base::REG2_TOKEN)) != std::string::npos) {
    143                 base4.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
    144               }
    145 
    146               if (first) {
    147                 first = false;
    148               } else {
    149                 oss << "\n";
    150               }
    151               oss << base4;
    152 
    153               (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
    154             }
    155           }
    156         }
    157       }
    158     }
    159     // Add a newline at the end.
    160     oss << "\n";
    161 
    162     return oss.str();
    163   }
    164 
    165   std::string RepeatRRiiC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
    166                           std::vector<std::pair<Imm, Imm>>& immediates,
    167                           std::string fmt) {
    168     return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(),
    169         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    170         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    171         immediates, fmt);
    172   }
    173 
    174   template <typename Reg1, typename Reg2>
    175   std::string RepeatTemplatedRRiiC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
    176         const std::vector<Reg1*> reg1_registers,
    177         const std::vector<Reg2*> reg2_registers,
    178         std::string (AssemblerArmTest::*GetName1)(const Reg1&),
    179         std::string (AssemblerArmTest::*GetName2)(const Reg2&),
    180         std::vector<std::pair<Imm, Imm>>& immediates,
    181         std::string fmt) {
    182     std::vector<Cond>& cond = GetConditions();
    183 
    184     WarnOnCombinations(cond.size() * immediates.size() * reg1_registers.size() *
    185                        reg2_registers.size());
    186 
    187     std::ostringstream oss;
    188     bool first = true;
    189     for (Cond& c : cond) {
    190       std::string after_cond = fmt;
    191 
    192       size_t cond_index = after_cond.find(COND_TOKEN);
    193       if (cond_index != std::string::npos) {
    194         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    195       }
    196 
    197       for (std::pair<Imm, Imm>& pair : immediates) {
    198         Imm i = pair.first;
    199         Imm j = pair.second;
    200         std::string after_imm1 = after_cond;
    201 
    202         size_t imm1_index = after_imm1.find(IMM1_TOKEN);
    203         if (imm1_index != std::string::npos) {
    204           std::ostringstream sreg;
    205           sreg << i;
    206           std::string imm_string = sreg.str();
    207           after_imm1.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
    208         }
    209 
    210         std::string after_imm2 = after_imm1;
    211 
    212         size_t imm2_index = after_imm2.find(IMM2_TOKEN);
    213         if (imm2_index != std::string::npos) {
    214           std::ostringstream sreg;
    215           sreg << j;
    216           std::string imm_string = sreg.str();
    217           after_imm2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
    218         }
    219 
    220         for (auto reg1 : reg1_registers) {
    221           std::string after_reg1 = after_imm2;
    222 
    223           std::string reg1_string = (this->*GetName1)(*reg1);
    224           size_t reg1_index;
    225           while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
    226             after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
    227           }
    228 
    229           for (auto reg2 : reg2_registers) {
    230             std::string after_reg2 = after_reg1;
    231 
    232             std::string reg2_string = (this->*GetName2)(*reg2);
    233             size_t reg2_index;
    234             while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
    235               after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
    236             }
    237 
    238             if (first) {
    239               first = false;
    240             } else {
    241               oss << "\n";
    242             }
    243             oss << after_reg2;
    244 
    245             (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
    246           }
    247         }
    248       }
    249     }
    250     // Add a newline at the end.
    251     oss << "\n";
    252 
    253     return oss.str();
    254   }
    255 
    256   std::string RepeatRRC(void (Ass::*f)(Reg, Reg, Cond), std::string fmt) {
    257     return RepeatTemplatedRRC(f, GetRegisters(), GetRegisters(), GetConditions(),
    258         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    259         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    260         fmt);
    261   }
    262 
    263   template <typename Reg1, typename Reg2>
    264   std::string RepeatTemplatedRRC(void (Ass::*f)(Reg1, Reg2, Cond),
    265                                  const std::vector<Reg1*>& reg1_registers,
    266                                  const std::vector<Reg2*>& reg2_registers,
    267                                  const std::vector<Cond>& cond,
    268                                  std::string (AssemblerArmTest::*GetName1)(const Reg1&),
    269                                  std::string (AssemblerArmTest::*GetName2)(const Reg2&),
    270                                  std::string fmt) {
    271     WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size());
    272 
    273     std::ostringstream oss;
    274     bool first = true;
    275     for (const Cond& c : cond) {
    276       std::string after_cond = fmt;
    277 
    278       size_t cond_index = after_cond.find(COND_TOKEN);
    279       if (cond_index != std::string::npos) {
    280         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    281       }
    282 
    283       for (auto reg1 : reg1_registers) {
    284         std::string after_reg1 = after_cond;
    285 
    286         std::string reg1_string = (this->*GetName1)(*reg1);
    287         size_t reg1_index;
    288         while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
    289           after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
    290         }
    291 
    292         for (auto reg2 : reg2_registers) {
    293           std::string after_reg2 = after_reg1;
    294 
    295           std::string reg2_string = (this->*GetName2)(*reg2);
    296           size_t reg2_index;
    297           while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
    298             after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
    299           }
    300 
    301           if (first) {
    302             first = false;
    303           } else {
    304             oss << "\n";
    305           }
    306           oss << after_reg2;
    307 
    308           (Base::GetAssembler()->*f)(*reg1, *reg2, c);
    309         }
    310       }
    311     }
    312     // Add a newline at the end.
    313     oss << "\n";
    314 
    315     return oss.str();
    316   }
    317 
    318   std::string RepeatRRRC(void (Ass::*f)(Reg, Reg, Reg, Cond), std::string fmt) {
    319     return RepeatTemplatedRRRC(f, GetRegisters(), GetRegisters(), GetRegisters(), GetConditions(),
    320                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    321                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    322                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
    323                                fmt);
    324   }
    325 
    326   template <typename Reg1, typename Reg2, typename Reg3>
    327   std::string RepeatTemplatedRRRC(void (Ass::*f)(Reg1, Reg2, Reg3, Cond),
    328                                   const std::vector<Reg1*>& reg1_registers,
    329                                   const std::vector<Reg2*>& reg2_registers,
    330                                   const std::vector<Reg3*>& reg3_registers,
    331                                   const std::vector<Cond>& cond,
    332                                   std::string (AssemblerArmTest::*GetName1)(const Reg1&),
    333                                   std::string (AssemblerArmTest::*GetName2)(const Reg2&),
    334                                   std::string (AssemblerArmTest::*GetName3)(const Reg3&),
    335                                   std::string fmt) {
    336     WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() *
    337                        reg3_registers.size());
    338 
    339     std::ostringstream oss;
    340     bool first = true;
    341     for (const Cond& c : cond) {
    342       std::string after_cond = fmt;
    343 
    344       size_t cond_index = after_cond.find(COND_TOKEN);
    345       if (cond_index != std::string::npos) {
    346         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    347       }
    348 
    349       for (auto reg1 : reg1_registers) {
    350         std::string after_reg1 = after_cond;
    351 
    352         std::string reg1_string = (this->*GetName1)(*reg1);
    353         size_t reg1_index;
    354         while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
    355           after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
    356         }
    357 
    358         for (auto reg2 : reg2_registers) {
    359           std::string after_reg2 = after_reg1;
    360 
    361           std::string reg2_string = (this->*GetName2)(*reg2);
    362           size_t reg2_index;
    363           while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
    364             after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
    365           }
    366 
    367           for (auto reg3 : reg3_registers) {
    368             std::string after_reg3 = after_reg2;
    369 
    370             std::string reg3_string = (this->*GetName3)(*reg3);
    371             size_t reg3_index;
    372             while ((reg3_index = after_reg3.find(REG3_TOKEN)) != std::string::npos) {
    373               after_reg3.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
    374             }
    375 
    376             if (first) {
    377               first = false;
    378             } else {
    379               oss << "\n";
    380             }
    381             oss << after_reg3;
    382 
    383             (Base::GetAssembler()->*f)(*reg1, *reg2, *reg3, c);
    384           }
    385         }
    386       }
    387     }
    388     // Add a newline at the end.
    389     oss << "\n";
    390 
    391     return oss.str();
    392   }
    393 
    394   template <typename RegT>
    395   std::string RepeatTemplatedRSC(void (Ass::*f)(RegT, SOp, Cond),
    396                                  const std::vector<RegT*>& registers,
    397                                  const std::vector<SOp>& shifts,
    398                                  const std::vector<Cond>& cond,
    399                                  std::string (AssemblerArmTest::*GetName)(const RegT&),
    400                                  std::string fmt) {
    401     WarnOnCombinations(cond.size() * registers.size() * shifts.size());
    402 
    403     std::ostringstream oss;
    404     bool first = true;
    405     for (const Cond& c : cond) {
    406       std::string after_cond = fmt;
    407 
    408       size_t cond_index = after_cond.find(COND_TOKEN);
    409       if (cond_index != std::string::npos) {
    410         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    411       }
    412 
    413       for (const SOp& shift : shifts) {
    414         std::string after_shift = after_cond;
    415 
    416         std::string shift_string = GetShiftString(shift);
    417         size_t shift_index;
    418         while ((shift_index = after_shift.find(Base::SHIFT_TOKEN)) != std::string::npos) {
    419           after_shift.replace(shift_index, ConstexprStrLen(Base::SHIFT_TOKEN), shift_string);
    420         }
    421 
    422         for (auto reg : registers) {
    423           std::string after_reg = after_shift;
    424 
    425           std::string reg_string = (this->*GetName)(*reg);
    426           size_t reg_index;
    427           while ((reg_index = after_reg.find(Base::REG_TOKEN)) != std::string::npos) {
    428             after_reg.replace(reg_index, ConstexprStrLen(Base::REG_TOKEN), reg_string);
    429           }
    430 
    431           if (first) {
    432             first = false;
    433           } else {
    434             oss << "\n";
    435           }
    436           oss << after_reg;
    437 
    438           (Base::GetAssembler()->*f)(*reg, shift, c);
    439         }
    440       }
    441     }
    442     // Add a newline at the end.
    443     oss << "\n";
    444 
    445     return oss.str();
    446   }
    447 
    448   template <typename Reg1, typename Reg2>
    449   std::string RepeatTemplatedRRSC(void (Ass::*f)(Reg1, Reg2, const SOp&, Cond),
    450                                   const std::vector<Reg1*>& reg1_registers,
    451                                   const std::vector<Reg2*>& reg2_registers,
    452                                   const std::vector<SOp>& shifts,
    453                                   const std::vector<Cond>& cond,
    454                                   std::string (AssemblerArmTest::*GetName1)(const Reg1&),
    455                                   std::string (AssemblerArmTest::*GetName2)(const Reg2&),
    456                                   std::string fmt) {
    457     WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * shifts.size());
    458 
    459     std::ostringstream oss;
    460     bool first = true;
    461     for (const Cond& c : cond) {
    462       std::string after_cond = fmt;
    463 
    464       size_t cond_index = after_cond.find(COND_TOKEN);
    465       if (cond_index != std::string::npos) {
    466         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    467       }
    468 
    469       for (const SOp& shift : shifts) {
    470         std::string after_shift = after_cond;
    471 
    472         std::string shift_string = GetShiftString(shift);
    473         size_t shift_index;
    474         while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
    475           after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    476         }
    477 
    478         for (auto reg1 : reg1_registers) {
    479           std::string after_reg1 = after_shift;
    480 
    481           std::string reg1_string = (this->*GetName1)(*reg1);
    482           size_t reg1_index;
    483           while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
    484             after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
    485           }
    486 
    487           for (auto reg2 : reg2_registers) {
    488             std::string after_reg2 = after_reg1;
    489 
    490             std::string reg2_string = (this->*GetName2)(*reg2);
    491             size_t reg2_index;
    492             while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
    493               after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
    494             }
    495 
    496             if (first) {
    497               first = false;
    498             } else {
    499               oss << "\n";
    500             }
    501             oss << after_reg2;
    502 
    503             (Base::GetAssembler()->*f)(*reg1, *reg2, shift, c);
    504           }
    505         }
    506       }
    507     }
    508     // Add a newline at the end.
    509     oss << "\n";
    510 
    511     return oss.str();
    512   }
    513 
    514  protected:
    515   explicit AssemblerArmTest() {}
    516 
    517   virtual std::vector<Cond>& GetConditions() = 0;
    518   virtual std::string GetConditionString(Cond c) = 0;
    519 
    520   virtual std::vector<SetCc>& GetSetCcs() = 0;
    521   virtual std::string GetSetCcString(SetCc s) = 0;
    522 
    523   virtual std::vector<SOp>& GetShiftOperands() = 0;
    524   virtual std::string GetShiftString(SOp sop) = 0;
    525 
    526   virtual Reg GetPCRegister() = 0;
    527   virtual std::vector<Reg*> GetRegistersWithoutPC() {
    528     std::vector<Reg*> without_pc = GetRegisters();
    529     Reg pc_reg = GetPCRegister();
    530 
    531     for (auto it = without_pc.begin(); it != without_pc.end(); ++it) {
    532       if (**it == pc_reg) {
    533         without_pc.erase(it);
    534         break;
    535       }
    536     }
    537 
    538     return without_pc;
    539   }
    540 
    541   static constexpr const char* IMM1_TOKEN = "{imm1}";
    542   static constexpr const char* IMM2_TOKEN = "{imm2}";
    543   static constexpr const char* REG3_TOKEN = "{reg3}";
    544   static constexpr const char* REG4_TOKEN = "{reg4}";
    545   static constexpr const char* COND_TOKEN = "{cond}";
    546   static constexpr const char* SET_CC_TOKEN = "{s}";
    547   static constexpr const char* SHIFT_TOKEN = "{shift}";
    548 
    549  private:
    550   DISALLOW_COPY_AND_ASSIGN(AssemblerArmTest);
    551 };
    552 
    553 }  // namespace art
    554 
    555 #endif  // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
    556