1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_UTILS_ASSEMBLER_TEST_H_ 18 #define ART_COMPILER_UTILS_ASSEMBLER_TEST_H_ 19 20 #include "assembler.h" 21 22 #include "assembler_test_base.h" 23 #include "common_runtime_test.h" // For ScratchFile 24 25 #include <cstdio> 26 #include <cstdlib> 27 #include <fstream> 28 #include <iterator> 29 #include <sys/stat.h> 30 31 namespace art { 32 33 // Helper for a constexpr string length. 34 constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) { 35 return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1); 36 } 37 38 enum class RegisterView { // private 39 kUsePrimaryName, 40 kUseSecondaryName, 41 kUseTertiaryName, 42 kUseQuaternaryName, 43 }; 44 45 template<typename Ass, typename Reg, typename FPReg, typename Imm> 46 class AssemblerTest : public testing::Test { 47 public: 48 Ass* GetAssembler() { 49 return assembler_.get(); 50 } 51 52 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler); 53 54 void DriverFn(TestFn f, std::string test_name) { 55 DriverWrapper(f(this, assembler_.get()), test_name); 56 } 57 58 // This driver assumes the assembler has already been called. 59 void DriverStr(std::string assembly_string, std::string test_name) { 60 DriverWrapper(assembly_string, test_name); 61 } 62 63 std::string RepeatR(void (Ass::*f)(Reg), std::string fmt) { 64 return RepeatTemplatedRegister<Reg>(f, 65 GetRegisters(), 66 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 67 fmt); 68 } 69 70 std::string Repeatr(void (Ass::*f)(Reg), std::string fmt) { 71 return RepeatTemplatedRegister<Reg>(f, 72 GetRegisters(), 73 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 74 fmt); 75 } 76 77 std::string RepeatRR(void (Ass::*f)(Reg, Reg), std::string fmt) { 78 return RepeatTemplatedRegisters<Reg, Reg>(f, 79 GetRegisters(), 80 GetRegisters(), 81 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 82 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 83 fmt); 84 } 85 86 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), std::string fmt) { 87 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f, 88 GetRegisters(), 89 GetRegisters(), 90 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 91 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 92 fmt); 93 } 94 95 std::string Repeatrr(void (Ass::*f)(Reg, Reg), std::string fmt) { 96 return RepeatTemplatedRegisters<Reg, Reg>(f, 97 GetRegisters(), 98 GetRegisters(), 99 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 100 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 101 fmt); 102 } 103 104 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), std::string fmt) { 105 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f, 106 GetRegisters(), 107 GetRegisters(), 108 GetRegisters(), 109 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 110 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 111 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 112 fmt); 113 } 114 115 std::string Repeatrb(void (Ass::*f)(Reg, Reg), std::string fmt) { 116 return RepeatTemplatedRegisters<Reg, Reg>(f, 117 GetRegisters(), 118 GetRegisters(), 119 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 120 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 121 fmt); 122 } 123 124 std::string RepeatRr(void (Ass::*f)(Reg, Reg), std::string fmt) { 125 return RepeatTemplatedRegisters<Reg, Reg>(f, 126 GetRegisters(), 127 GetRegisters(), 128 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 129 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 130 fmt); 131 } 132 133 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) { 134 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt); 135 } 136 137 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) { 138 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt); 139 } 140 141 template <typename Reg1, typename Reg2, typename ImmType> 142 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType), 143 int imm_bits, 144 const std::vector<Reg1*> reg1_registers, 145 const std::vector<Reg2*> reg2_registers, 146 std::string (AssemblerTest::*GetName1)(const Reg1&), 147 std::string (AssemblerTest::*GetName2)(const Reg2&), 148 std::string fmt) { 149 std::string str; 150 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 151 152 for (auto reg1 : reg1_registers) { 153 for (auto reg2 : reg2_registers) { 154 for (int64_t imm : imms) { 155 ImmType new_imm = CreateImmediate(imm); 156 (assembler_.get()->*f)(*reg1, *reg2, new_imm); 157 std::string base = fmt; 158 159 std::string reg1_string = (this->*GetName1)(*reg1); 160 size_t reg1_index; 161 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 162 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 163 } 164 165 std::string reg2_string = (this->*GetName2)(*reg2); 166 size_t reg2_index; 167 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 168 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 169 } 170 171 size_t imm_index = base.find(IMM_TOKEN); 172 if (imm_index != std::string::npos) { 173 std::ostringstream sreg; 174 sreg << imm; 175 std::string imm_string = sreg.str(); 176 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 177 } 178 179 if (str.size() > 0) { 180 str += "\n"; 181 } 182 str += base; 183 } 184 } 185 } 186 // Add a newline at the end. 187 str += "\n"; 188 return str; 189 } 190 191 template <typename ImmType, typename Reg1, typename Reg2> 192 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2), 193 const std::vector<Reg1*> reg1_registers, 194 const std::vector<Reg2*> reg2_registers, 195 std::string (AssemblerTest::*GetName1)(const Reg1&), 196 std::string (AssemblerTest::*GetName2)(const Reg2&), 197 int imm_bits, 198 std::string fmt) { 199 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 200 201 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); 202 203 std::string str; 204 for (auto reg1 : reg1_registers) { 205 for (auto reg2 : reg2_registers) { 206 for (int64_t imm : imms) { 207 ImmType new_imm = CreateImmediate(imm); 208 (assembler_.get()->*f)(new_imm, *reg1, *reg2); 209 std::string base = fmt; 210 211 std::string reg1_string = (this->*GetName1)(*reg1); 212 size_t reg1_index; 213 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 214 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 215 } 216 217 std::string reg2_string = (this->*GetName2)(*reg2); 218 size_t reg2_index; 219 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 220 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 221 } 222 223 size_t imm_index = base.find(IMM_TOKEN); 224 if (imm_index != std::string::npos) { 225 std::ostringstream sreg; 226 sreg << imm; 227 std::string imm_string = sreg.str(); 228 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 229 } 230 231 if (str.size() > 0) { 232 str += "\n"; 233 } 234 str += base; 235 } 236 } 237 } 238 // Add a newline at the end. 239 str += "\n"; 240 return str; 241 } 242 243 template <typename RegType, typename ImmType> 244 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType), 245 int imm_bits, 246 const std::vector<Reg*> registers, 247 std::string (AssemblerTest::*GetName)(const RegType&), 248 std::string fmt) { 249 std::string str; 250 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 251 252 for (auto reg : registers) { 253 for (int64_t imm : imms) { 254 ImmType new_imm = CreateImmediate(imm); 255 (assembler_.get()->*f)(*reg, new_imm); 256 std::string base = fmt; 257 258 std::string reg_string = (this->*GetName)(*reg); 259 size_t reg_index; 260 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 261 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 262 } 263 264 size_t imm_index = base.find(IMM_TOKEN); 265 if (imm_index != std::string::npos) { 266 std::ostringstream sreg; 267 sreg << imm; 268 std::string imm_string = sreg.str(); 269 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 270 } 271 272 if (str.size() > 0) { 273 str += "\n"; 274 } 275 str += base; 276 } 277 } 278 // Add a newline at the end. 279 str += "\n"; 280 return str; 281 } 282 283 template <typename ImmType> 284 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType), int imm_bits, std::string fmt) { 285 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f, 286 imm_bits, 287 GetRegisters(), 288 GetRegisters(), 289 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 290 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 291 fmt); 292 } 293 294 template <typename ImmType> 295 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt) { 296 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f, 297 imm_bits, 298 GetRegisters(), 299 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 300 fmt); 301 } 302 303 template <typename ImmType> 304 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType), int imm_bits, std::string fmt) { 305 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f, 306 imm_bits, 307 GetFPRegisters(), 308 GetRegisters(), 309 &AssemblerTest::GetFPRegName, 310 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 311 fmt); 312 } 313 314 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) { 315 return RepeatTemplatedRegisters<FPReg, FPReg>(f, 316 GetFPRegisters(), 317 GetFPRegisters(), 318 &AssemblerTest::GetFPRegName, 319 &AssemblerTest::GetFPRegName, 320 fmt); 321 } 322 323 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), std::string fmt) { 324 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f, 325 GetFPRegisters(), 326 GetFPRegisters(), 327 GetFPRegisters(), 328 &AssemblerTest::GetFPRegName, 329 &AssemblerTest::GetFPRegName, 330 &AssemblerTest::GetFPRegName, 331 fmt); 332 } 333 334 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&), 335 size_t imm_bytes, 336 std::string fmt) { 337 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f, 338 GetFPRegisters(), 339 GetFPRegisters(), 340 &AssemblerTest::GetFPRegName, 341 &AssemblerTest::GetFPRegName, 342 imm_bytes, 343 fmt); 344 } 345 346 template <typename ImmType> 347 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), int imm_bits, std::string fmt) { 348 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f, 349 GetFPRegisters(), 350 GetFPRegisters(), 351 &AssemblerTest::GetFPRegName, 352 &AssemblerTest::GetFPRegName, 353 imm_bits, 354 fmt); 355 } 356 357 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) { 358 return RepeatTemplatedRegisters<FPReg, Reg>(f, 359 GetFPRegisters(), 360 GetRegisters(), 361 &AssemblerTest::GetFPRegName, 362 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 363 fmt); 364 } 365 366 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), std::string fmt) { 367 return RepeatTemplatedRegisters<FPReg, Reg>(f, 368 GetFPRegisters(), 369 GetRegisters(), 370 &AssemblerTest::GetFPRegName, 371 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 372 fmt); 373 } 374 375 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) { 376 return RepeatTemplatedRegisters<Reg, FPReg>(f, 377 GetRegisters(), 378 GetFPRegisters(), 379 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 380 &AssemblerTest::GetFPRegName, 381 fmt); 382 } 383 384 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), std::string fmt) { 385 return RepeatTemplatedRegisters<Reg, FPReg>(f, 386 GetRegisters(), 387 GetFPRegisters(), 388 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 389 &AssemblerTest::GetFPRegName, 390 fmt); 391 } 392 393 std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt, 394 bool as_uint = false) { 395 std::string str; 396 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint); 397 398 WarnOnCombinations(imms.size()); 399 400 for (int64_t imm : imms) { 401 Imm new_imm = CreateImmediate(imm); 402 (assembler_.get()->*f)(new_imm); 403 std::string base = fmt; 404 405 size_t imm_index = base.find(IMM_TOKEN); 406 if (imm_index != std::string::npos) { 407 std::ostringstream sreg; 408 sreg << imm; 409 std::string imm_string = sreg.str(); 410 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 411 } 412 413 if (str.size() > 0) { 414 str += "\n"; 415 } 416 str += base; 417 } 418 // Add a newline at the end. 419 str += "\n"; 420 return str; 421 } 422 423 // This is intended to be run as a test. 424 bool CheckTools() { 425 return test_helper_->CheckTools(); 426 } 427 428 // The following functions are public so that TestFn can use them... 429 430 virtual std::vector<Reg*> GetRegisters() = 0; 431 432 virtual std::vector<FPReg*> GetFPRegisters() { 433 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers"; 434 UNREACHABLE(); 435 } 436 437 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems. 438 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 439 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers"; 440 UNREACHABLE(); 441 } 442 443 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems. 444 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 445 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers"; 446 UNREACHABLE(); 447 } 448 449 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems. 450 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 451 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers"; 452 UNREACHABLE(); 453 } 454 455 std::string GetRegisterName(const Reg& reg) { 456 return GetRegName<RegisterView::kUsePrimaryName>(reg); 457 } 458 459 protected: 460 explicit AssemblerTest() {} 461 462 void SetUp() OVERRIDE { 463 arena_.reset(new ArenaAllocator(&pool_)); 464 assembler_.reset(new (arena_.get()) Ass(arena_.get())); 465 test_helper_.reset( 466 new AssemblerTestInfrastructure(GetArchitectureString(), 467 GetAssemblerCmdName(), 468 GetAssemblerParameters(), 469 GetObjdumpCmdName(), 470 GetObjdumpParameters(), 471 GetDisassembleCmdName(), 472 GetDisassembleParameters(), 473 GetAssemblyHeader())); 474 475 SetUpHelpers(); 476 } 477 478 void TearDown() OVERRIDE { 479 test_helper_.reset(); // Clean up the helper. 480 assembler_.reset(); 481 arena_.reset(); 482 } 483 484 // Override this to set up any architecture-specific things, e.g., register vectors. 485 virtual void SetUpHelpers() {} 486 487 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ... 488 virtual std::string GetArchitectureString() = 0; 489 490 // Get the name of the assembler, e.g., "as" by default. 491 virtual std::string GetAssemblerCmdName() { 492 return "as"; 493 } 494 495 // Switches to the assembler command. Default none. 496 virtual std::string GetAssemblerParameters() { 497 return ""; 498 } 499 500 // Get the name of the objdump, e.g., "objdump" by default. 501 virtual std::string GetObjdumpCmdName() { 502 return "objdump"; 503 } 504 505 // Switches to the objdump command. Default is " -h". 506 virtual std::string GetObjdumpParameters() { 507 return " -h"; 508 } 509 510 // Get the name of the objdump, e.g., "objdump" by default. 511 virtual std::string GetDisassembleCmdName() { 512 return "objdump"; 513 } 514 515 // Switches to the objdump command. As it's a binary, one needs to push the architecture and 516 // such to objdump, so it's architecture-specific and there is no default. 517 virtual std::string GetDisassembleParameters() = 0; 518 519 // Create a couple of immediate values up to the number of bytes given. 520 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) { 521 std::vector<int64_t> res; 522 res.push_back(0); 523 if (!as_uint) { 524 res.push_back(-1); 525 } else { 526 res.push_back(0xFF); 527 } 528 res.push_back(0x12); 529 if (imm_bytes >= 2) { 530 res.push_back(0x1234); 531 if (!as_uint) { 532 res.push_back(-0x1234); 533 } else { 534 res.push_back(0xFFFF); 535 } 536 if (imm_bytes >= 4) { 537 res.push_back(0x12345678); 538 if (!as_uint) { 539 res.push_back(-0x12345678); 540 } else { 541 res.push_back(0xFFFFFFFF); 542 } 543 if (imm_bytes >= 6) { 544 res.push_back(0x123456789ABC); 545 if (!as_uint) { 546 res.push_back(-0x123456789ABC); 547 } 548 if (imm_bytes >= 8) { 549 res.push_back(0x123456789ABCDEF0); 550 if (!as_uint) { 551 res.push_back(-0x123456789ABCDEF0); 552 } else { 553 res.push_back(0xFFFFFFFFFFFFFFFF); 554 } 555 } 556 } 557 } 558 } 559 return res; 560 } 561 562 const int kMaxBitsExhaustiveTest = 8; 563 564 // Create a couple of immediate values up to the number of bits given. 565 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) { 566 CHECK_GT(imm_bits, 0); 567 CHECK_LE(imm_bits, 64); 568 std::vector<int64_t> res; 569 570 if (imm_bits <= kMaxBitsExhaustiveTest) { 571 if (as_uint) { 572 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) { 573 res.push_back(static_cast<int64_t>(i)); 574 } 575 } else { 576 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) { 577 res.push_back(i); 578 } 579 } 580 } else { 581 if (as_uint) { 582 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest); 583 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest); 584 i++) { 585 res.push_back(static_cast<int64_t>(i)); 586 } 587 for (int i = 0; i <= imm_bits; i++) { 588 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) + 589 ((MaxInt<uint64_t>(imm_bits) - 590 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1)) 591 * i / imm_bits); 592 res.push_back(static_cast<int64_t>(j)); 593 } 594 } else { 595 for (int i = 0; i <= imm_bits; i++) { 596 int64_t j = MinInt<int64_t>(imm_bits) + 597 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) - 598 MinInt<int64_t>(imm_bits)) 599 * i) / imm_bits); 600 res.push_back(static_cast<int64_t>(j)); 601 } 602 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest); 603 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest); 604 i++) { 605 res.push_back(static_cast<int64_t>(i)); 606 } 607 for (int i = 0; i <= imm_bits; i++) { 608 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) + 609 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1)) 610 * i / imm_bits); 611 res.push_back(static_cast<int64_t>(j)); 612 } 613 } 614 } 615 616 return res; 617 } 618 619 // Create an immediate from the specific value. 620 virtual Imm CreateImmediate(int64_t imm_value) = 0; 621 622 template <typename RegType> 623 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType), 624 const std::vector<RegType*> registers, 625 std::string (AssemblerTest::*GetName)(const RegType&), 626 std::string fmt) { 627 std::string str; 628 for (auto reg : registers) { 629 (assembler_.get()->*f)(*reg); 630 std::string base = fmt; 631 632 std::string reg_string = (this->*GetName)(*reg); 633 size_t reg_index; 634 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 635 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 636 } 637 638 if (str.size() > 0) { 639 str += "\n"; 640 } 641 str += base; 642 } 643 // Add a newline at the end. 644 str += "\n"; 645 return str; 646 } 647 648 template <typename Reg1, typename Reg2> 649 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2), 650 const std::vector<Reg1*> reg1_registers, 651 const std::vector<Reg2*> reg2_registers, 652 std::string (AssemblerTest::*GetName1)(const Reg1&), 653 std::string (AssemblerTest::*GetName2)(const Reg2&), 654 std::string fmt) { 655 WarnOnCombinations(reg1_registers.size() * reg2_registers.size()); 656 657 std::string str; 658 for (auto reg1 : reg1_registers) { 659 for (auto reg2 : reg2_registers) { 660 (assembler_.get()->*f)(*reg1, *reg2); 661 std::string base = fmt; 662 663 std::string reg1_string = (this->*GetName1)(*reg1); 664 size_t reg1_index; 665 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 666 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 667 } 668 669 std::string reg2_string = (this->*GetName2)(*reg2); 670 size_t reg2_index; 671 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 672 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 673 } 674 675 if (str.size() > 0) { 676 str += "\n"; 677 } 678 str += base; 679 } 680 } 681 // Add a newline at the end. 682 str += "\n"; 683 return str; 684 } 685 686 template <typename Reg1, typename Reg2> 687 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2), 688 const std::vector<Reg1*> reg1_registers, 689 const std::vector<Reg2*> reg2_registers, 690 std::string (AssemblerTest::*GetName1)(const Reg1&), 691 std::string (AssemblerTest::*GetName2)(const Reg2&), 692 std::string fmt) { 693 WarnOnCombinations(reg1_registers.size() * reg2_registers.size()); 694 695 std::string str; 696 for (auto reg1 : reg1_registers) { 697 for (auto reg2 : reg2_registers) { 698 if (reg1 == reg2) continue; 699 (assembler_.get()->*f)(*reg1, *reg2); 700 std::string base = fmt; 701 702 std::string reg1_string = (this->*GetName1)(*reg1); 703 size_t reg1_index; 704 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 705 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 706 } 707 708 std::string reg2_string = (this->*GetName2)(*reg2); 709 size_t reg2_index; 710 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 711 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 712 } 713 714 if (str.size() > 0) { 715 str += "\n"; 716 } 717 str += base; 718 } 719 } 720 // Add a newline at the end. 721 str += "\n"; 722 return str; 723 } 724 725 template <typename Reg1, typename Reg2, typename Reg3> 726 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3), 727 const std::vector<Reg1*> reg1_registers, 728 const std::vector<Reg2*> reg2_registers, 729 const std::vector<Reg3*> reg3_registers, 730 std::string (AssemblerTest::*GetName1)(const Reg1&), 731 std::string (AssemblerTest::*GetName2)(const Reg2&), 732 std::string (AssemblerTest::*GetName3)(const Reg3&), 733 std::string fmt) { 734 std::string str; 735 for (auto reg1 : reg1_registers) { 736 for (auto reg2 : reg2_registers) { 737 for (auto reg3 : reg3_registers) { 738 (assembler_.get()->*f)(*reg1, *reg2, *reg3); 739 std::string base = fmt; 740 741 std::string reg1_string = (this->*GetName1)(*reg1); 742 size_t reg1_index; 743 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 744 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 745 } 746 747 std::string reg2_string = (this->*GetName2)(*reg2); 748 size_t reg2_index; 749 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 750 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 751 } 752 753 std::string reg3_string = (this->*GetName3)(*reg3); 754 size_t reg3_index; 755 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) { 756 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); 757 } 758 759 if (str.size() > 0) { 760 str += "\n"; 761 } 762 str += base; 763 } 764 } 765 } 766 // Add a newline at the end. 767 str += "\n"; 768 return str; 769 } 770 771 template <typename Reg1, typename Reg2> 772 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&), 773 const std::vector<Reg1*> reg1_registers, 774 const std::vector<Reg2*> reg2_registers, 775 std::string (AssemblerTest::*GetName1)(const Reg1&), 776 std::string (AssemblerTest::*GetName2)(const Reg2&), 777 size_t imm_bytes, 778 std::string fmt) { 779 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 780 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); 781 782 std::string str; 783 for (auto reg1 : reg1_registers) { 784 for (auto reg2 : reg2_registers) { 785 for (int64_t imm : imms) { 786 Imm new_imm = CreateImmediate(imm); 787 (assembler_.get()->*f)(*reg1, *reg2, new_imm); 788 std::string base = fmt; 789 790 std::string reg1_string = (this->*GetName1)(*reg1); 791 size_t reg1_index; 792 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 793 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 794 } 795 796 std::string reg2_string = (this->*GetName2)(*reg2); 797 size_t reg2_index; 798 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 799 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 800 } 801 802 size_t imm_index = base.find(IMM_TOKEN); 803 if (imm_index != std::string::npos) { 804 std::ostringstream sreg; 805 sreg << imm; 806 std::string imm_string = sreg.str(); 807 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 808 } 809 810 if (str.size() > 0) { 811 str += "\n"; 812 } 813 str += base; 814 } 815 } 816 } 817 // Add a newline at the end. 818 str += "\n"; 819 return str; 820 } 821 822 template <RegisterView kRegView> 823 std::string GetRegName(const Reg& reg) { 824 std::ostringstream sreg; 825 switch (kRegView) { 826 case RegisterView::kUsePrimaryName: 827 sreg << reg; 828 break; 829 830 case RegisterView::kUseSecondaryName: 831 sreg << GetSecondaryRegisterName(reg); 832 break; 833 834 case RegisterView::kUseTertiaryName: 835 sreg << GetTertiaryRegisterName(reg); 836 break; 837 838 case RegisterView::kUseQuaternaryName: 839 sreg << GetQuaternaryRegisterName(reg); 840 break; 841 } 842 return sreg.str(); 843 } 844 845 std::string GetFPRegName(const FPReg& reg) { 846 std::ostringstream sreg; 847 sreg << reg; 848 return sreg.str(); 849 } 850 851 // If the assembly file needs a header, return it in a sub-class. 852 virtual const char* GetAssemblyHeader() { 853 return nullptr; 854 } 855 856 void WarnOnCombinations(size_t count) { 857 if (count > kWarnManyCombinationsThreshold) { 858 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow."; 859 } 860 } 861 862 static constexpr const char* REG_TOKEN = "{reg}"; 863 static constexpr const char* REG1_TOKEN = "{reg1}"; 864 static constexpr const char* REG2_TOKEN = "{reg2}"; 865 static constexpr const char* REG3_TOKEN = "{reg3}"; 866 static constexpr const char* IMM_TOKEN = "{imm}"; 867 868 private: 869 template <RegisterView kRegView> 870 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, 871 std::string fmt) { 872 const std::vector<Reg*> registers = GetRegisters(); 873 std::string str; 874 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 875 876 WarnOnCombinations(registers.size() * imms.size()); 877 878 for (auto reg : registers) { 879 for (int64_t imm : imms) { 880 Imm new_imm = CreateImmediate(imm); 881 (assembler_.get()->*f)(*reg, new_imm); 882 std::string base = fmt; 883 884 std::string reg_string = GetRegName<kRegView>(*reg); 885 size_t reg_index; 886 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 887 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 888 } 889 890 size_t imm_index = base.find(IMM_TOKEN); 891 if (imm_index != std::string::npos) { 892 std::ostringstream sreg; 893 sreg << imm; 894 std::string imm_string = sreg.str(); 895 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 896 } 897 898 if (str.size() > 0) { 899 str += "\n"; 900 } 901 str += base; 902 } 903 } 904 // Add a newline at the end. 905 str += "\n"; 906 return str; 907 } 908 909 // Override this to pad the code with NOPs to a certain size if needed. 910 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) { 911 } 912 913 void DriverWrapper(std::string assembly_text, std::string test_name) { 914 assembler_->FinalizeCode(); 915 size_t cs = assembler_->CodeSize(); 916 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs)); 917 MemoryRegion code(&(*data)[0], data->size()); 918 assembler_->FinalizeInstructions(code); 919 Pad(*data); 920 test_helper_->Driver(*data, assembly_text, test_name); 921 } 922 923 static constexpr size_t kWarnManyCombinationsThreshold = 500; 924 925 ArenaPool pool_; 926 std::unique_ptr<ArenaAllocator> arena_; 927 std::unique_ptr<Ass> assembler_; 928 std::unique_ptr<AssemblerTestInfrastructure> test_helper_; 929 930 DISALLOW_COPY_AND_ASSIGN(AssemblerTest); 931 }; 932 933 } // namespace art 934 935 #endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_ 936