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