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(®isters_); 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