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 #include "assembler_arm32.h"
     18 
     19 #include <functional>
     20 #include <type_traits>
     21 
     22 #include "base/macros.h"
     23 #include "base/stl_util.h"
     24 #include "utils/arm/assembler_arm_test.h"
     25 
     26 namespace art {
     27 
     28 using std::placeholders::_1;
     29 using std::placeholders::_2;
     30 using std::placeholders::_3;
     31 using std::placeholders::_4;
     32 using std::placeholders::_5;
     33 
     34 // To speed up tests, don't use all register combinations.
     35 static constexpr bool kUseSparseRegisterList = true;
     36 
     37 // To speed up tests, don't use all condition codes.
     38 static constexpr bool kUseSparseConditionList = true;
     39 
     40 // To speed up tests, don't use all shift immediates.
     41 static constexpr bool kUseSparseShiftImmediates = true;
     42 
     43 class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler,
     44                                                    arm::Register, arm::SRegister,
     45                                                    uint32_t, arm::ShifterOperand, arm::Condition,
     46                                                    arm::SetCc> {
     47  protected:
     48   std::string GetArchitectureString() OVERRIDE {
     49     return "arm";
     50   }
     51 
     52   std::string GetAssemblerParameters() OVERRIDE {
     53     // Arm-v7a, cortex-a15 (means we have sdiv).
     54     return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
     55   }
     56 
     57   const char* GetAssemblyHeader() OVERRIDE {
     58     return kArm32AssemblyHeader;
     59   }
     60 
     61   std::string GetDisassembleParameters() OVERRIDE {
     62     return " -D -bbinary -marm --no-show-raw-insn";
     63   }
     64 
     65   void SetUpHelpers() OVERRIDE {
     66     if (registers_.size() == 0) {
     67       if (kUseSparseRegisterList) {
     68         registers_.insert(end(registers_),
     69                           {  // NOLINT(whitespace/braces)
     70                               new arm::Register(arm::R0),
     71                               new arm::Register(arm::R1),
     72                               new arm::Register(arm::R4),
     73                               new arm::Register(arm::R8),
     74                               new arm::Register(arm::R11),
     75                               new arm::Register(arm::R12),
     76                               new arm::Register(arm::R13),
     77                               new arm::Register(arm::R14),
     78                               new arm::Register(arm::R15)
     79                           });
     80       } else {
     81         registers_.insert(end(registers_),
     82                           {  // NOLINT(whitespace/braces)
     83                               new arm::Register(arm::R0),
     84                               new arm::Register(arm::R1),
     85                               new arm::Register(arm::R2),
     86                               new arm::Register(arm::R3),
     87                               new arm::Register(arm::R4),
     88                               new arm::Register(arm::R5),
     89                               new arm::Register(arm::R6),
     90                               new arm::Register(arm::R7),
     91                               new arm::Register(arm::R8),
     92                               new arm::Register(arm::R9),
     93                               new arm::Register(arm::R10),
     94                               new arm::Register(arm::R11),
     95                               new arm::Register(arm::R12),
     96                               new arm::Register(arm::R13),
     97                               new arm::Register(arm::R14),
     98                               new arm::Register(arm::R15)
     99                           });
    100       }
    101     }
    102 
    103     if (!kUseSparseConditionList) {
    104       conditions_.push_back(arm::Condition::EQ);
    105       conditions_.push_back(arm::Condition::NE);
    106       conditions_.push_back(arm::Condition::CS);
    107       conditions_.push_back(arm::Condition::CC);
    108       conditions_.push_back(arm::Condition::MI);
    109       conditions_.push_back(arm::Condition::PL);
    110       conditions_.push_back(arm::Condition::VS);
    111       conditions_.push_back(arm::Condition::VC);
    112       conditions_.push_back(arm::Condition::HI);
    113       conditions_.push_back(arm::Condition::LS);
    114       conditions_.push_back(arm::Condition::GE);
    115       conditions_.push_back(arm::Condition::LT);
    116       conditions_.push_back(arm::Condition::GT);
    117       conditions_.push_back(arm::Condition::LE);
    118       conditions_.push_back(arm::Condition::AL);
    119     } else {
    120       conditions_.push_back(arm::Condition::EQ);
    121       conditions_.push_back(arm::Condition::NE);
    122       conditions_.push_back(arm::Condition::CC);
    123       conditions_.push_back(arm::Condition::VC);
    124       conditions_.push_back(arm::Condition::HI);
    125       conditions_.push_back(arm::Condition::LT);
    126       conditions_.push_back(arm::Condition::AL);
    127     }
    128 
    129     set_ccs_.push_back(arm::kCcDontCare);
    130     set_ccs_.push_back(arm::kCcSet);
    131     set_ccs_.push_back(arm::kCcKeep);
    132 
    133     shifter_operands_.push_back(arm::ShifterOperand(0));
    134     shifter_operands_.push_back(arm::ShifterOperand(1));
    135     shifter_operands_.push_back(arm::ShifterOperand(2));
    136     shifter_operands_.push_back(arm::ShifterOperand(3));
    137     shifter_operands_.push_back(arm::ShifterOperand(4));
    138     shifter_operands_.push_back(arm::ShifterOperand(5));
    139     shifter_operands_.push_back(arm::ShifterOperand(127));
    140     shifter_operands_.push_back(arm::ShifterOperand(128));
    141     shifter_operands_.push_back(arm::ShifterOperand(254));
    142     shifter_operands_.push_back(arm::ShifterOperand(255));
    143 
    144     if (!kUseSparseRegisterList) {
    145       shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
    146       shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
    147       shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
    148       shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
    149       shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
    150       shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
    151       shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
    152       shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
    153       shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
    154       shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
    155       shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
    156       shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
    157       shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
    158       shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
    159     } else {
    160       shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
    161       shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
    162       shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
    163       shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
    164       shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
    165       shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
    166       shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
    167     }
    168 
    169     std::vector<arm::Shift> shifts {
    170       arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
    171     };
    172 
    173     // ShifterOperands of form "reg shift-type imm."
    174     for (arm::Shift shift : shifts) {
    175       for (arm::Register* reg : registers_) {  // Note: this will pick up the sparse set.
    176         if (*reg == arm::R15) {  // Skip PC.
    177           continue;
    178         }
    179         if (shift != arm::Shift::RRX) {
    180           if (!kUseSparseShiftImmediates) {
    181             for (uint32_t imm = 1; imm < 32; ++imm) {
    182               shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
    183             }
    184           } else {
    185             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
    186             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
    187             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
    188             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
    189             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
    190             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
    191             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
    192             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
    193           }
    194         } else {
    195           // RRX doesn't have an immediate.
    196           shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
    197         }
    198       }
    199     }
    200   }
    201 
    202   std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
    203                                                         int32_t shift_min, int32_t shift_max) {
    204     std::vector<arm::ShifterOperand> res;
    205     static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
    206                                               arm::Shift::ROR };
    207 
    208     for (arm::Shift shift : kShifts) {
    209       for (arm::Register* reg : base_regs) {
    210         // Take the min, the max, and three values in between.
    211         res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
    212         if (shift_min != shift_max) {
    213           res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
    214           int32_t middle = (shift_min + shift_max) / 2;
    215           res.push_back(arm::ShifterOperand(*reg, shift, middle));
    216           res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
    217           res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
    218         }
    219       }
    220     }
    221 
    222     return res;
    223   }
    224 
    225   void TearDown() OVERRIDE {
    226     AssemblerArmTest::TearDown();
    227     STLDeleteElements(&registers_);
    228   }
    229 
    230   std::vector<arm::Register*> GetRegisters() OVERRIDE {
    231     return registers_;
    232   }
    233 
    234   uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
    235     return imm_value;
    236   }
    237 
    238   std::vector<arm::Condition>& GetConditions() OVERRIDE {
    239     return conditions_;
    240   }
    241 
    242   std::string GetConditionString(arm::Condition c) OVERRIDE {
    243     std::ostringstream oss;
    244     oss << c;
    245     return oss.str();
    246   }
    247 
    248   std::vector<arm::SetCc>& GetSetCcs() OVERRIDE {
    249     return set_ccs_;
    250   }
    251 
    252   std::string GetSetCcString(arm::SetCc s) OVERRIDE {
    253     // For arm32, kCcDontCare defaults to not setting condition codes.
    254     return s == arm::kCcSet ? "s" : "";
    255   }
    256 
    257   arm::Register GetPCRegister() OVERRIDE {
    258     return arm::R15;
    259   }
    260 
    261   std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
    262     return shifter_operands_;
    263   }
    264 
    265   std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
    266     std::ostringstream oss;
    267     if (sop.IsShift()) {
    268       // Not a rotate...
    269       if (sop.GetShift() == arm::Shift::RRX) {
    270         oss << sop.GetRegister() << ", " << sop.GetShift();
    271       } else {
    272         oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
    273       }
    274     } else if (sop.IsRegister()) {
    275       oss << sop.GetRegister();
    276     } else {
    277       CHECK(sop.IsImmediate());
    278       oss << "#" << sop.GetImmediate();
    279     }
    280     return oss.str();
    281   }
    282 
    283   static const char* GetRegTokenFromDepth(int depth) {
    284     switch (depth) {
    285       case 0:
    286         return Base::REG1_TOKEN;
    287       case 1:
    288         return Base::REG2_TOKEN;
    289       case 2:
    290         return Base::REG3_TOKEN;
    291       case 3:
    292         return REG4_TOKEN;
    293       default:
    294         LOG(FATAL) << "Depth problem.";
    295         UNREACHABLE();
    296     }
    297   }
    298 
    299   void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
    300     if (first_) {
    301       first_ = false;
    302     } else {
    303       oss << "\n";
    304     }
    305     oss << fmt;
    306 
    307     f();
    308   }
    309 
    310   // NOTE: Only support simple test like "aaa=bbb"
    311   bool EvalFilterString(std::string filter) {
    312     if (filter.compare("") == 0) {
    313       return false;
    314     }
    315 
    316     size_t equal_sign_index = filter.find('=');
    317     if (equal_sign_index == std::string::npos) {
    318       EXPECT_TRUE(false) << "Unsupported filter string.";
    319     }
    320 
    321     std::string lhs = filter.substr(0, equal_sign_index);
    322     std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
    323     return lhs.compare(rhs) == 0;
    324   }
    325 
    326   void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
    327                       bool without_pc, std::string fmt, std::string filter,
    328                       std::ostringstream& oss) {
    329     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
    330     for (auto reg : registers) {
    331       std::string after_reg = fmt;
    332       std::string after_reg_filter = filter;
    333 
    334       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
    335       size_t reg_index;
    336       const char* reg_token = GetRegTokenFromDepth(depth);
    337 
    338       while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
    339         after_reg.replace(reg_index, strlen(reg_token), reg_string);
    340       }
    341 
    342       while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
    343         after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
    344       }
    345       if (EvalFilterString(after_reg_filter)) {
    346         continue;
    347       }
    348 
    349       ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
    350     }
    351   }
    352 
    353   void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
    354                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
    355                       std::ostringstream& oss) {
    356     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
    357       std::string after_shift = fmt;
    358       std::string after_shift_filter = filter;
    359 
    360       std::string shift_string = GetShiftString(shift);
    361       size_t shift_index;
    362       while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
    363         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    364       }
    365 
    366       while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
    367         after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    368       }
    369       if (EvalFilterString(after_shift_filter)) {
    370         continue;
    371       }
    372 
    373       ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
    374     }
    375   }
    376 
    377   void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
    378                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
    379                       std::ostringstream& oss) {
    380     for (arm::Condition c : GetConditions()) {
    381       std::string after_cond = fmt;
    382       std::string after_cond_filter = filter;
    383 
    384       size_t cond_index = after_cond.find(COND_TOKEN);
    385       if (cond_index != std::string::npos) {
    386         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    387       }
    388 
    389       cond_index = after_cond_filter.find(COND_TOKEN);
    390       if (cond_index != std::string::npos) {
    391         after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    392       }
    393       if (EvalFilterString(after_cond_filter)) {
    394         continue;
    395       }
    396 
    397       ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
    398     }
    399   }
    400 
    401   void TemplateHelper(std::function<void(arm::SetCc)> f, int depth ATTRIBUTE_UNUSED,
    402                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
    403                       std::ostringstream& oss) {
    404     for (arm::SetCc s : GetSetCcs()) {
    405       std::string after_cond = fmt;
    406       std::string after_cond_filter = filter;
    407 
    408       size_t cond_index = after_cond.find(SET_CC_TOKEN);
    409       if (cond_index != std::string::npos) {
    410         after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
    411       }
    412 
    413       cond_index = after_cond_filter.find(SET_CC_TOKEN);
    414       if (cond_index != std::string::npos) {
    415         after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
    416       }
    417       if (EvalFilterString(after_cond_filter)) {
    418         continue;
    419       }
    420 
    421       ExecuteAndPrint([&] () { f(s); }, after_cond, oss);
    422     }
    423   }
    424 
    425   template <typename... Args>
    426   void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
    427                       std::string fmt, std::string filter, std::ostringstream& oss) {
    428     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
    429     for (auto reg : registers) {
    430       std::string after_reg = fmt;
    431       std::string after_reg_filter = filter;
    432 
    433       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
    434       size_t reg_index;
    435       const char* reg_token = GetRegTokenFromDepth(depth);
    436 
    437       while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
    438         after_reg.replace(reg_index, strlen(reg_token), reg_string);
    439       }
    440 
    441       while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
    442         after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
    443       }
    444       if (EvalFilterString(after_reg_filter)) {
    445         continue;
    446       }
    447 
    448       auto lambda = [&] (Args... args) { f(*reg, args...); };  // NOLINT [readability/braces] [4]
    449       TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
    450           after_reg, after_reg_filter, oss);
    451     }
    452   }
    453 
    454   template <typename... Args>
    455   void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
    456                       bool without_pc, std::string fmt, std::string filter,
    457                       std::ostringstream& oss) {
    458     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
    459       std::string after_shift = fmt;
    460       std::string after_shift_filter = filter;
    461 
    462       std::string shift_string = GetShiftString(shift);
    463       size_t shift_index;
    464       while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
    465         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    466       }
    467 
    468       while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
    469         after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    470       }
    471       if (EvalFilterString(after_shift_filter)) {
    472         continue;
    473       }
    474 
    475       auto lambda = [&] (Args... args) { f(shift, args...); };  // NOLINT [readability/braces] [4]
    476       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
    477           after_shift, after_shift_filter, oss);
    478     }
    479   }
    480 
    481   template <typename... Args>
    482   void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
    483                       std::string fmt, std::string filter, std::ostringstream& oss) {
    484     for (arm::Condition c : GetConditions()) {
    485       std::string after_cond = fmt;
    486       std::string after_cond_filter = filter;
    487 
    488       size_t cond_index = after_cond.find(COND_TOKEN);
    489       if (cond_index != std::string::npos) {
    490         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    491       }
    492 
    493       cond_index = after_cond_filter.find(COND_TOKEN);
    494       if (cond_index != std::string::npos) {
    495         after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
    496       }
    497       if (EvalFilterString(after_cond_filter)) {
    498         continue;
    499       }
    500 
    501       auto lambda = [&] (Args... args) { f(c, args...); };  // NOLINT [readability/braces] [4]
    502       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
    503           after_cond, after_cond_filter, oss);
    504     }
    505   }
    506 
    507   template <typename... Args>
    508   void TemplateHelper(std::function<void(arm::SetCc, Args...)> f, int depth, bool without_pc,
    509                       std::string fmt, std::string filter, std::ostringstream& oss) {
    510     for (arm::SetCc s : GetSetCcs()) {
    511       std::string after_cond = fmt;
    512       std::string after_cond_filter = filter;
    513 
    514       size_t cond_index = after_cond.find(SET_CC_TOKEN);
    515       if (cond_index != std::string::npos) {
    516         after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
    517       }
    518 
    519       cond_index = after_cond_filter.find(SET_CC_TOKEN);
    520       if (cond_index != std::string::npos) {
    521         after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
    522       }
    523       if (EvalFilterString(after_cond_filter)) {
    524         continue;
    525       }
    526 
    527       auto lambda = [&] (Args... args) { f(s, args...); };  // NOLINT [readability/braces] [4]
    528       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
    529           after_cond, after_cond_filter, oss);
    530     }
    531   }
    532 
    533   template <typename Assembler, typename T1, typename T2>
    534   std::function<void(T1, T2)> GetBoundFunction2(void (Assembler::*f)(T1, T2)) {
    535     return std::bind(f, GetAssembler(), _1, _2);
    536   }
    537 
    538   template <typename Assembler, typename T1, typename T2, typename T3>
    539   std::function<void(T1, T2, T3)> GetBoundFunction3(void (Assembler::*f)(T1, T2, T3)) {
    540     return std::bind(f, GetAssembler(), _1, _2, _3);
    541   }
    542 
    543   template <typename Assembler, typename T1, typename T2, typename T3, typename T4>
    544   std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
    545       void (Assembler::*f)(T1, T2, T3, T4)) {
    546     return std::bind(f, GetAssembler(), _1, _2, _3, _4);
    547   }
    548 
    549   template <typename Assembler, typename T1, typename T2, typename T3, typename T4, typename T5>
    550   std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
    551       void (Assembler::*f)(T1, T2, T3, T4, T5)) {
    552     return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
    553   }
    554 
    555   template <typename... Args>
    556   void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
    557                              std::string fmt, std::string test_name, std::string filter) {
    558     first_ = false;
    559     WarnOnCombinations(CountHelper<Args...>(without_pc));
    560 
    561     std::ostringstream oss;
    562 
    563     TemplateHelper(f, 0, without_pc, fmt, filter, oss);
    564 
    565     oss << "\n";  // Trailing newline.
    566 
    567     DriverStr(oss.str(), test_name);
    568   }
    569 
    570   template <typename Assembler, typename... Args>
    571   void T2Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
    572                 std::string test_name, std::string filter = "") {
    573     GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
    574   }
    575 
    576   template <typename Assembler, typename... Args>
    577   void T3Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
    578       std::string test_name, std::string filter = "") {
    579     GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
    580   }
    581 
    582   template <typename Assembler, typename... Args>
    583   void T4Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
    584       std::string test_name, std::string filter = "") {
    585     GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
    586   }
    587 
    588   template <typename Assembler, typename... Args>
    589   void T5Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
    590       std::string test_name, std::string filter = "") {
    591     GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
    592   }
    593 
    594  private:
    595   template <typename T>
    596   size_t CountHelper(bool without_pc) {
    597     size_t tmp;
    598     if (std::is_same<T, arm::Register>::value) {
    599       tmp = GetRegisters().size();
    600       if (without_pc) {
    601         tmp--;;  // Approximation...
    602       }
    603       return tmp;
    604     } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
    605       return GetShiftOperands().size();
    606     } else if (std::is_same<T, arm::Condition>::value) {
    607       return GetConditions().size();
    608     } else {
    609       LOG(WARNING) << "Unknown type while counting.";
    610       return 1;
    611     }
    612   }
    613 
    614   template <typename T1, typename T2, typename... Args>
    615   size_t CountHelper(bool without_pc) {
    616     size_t tmp;
    617     if (std::is_same<T1, arm::Register>::value) {
    618       tmp = GetRegisters().size();
    619       if (without_pc) {
    620         tmp--;;  // Approximation...
    621       }
    622     } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
    623       tmp =  GetShiftOperands().size();
    624     } else if (std::is_same<T1, arm::Condition>::value) {
    625       tmp = GetConditions().size();
    626     } else {
    627       LOG(WARNING) << "Unknown type while counting.";
    628       tmp = 1;
    629     }
    630     size_t rec = CountHelper<T2, Args...>(without_pc);
    631     return rec * tmp;
    632   }
    633 
    634   bool first_;
    635 
    636   static constexpr const char* kArm32AssemblyHeader = ".arm\n";
    637 
    638   std::vector<arm::Register*> registers_;
    639   std::vector<arm::Condition> conditions_;
    640   std::vector<arm::SetCc> set_ccs_;
    641   std::vector<arm::ShifterOperand> shifter_operands_;
    642 };
    643 
    644 
    645 TEST_F(AssemblerArm32Test, Toolchain) {
    646   EXPECT_TRUE(CheckTools());
    647 }
    648 
    649 TEST_F(AssemblerArm32Test, Sbfx) {
    650   std::vector<std::pair<uint32_t, uint32_t>> immediates;
    651   immediates.push_back({0, 1});
    652   immediates.push_back({0, 8});
    653   immediates.push_back({0, 15});
    654   immediates.push_back({0, 16});
    655   immediates.push_back({0, 31});
    656   immediates.push_back({0, 32});
    657 
    658   immediates.push_back({1, 1});
    659   immediates.push_back({1, 15});
    660   immediates.push_back({1, 31});
    661 
    662   immediates.push_back({8, 1});
    663   immediates.push_back({8, 15});
    664   immediates.push_back({8, 16});
    665   immediates.push_back({8, 24});
    666 
    667   immediates.push_back({31, 1});
    668 
    669   DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
    670                         "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
    671 }
    672 
    673 TEST_F(AssemblerArm32Test, Ubfx) {
    674   std::vector<std::pair<uint32_t, uint32_t>> immediates;
    675   immediates.push_back({0, 1});
    676   immediates.push_back({0, 8});
    677   immediates.push_back({0, 15});
    678   immediates.push_back({0, 16});
    679   immediates.push_back({0, 31});
    680   immediates.push_back({0, 32});
    681 
    682   immediates.push_back({1, 1});
    683   immediates.push_back({1, 15});
    684   immediates.push_back({1, 31});
    685 
    686   immediates.push_back({8, 1});
    687   immediates.push_back({8, 15});
    688   immediates.push_back({8, 16});
    689   immediates.push_back({8, 24});
    690 
    691   immediates.push_back({31, 1});
    692 
    693   DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
    694                         "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
    695 }
    696 
    697 TEST_F(AssemblerArm32Test, Mul) {
    698   T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
    699 }
    700 
    701 TEST_F(AssemblerArm32Test, Mla) {
    702   T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
    703 }
    704 
    705 TEST_F(AssemblerArm32Test, Umull) {
    706   T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
    707            "umull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
    708 }
    709 
    710 TEST_F(AssemblerArm32Test, Smull) {
    711   T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
    712            "smull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
    713 }
    714 
    715 TEST_F(AssemblerArm32Test, Sdiv) {
    716   T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
    717 }
    718 
    719 TEST_F(AssemblerArm32Test, Udiv) {
    720   T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
    721 }
    722 
    723 TEST_F(AssemblerArm32Test, And) {
    724   T5Helper(&arm::Arm32Assembler::and_, true, "and{cond}{s} {reg1}, {reg2}, {shift}", "and");
    725 }
    726 
    727 TEST_F(AssemblerArm32Test, Ands) {
    728   T4Helper(&arm::Arm32Assembler::ands, true, "and{cond}s {reg1}, {reg2}, {shift}", "ands");
    729 }
    730 
    731 TEST_F(AssemblerArm32Test, Eor) {
    732   T5Helper(&arm::Arm32Assembler::eor, true, "eor{cond}{s} {reg1}, {reg2}, {shift}", "eor");
    733 }
    734 
    735 TEST_F(AssemblerArm32Test, Eors) {
    736   T4Helper(&arm::Arm32Assembler::eors, true, "eor{cond}s {reg1}, {reg2}, {shift}", "eors");
    737 }
    738 
    739 TEST_F(AssemblerArm32Test, Orr) {
    740   T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr");
    741 }
    742 
    743 TEST_F(AssemblerArm32Test, Orrs) {
    744   T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
    745 }
    746 
    747 TEST_F(AssemblerArm32Test, Bic) {
    748   T5Helper(&arm::Arm32Assembler::bic, true, "bic{cond}{s} {reg1}, {reg2}, {shift}", "bic");
    749 }
    750 
    751 TEST_F(AssemblerArm32Test, Bics) {
    752   T4Helper(&arm::Arm32Assembler::bics, true, "bic{cond}s {reg1}, {reg2}, {shift}", "bics");
    753 }
    754 
    755 TEST_F(AssemblerArm32Test, Mov) {
    756   T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov");
    757 }
    758 
    759 TEST_F(AssemblerArm32Test, Movs) {
    760   T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
    761 }
    762 
    763 TEST_F(AssemblerArm32Test, Mvn) {
    764   T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn");
    765 }
    766 
    767 TEST_F(AssemblerArm32Test, Mvns) {
    768   T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
    769 }
    770 
    771 TEST_F(AssemblerArm32Test, Add) {
    772   T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add");
    773 }
    774 
    775 TEST_F(AssemblerArm32Test, Adds) {
    776   T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
    777 }
    778 
    779 TEST_F(AssemblerArm32Test, Adc) {
    780   T5Helper(&arm::Arm32Assembler::adc, false, "adc{cond}{s} {reg1}, {reg2}, {shift}", "adc");
    781 }
    782 
    783 TEST_F(AssemblerArm32Test, Adcs) {
    784   T4Helper(&arm::Arm32Assembler::adcs, false, "adc{cond}s {reg1}, {reg2}, {shift}", "adcs");
    785 }
    786 
    787 TEST_F(AssemblerArm32Test, Sub) {
    788   T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub");
    789 }
    790 
    791 TEST_F(AssemblerArm32Test, Subs) {
    792   T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
    793 }
    794 
    795 TEST_F(AssemblerArm32Test, Sbc) {
    796   T5Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond}{s} {reg1}, {reg2}, {shift}", "sbc");
    797 }
    798 
    799 TEST_F(AssemblerArm32Test, Sbcs) {
    800   T4Helper(&arm::Arm32Assembler::sbcs, false, "sbc{cond}s {reg1}, {reg2}, {shift}", "sbcs");
    801 }
    802 
    803 TEST_F(AssemblerArm32Test, Rsb) {
    804   T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb");
    805 }
    806 
    807 TEST_F(AssemblerArm32Test, Rsbs) {
    808   T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
    809 }
    810 
    811 TEST_F(AssemblerArm32Test, Rsc) {
    812   T5Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond}{s} {reg1}, {reg2}, {shift}", "rsc");
    813 }
    814 
    815 TEST_F(AssemblerArm32Test, Rscs) {
    816   T4Helper(&arm::Arm32Assembler::rscs, false, "rsc{cond}s {reg1}, {reg2}, {shift}", "rscs");
    817 }
    818 
    819 /* TODO: Need better filter support.
    820 TEST_F(AssemblerArm32Test, Strex) {
    821   T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
    822            "{reg1}={reg2}||{reg1}={reg3}");  // Skip the cases where reg1 == reg2 || reg1 == reg3.
    823 }
    824 */
    825 
    826 TEST_F(AssemblerArm32Test, Clz) {
    827   T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
    828 }
    829 
    830 TEST_F(AssemblerArm32Test, Tst) {
    831   T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
    832 }
    833 
    834 TEST_F(AssemblerArm32Test, Teq) {
    835   T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
    836 }
    837 
    838 TEST_F(AssemblerArm32Test, Cmp) {
    839   T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
    840 }
    841 
    842 TEST_F(AssemblerArm32Test, Cmn) {
    843   T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
    844 }
    845 
    846 TEST_F(AssemblerArm32Test, Blx) {
    847   T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
    848 }
    849 
    850 TEST_F(AssemblerArm32Test, Bx) {
    851   T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
    852 }
    853 
    854 TEST_F(AssemblerArm32Test, Vmstat) {
    855   GetAssembler()->vmstat();
    856 
    857   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
    858 
    859   DriverStr(expected, "vmrs");
    860 }
    861 
    862 TEST_F(AssemblerArm32Test, ldrexd) {
    863   GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
    864   GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
    865   GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
    866 
    867   const char* expected =
    868       "ldrexd r0, r1, [r0]\n"
    869       "ldrexd r0, r1, [r1]\n"
    870       "ldrexd r0, r1, [r2]\n";
    871   DriverStr(expected, "ldrexd");
    872 }
    873 
    874 TEST_F(AssemblerArm32Test, strexd) {
    875   GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
    876   GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
    877   GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
    878 
    879   const char* expected =
    880       "strexd r9, r0, r1, [r0]\n"
    881       "strexd r9, r0, r1, [r1]\n"
    882       "strexd r9, r0, r1, [r2]\n";
    883   DriverStr(expected, "strexd");
    884 }
    885 
    886 TEST_F(AssemblerArm32Test, rbit) {
    887   T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit");
    888 }
    889 
    890 TEST_F(AssemblerArm32Test, rev) {
    891   T3Helper(&arm::Arm32Assembler::rev, true, "rev{cond} {reg1}, {reg2}", "rev");
    892 }
    893 
    894 TEST_F(AssemblerArm32Test, rev16) {
    895   T3Helper(&arm::Arm32Assembler::rev16, true, "rev16{cond} {reg1}, {reg2}", "rev16");
    896 }
    897 
    898 TEST_F(AssemblerArm32Test, revsh) {
    899   T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh");
    900 }
    901 
    902 }  // namespace art
    903