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  protected:
     47   std::string GetArchitectureString() OVERRIDE {
     48     return "arm";
     49   }
     50 
     51   std::string GetAssemblerParameters() OVERRIDE {
     52     // Arm-v7a, cortex-a15 (means we have sdiv).
     53     return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
     54   }
     55 
     56   const char* GetAssemblyHeader() OVERRIDE {
     57     return kArm32AssemblyHeader;
     58   }
     59 
     60   std::string GetDisassembleParameters() OVERRIDE {
     61     return " -D -bbinary -marm --no-show-raw-insn";
     62   }
     63 
     64   void SetUpHelpers() OVERRIDE {
     65     if (registers_.size() == 0) {
     66       if (kUseSparseRegisterList) {
     67         registers_.insert(end(registers_),
     68                           {  // NOLINT(whitespace/braces)
     69                               new arm::Register(arm::R0),
     70                               new arm::Register(arm::R1),
     71                               new arm::Register(arm::R4),
     72                               new arm::Register(arm::R8),
     73                               new arm::Register(arm::R11),
     74                               new arm::Register(arm::R12),
     75                               new arm::Register(arm::R13),
     76                               new arm::Register(arm::R14),
     77                               new arm::Register(arm::R15)
     78                           });
     79       } else {
     80         registers_.insert(end(registers_),
     81                           {  // NOLINT(whitespace/braces)
     82                               new arm::Register(arm::R0),
     83                               new arm::Register(arm::R1),
     84                               new arm::Register(arm::R2),
     85                               new arm::Register(arm::R3),
     86                               new arm::Register(arm::R4),
     87                               new arm::Register(arm::R5),
     88                               new arm::Register(arm::R6),
     89                               new arm::Register(arm::R7),
     90                               new arm::Register(arm::R8),
     91                               new arm::Register(arm::R9),
     92                               new arm::Register(arm::R10),
     93                               new arm::Register(arm::R11),
     94                               new arm::Register(arm::R12),
     95                               new arm::Register(arm::R13),
     96                               new arm::Register(arm::R14),
     97                               new arm::Register(arm::R15)
     98                           });
     99       }
    100     }
    101 
    102     if (!kUseSparseConditionList) {
    103       conditions_.push_back(arm::Condition::EQ);
    104       conditions_.push_back(arm::Condition::NE);
    105       conditions_.push_back(arm::Condition::CS);
    106       conditions_.push_back(arm::Condition::CC);
    107       conditions_.push_back(arm::Condition::MI);
    108       conditions_.push_back(arm::Condition::PL);
    109       conditions_.push_back(arm::Condition::VS);
    110       conditions_.push_back(arm::Condition::VC);
    111       conditions_.push_back(arm::Condition::HI);
    112       conditions_.push_back(arm::Condition::LS);
    113       conditions_.push_back(arm::Condition::GE);
    114       conditions_.push_back(arm::Condition::LT);
    115       conditions_.push_back(arm::Condition::GT);
    116       conditions_.push_back(arm::Condition::LE);
    117       conditions_.push_back(arm::Condition::AL);
    118     } else {
    119       conditions_.push_back(arm::Condition::EQ);
    120       conditions_.push_back(arm::Condition::NE);
    121       conditions_.push_back(arm::Condition::CC);
    122       conditions_.push_back(arm::Condition::VC);
    123       conditions_.push_back(arm::Condition::HI);
    124       conditions_.push_back(arm::Condition::LT);
    125       conditions_.push_back(arm::Condition::AL);
    126     }
    127 
    128     shifter_operands_.push_back(arm::ShifterOperand(0));
    129     shifter_operands_.push_back(arm::ShifterOperand(1));
    130     shifter_operands_.push_back(arm::ShifterOperand(2));
    131     shifter_operands_.push_back(arm::ShifterOperand(3));
    132     shifter_operands_.push_back(arm::ShifterOperand(4));
    133     shifter_operands_.push_back(arm::ShifterOperand(5));
    134     shifter_operands_.push_back(arm::ShifterOperand(127));
    135     shifter_operands_.push_back(arm::ShifterOperand(128));
    136     shifter_operands_.push_back(arm::ShifterOperand(254));
    137     shifter_operands_.push_back(arm::ShifterOperand(255));
    138 
    139     if (!kUseSparseRegisterList) {
    140       shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
    141       shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
    142       shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
    143       shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
    144       shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
    145       shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
    146       shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
    147       shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
    148       shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
    149       shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
    150       shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
    151       shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
    152       shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
    153       shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
    154     } else {
    155       shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
    156       shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
    157       shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
    158       shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
    159       shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
    160       shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
    161       shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
    162     }
    163 
    164     std::vector<arm::Shift> shifts {
    165       arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
    166     };
    167 
    168     // ShifterOperands of form "reg shift-type imm."
    169     for (arm::Shift shift : shifts) {
    170       for (arm::Register* reg : registers_) {  // Note: this will pick up the sparse set.
    171         if (*reg == arm::R15) {  // Skip PC.
    172           continue;
    173         }
    174         if (shift != arm::Shift::RRX) {
    175           if (!kUseSparseShiftImmediates) {
    176             for (uint32_t imm = 1; imm < 32; ++imm) {
    177               shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
    178             }
    179           } else {
    180             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
    181             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
    182             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
    183             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
    184             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
    185             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
    186             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
    187             shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
    188           }
    189         } else {
    190           // RRX doesn't have an immediate.
    191           shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
    192         }
    193       }
    194     }
    195   }
    196 
    197   std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
    198                                                         int32_t shift_min, int32_t shift_max) {
    199     std::vector<arm::ShifterOperand> res;
    200     static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
    201                                               arm::Shift::ROR };
    202 
    203     for (arm::Shift shift : kShifts) {
    204       for (arm::Register* reg : base_regs) {
    205         // Take the min, the max, and three values in between.
    206         res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
    207         if (shift_min != shift_max) {
    208           res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
    209           int32_t middle = (shift_min + shift_max) / 2;
    210           res.push_back(arm::ShifterOperand(*reg, shift, middle));
    211           res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
    212           res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
    213         }
    214       }
    215     }
    216 
    217     return res;
    218   }
    219 
    220   void TearDown() OVERRIDE {
    221     AssemblerArmTest::TearDown();
    222     STLDeleteElements(&registers_);
    223   }
    224 
    225   std::vector<arm::Register*> GetRegisters() OVERRIDE {
    226     return registers_;
    227   }
    228 
    229   uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
    230     return imm_value;
    231   }
    232 
    233   std::vector<arm::Condition>& GetConditions() OVERRIDE {
    234     return conditions_;
    235   }
    236 
    237   std::string GetConditionString(arm::Condition c) OVERRIDE {
    238     std::ostringstream oss;
    239     oss << c;
    240     return oss.str();
    241   }
    242 
    243   arm::Register GetPCRegister() OVERRIDE {
    244     return arm::R15;
    245   }
    246 
    247   std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
    248     return shifter_operands_;
    249   }
    250 
    251   std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
    252     std::ostringstream oss;
    253     if (sop.IsShift()) {
    254       // Not a rotate...
    255       if (sop.GetShift() == arm::Shift::RRX) {
    256         oss << sop.GetRegister() << ", " << sop.GetShift();
    257       } else {
    258         oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
    259       }
    260     } else if (sop.IsRegister()) {
    261       oss << sop.GetRegister();
    262     } else {
    263       CHECK(sop.IsImmediate());
    264       oss << "#" << sop.GetImmediate();
    265     }
    266     return oss.str();
    267   }
    268 
    269   static const char* GetRegTokenFromDepth(int depth) {
    270     switch (depth) {
    271       case 0:
    272         return Base::REG1_TOKEN;
    273       case 1:
    274         return Base::REG2_TOKEN;
    275       case 2:
    276         return REG3_TOKEN;
    277       case 3:
    278         return REG4_TOKEN;
    279       default:
    280         LOG(FATAL) << "Depth problem.";
    281         UNREACHABLE();
    282     }
    283   }
    284 
    285   void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
    286     if (first_) {
    287       first_ = false;
    288     } else {
    289       oss << "\n";
    290     }
    291     oss << fmt;
    292 
    293     f();
    294   }
    295 
    296   void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
    297                       bool without_pc,
    298                       std::string fmt, std::ostringstream& oss) {
    299     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
    300     for (auto reg : registers) {
    301       std::string after_reg = fmt;
    302 
    303       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
    304       size_t reg_index;
    305       const char* reg_token = GetRegTokenFromDepth(depth);
    306 
    307       while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
    308         after_reg.replace(reg_index, strlen(reg_token), reg_string);
    309       }
    310 
    311       ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
    312     }
    313   }
    314 
    315   void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
    316                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
    317     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
    318       std::string after_shift = fmt;
    319 
    320       std::string shift_string = GetShiftString(shift);
    321       size_t shift_index;
    322       while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
    323         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    324       }
    325 
    326       ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
    327     }
    328   }
    329 
    330   void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
    331                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
    332     for (arm::Condition c : GetConditions()) {
    333       std::string after_cond = fmt;
    334 
    335       size_t cond_index = after_cond.find(COND_TOKEN);
    336       if (cond_index != std::string::npos) {
    337         after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
    338       }
    339 
    340       ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
    341     }
    342   }
    343 
    344   template <typename... Args>
    345   void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
    346                       std::string fmt, std::ostringstream& oss) {
    347     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
    348     for (auto reg : registers) {
    349       std::string after_reg = fmt;
    350 
    351       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
    352       size_t reg_index;
    353       const char* reg_token = GetRegTokenFromDepth(depth);
    354 
    355       while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
    356         after_reg.replace(reg_index, strlen(reg_token), reg_string);
    357       }
    358 
    359       auto lambda = [&] (Args... args) { f(*reg, args...); };  // NOLINT [readability/braces] [4]
    360       TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
    361           after_reg, oss);
    362     }
    363   }
    364 
    365   template <typename... Args>
    366   void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
    367                       bool without_pc, std::string fmt, std::ostringstream& oss) {
    368     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
    369       std::string after_shift = fmt;
    370 
    371       std::string shift_string = GetShiftString(shift);
    372       size_t shift_index;
    373       while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
    374         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
    375       }
    376 
    377       auto lambda = [&] (Args... args) { f(shift, args...); };  // NOLINT [readability/braces] [4]
    378       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
    379           after_shift, oss);
    380     }
    381   }
    382 
    383   template <typename... Args>
    384   void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
    385                       std::string fmt, std::ostringstream& oss) {
    386     for (arm::Condition c : GetConditions()) {
    387       std::string after_cond = fmt;
    388 
    389       size_t cond_index = after_cond.find(COND_TOKEN);
    390       if (cond_index != std::string::npos) {
    391         after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
    392       }
    393 
    394       auto lambda = [&] (Args... args) { f(c, args...); };  // NOLINT [readability/braces] [4]
    395       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
    396           after_cond, oss);
    397     }
    398   }
    399 
    400   template <typename T1, typename T2>
    401   std::function<void(T1, T2)> GetBoundFunction2(void (arm::Arm32Assembler::*f)(T1, T2)) {
    402     return std::bind(f, GetAssembler(), _1, _2);
    403   }
    404 
    405   template <typename T1, typename T2, typename T3>
    406   std::function<void(T1, T2, T3)> GetBoundFunction3(void (arm::Arm32Assembler::*f)(T1, T2, T3)) {
    407     return std::bind(f, GetAssembler(), _1, _2, _3);
    408   }
    409 
    410   template <typename T1, typename T2, typename T3, typename T4>
    411   std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
    412       void (arm::Arm32Assembler::*f)(T1, T2, T3, T4)) {
    413     return std::bind(f, GetAssembler(), _1, _2, _3, _4);
    414   }
    415 
    416   template <typename T1, typename T2, typename T3, typename T4, typename T5>
    417   std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
    418       void (arm::Arm32Assembler::*f)(T1, T2, T3, T4, T5)) {
    419     return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
    420   }
    421 
    422   template <typename... Args>
    423   void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
    424                              std::string fmt, std::string test_name) {
    425     first_ = false;
    426     WarnOnCombinations(CountHelper<Args...>(without_pc));
    427 
    428     std::ostringstream oss;
    429 
    430     TemplateHelper(f, 0, without_pc, fmt, oss);
    431 
    432     oss << "\n";  // Trailing newline.
    433 
    434     DriverStr(oss.str(), test_name);
    435   }
    436 
    437   template <typename... Args>
    438   void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
    439                 std::string test_name) {
    440     GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
    441   }
    442 
    443   template <typename... Args>
    444   void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
    445       std::string test_name) {
    446     GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
    447   }
    448 
    449   template <typename... Args>
    450   void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
    451       std::string test_name) {
    452     GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
    453   }
    454 
    455   template <typename... Args>
    456   void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
    457       std::string test_name) {
    458     GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
    459   }
    460 
    461  private:
    462   template <typename T>
    463   size_t CountHelper(bool without_pc) {
    464     size_t tmp;
    465     if (std::is_same<T, arm::Register>::value) {
    466       tmp = GetRegisters().size();
    467       if (without_pc) {
    468         tmp--;;  // Approximation...
    469       }
    470       return tmp;
    471     } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
    472       return GetShiftOperands().size();
    473     } else if (std::is_same<T, arm::Condition>::value) {
    474       return GetConditions().size();
    475     } else {
    476       LOG(WARNING) << "Unknown type while counting.";
    477       return 1;
    478     }
    479   }
    480 
    481   template <typename T1, typename T2, typename... Args>
    482   size_t CountHelper(bool without_pc) {
    483     size_t tmp;
    484     if (std::is_same<T1, arm::Register>::value) {
    485       tmp = GetRegisters().size();
    486       if (without_pc) {
    487         tmp--;;  // Approximation...
    488       }
    489     } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
    490       tmp =  GetShiftOperands().size();
    491     } else if (std::is_same<T1, arm::Condition>::value) {
    492       tmp = GetConditions().size();
    493     } else {
    494       LOG(WARNING) << "Unknown type while counting.";
    495       tmp = 1;
    496     }
    497     size_t rec = CountHelper<T2, Args...>(without_pc);
    498     return rec * tmp;
    499   }
    500 
    501   bool first_;
    502 
    503   static constexpr const char* kArm32AssemblyHeader = ".arm\n";
    504 
    505   std::vector<arm::Register*> registers_;
    506   std::vector<arm::Condition> conditions_;
    507   std::vector<arm::ShifterOperand> shifter_operands_;
    508 };
    509 
    510 
    511 TEST_F(AssemblerArm32Test, Toolchain) {
    512   EXPECT_TRUE(CheckTools());
    513 }
    514 
    515 TEST_F(AssemblerArm32Test, Sbfx) {
    516   std::vector<std::pair<uint32_t, uint32_t>> immediates;
    517   immediates.push_back({0, 1});
    518   immediates.push_back({0, 8});
    519   immediates.push_back({0, 15});
    520   immediates.push_back({0, 16});
    521   immediates.push_back({0, 31});
    522   immediates.push_back({0, 32});
    523 
    524   immediates.push_back({1, 1});
    525   immediates.push_back({1, 15});
    526   immediates.push_back({1, 31});
    527 
    528   immediates.push_back({8, 1});
    529   immediates.push_back({8, 15});
    530   immediates.push_back({8, 16});
    531   immediates.push_back({8, 24});
    532 
    533   immediates.push_back({31, 1});
    534 
    535   DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
    536                         "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
    537 }
    538 
    539 TEST_F(AssemblerArm32Test, Ubfx) {
    540   std::vector<std::pair<uint32_t, uint32_t>> immediates;
    541   immediates.push_back({0, 1});
    542   immediates.push_back({0, 8});
    543   immediates.push_back({0, 15});
    544   immediates.push_back({0, 16});
    545   immediates.push_back({0, 31});
    546   immediates.push_back({0, 32});
    547 
    548   immediates.push_back({1, 1});
    549   immediates.push_back({1, 15});
    550   immediates.push_back({1, 31});
    551 
    552   immediates.push_back({8, 1});
    553   immediates.push_back({8, 15});
    554   immediates.push_back({8, 16});
    555   immediates.push_back({8, 24});
    556 
    557   immediates.push_back({31, 1});
    558 
    559   DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
    560                         "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
    561 }
    562 
    563 TEST_F(AssemblerArm32Test, Mul) {
    564   T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
    565 }
    566 
    567 TEST_F(AssemblerArm32Test, Mla) {
    568   T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
    569 }
    570 
    571 /* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
    572 TEST_F(AssemblerArm32Test, Umull) {
    573   T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
    574            "umull");
    575 }
    576 */
    577 
    578 TEST_F(AssemblerArm32Test, Sdiv) {
    579   T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
    580 }
    581 
    582 TEST_F(AssemblerArm32Test, Udiv) {
    583   T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
    584 }
    585 
    586 TEST_F(AssemblerArm32Test, And) {
    587   T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and");
    588 }
    589 
    590 TEST_F(AssemblerArm32Test, Eor) {
    591   T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor");
    592 }
    593 
    594 TEST_F(AssemblerArm32Test, Orr) {
    595   T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr");
    596 }
    597 
    598 TEST_F(AssemblerArm32Test, Orrs) {
    599   T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
    600 }
    601 
    602 TEST_F(AssemblerArm32Test, Bic) {
    603   T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic");
    604 }
    605 
    606 TEST_F(AssemblerArm32Test, Mov) {
    607   T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov");
    608 }
    609 
    610 TEST_F(AssemblerArm32Test, Movs) {
    611   T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
    612 }
    613 
    614 TEST_F(AssemblerArm32Test, Mvn) {
    615   T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn");
    616 }
    617 
    618 TEST_F(AssemblerArm32Test, Mvns) {
    619   T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
    620 }
    621 
    622 TEST_F(AssemblerArm32Test, Add) {
    623   T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add");
    624 }
    625 
    626 TEST_F(AssemblerArm32Test, Adds) {
    627   T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
    628 }
    629 
    630 TEST_F(AssemblerArm32Test, Adc) {
    631   T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc");
    632 }
    633 
    634 TEST_F(AssemblerArm32Test, Sub) {
    635   T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub");
    636 }
    637 
    638 TEST_F(AssemblerArm32Test, Subs) {
    639   T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
    640 }
    641 
    642 TEST_F(AssemblerArm32Test, Sbc) {
    643   T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc");
    644 }
    645 
    646 TEST_F(AssemblerArm32Test, Rsb) {
    647   T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb");
    648 }
    649 
    650 TEST_F(AssemblerArm32Test, Rsbs) {
    651   T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
    652 }
    653 
    654 TEST_F(AssemblerArm32Test, Rsc) {
    655   T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
    656 }
    657 
    658 /* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
    659 TEST_F(AssemblerArm32Test, Strex) {
    660   RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
    661 }
    662 */
    663 
    664 TEST_F(AssemblerArm32Test, Clz) {
    665   T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
    666 }
    667 
    668 TEST_F(AssemblerArm32Test, Tst) {
    669   T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
    670 }
    671 
    672 TEST_F(AssemblerArm32Test, Teq) {
    673   T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
    674 }
    675 
    676 TEST_F(AssemblerArm32Test, Cmp) {
    677   T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
    678 }
    679 
    680 TEST_F(AssemblerArm32Test, Cmn) {
    681   T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
    682 }
    683 
    684 TEST_F(AssemblerArm32Test, Blx) {
    685   T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
    686 }
    687 
    688 TEST_F(AssemblerArm32Test, Bx) {
    689   T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
    690 }
    691 
    692 TEST_F(AssemblerArm32Test, Vmstat) {
    693   GetAssembler()->vmstat();
    694 
    695   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
    696 
    697   DriverStr(expected, "vmrs");
    698 }
    699 
    700 TEST_F(AssemblerArm32Test, ldrexd) {
    701   GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
    702   GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
    703   GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
    704 
    705   const char* expected =
    706       "ldrexd r0, r1, [r0]\n"
    707       "ldrexd r0, r1, [r1]\n"
    708       "ldrexd r0, r1, [r2]\n";
    709   DriverStr(expected, "ldrexd");
    710 }
    711 
    712 TEST_F(AssemblerArm32Test, strexd) {
    713   GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
    714   GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
    715   GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
    716 
    717   const char* expected =
    718       "strexd r9, r0, r1, [r0]\n"
    719       "strexd r9, r0, r1, [r1]\n"
    720       "strexd r9, r0, r1, [r2]\n";
    721   DriverStr(expected, "strexd");
    722 }
    723 
    724 }  // namespace art
    725