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