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_ARM_ASSEMBLER_ARM_TEST_H_ 18 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_ 19 20 #include "utils/assembler_test.h" 21 22 namespace art { 23 24 template<typename Ass, typename Reg, typename FPReg, typename Imm, typename SOp, typename Cond> 25 class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { 26 public: 27 typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base; 28 29 using Base::GetRegisters; 30 using Base::GetRegName; 31 using Base::CreateImmediate; 32 using Base::WarnOnCombinations; 33 34 static constexpr int64_t kFullImmRangeThreshold = 32; 35 36 virtual void FillImmediates(std::vector<Imm>& immediates, int64_t imm_min, int64_t imm_max) { 37 // Small range: do completely. 38 if (imm_max - imm_min <= kFullImmRangeThreshold) { 39 for (int64_t i = imm_min; i <= imm_max; ++i) { 40 immediates.push_back(CreateImmediate(i)); 41 } 42 } else { 43 immediates.push_back(CreateImmediate(imm_min)); 44 immediates.push_back(CreateImmediate(imm_max)); 45 if (imm_min < imm_max - 1) { 46 immediates.push_back(CreateImmediate(imm_min + 1)); 47 } 48 if (imm_min < imm_max - 2) { 49 immediates.push_back(CreateImmediate(imm_min + 2)); 50 } 51 if (imm_min < imm_max - 3) { 52 immediates.push_back(CreateImmediate(imm_max - 1)); 53 } 54 if (imm_min < imm_max - 4) { 55 immediates.push_back(CreateImmediate((imm_min + imm_max) / 2)); 56 } 57 } 58 } 59 60 std::string RepeatRRIIC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond), 61 int64_t imm1_min, int64_t imm1_max, 62 int64_t imm2_min, int64_t imm2_max, 63 std::string fmt) { 64 return RepeatTemplatedRRIIC(f, GetRegisters(), GetRegisters(), 65 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 66 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 67 imm1_min, imm1_max, imm2_min, imm2_max, 68 fmt); 69 } 70 71 template <typename Reg1, typename Reg2> 72 std::string RepeatTemplatedRRIIC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond), 73 const std::vector<Reg1*> reg1_registers, 74 const std::vector<Reg2*> reg2_registers, 75 std::string (AssemblerArmTest::*GetName1)(const Reg1&), 76 std::string (AssemblerArmTest::*GetName2)(const Reg2&), 77 int64_t imm1_min, int64_t imm1_max, 78 int64_t imm2_min, int64_t imm2_max, 79 std::string fmt) { 80 std::vector<Imm> immediates1; 81 FillImmediates(immediates1, imm1_min, imm1_max); 82 std::vector<Imm> immediates2; 83 FillImmediates(immediates2, imm2_min, imm2_max); 84 85 std::vector<Cond>& cond = GetConditions(); 86 87 WarnOnCombinations(cond.size() * immediates1.size() * immediates2.size() * 88 reg1_registers.size() * reg2_registers.size()); 89 90 std::ostringstream oss; 91 bool first = true; 92 for (Cond& c : cond) { 93 std::string after_cond = fmt; 94 95 size_t cond_index = after_cond.find(COND_TOKEN); 96 if (cond_index != std::string::npos) { 97 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); 98 } 99 100 for (Imm i : immediates1) { 101 std::string base = after_cond; 102 103 size_t imm1_index = base.find(IMM1_TOKEN); 104 if (imm1_index != std::string::npos) { 105 std::ostringstream sreg; 106 sreg << i; 107 std::string imm_string = sreg.str(); 108 base.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string); 109 } 110 111 for (Imm j : immediates2) { 112 std::string base2 = base; 113 114 size_t imm2_index = base2.find(IMM2_TOKEN); 115 if (imm2_index != std::string::npos) { 116 std::ostringstream sreg; 117 sreg << j; 118 std::string imm_string = sreg.str(); 119 base2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string); 120 } 121 122 for (auto reg1 : reg1_registers) { 123 std::string base3 = base2; 124 125 std::string reg1_string = (this->*GetName1)(*reg1); 126 size_t reg1_index; 127 while ((reg1_index = base3.find(Base::REG1_TOKEN)) != std::string::npos) { 128 base3.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); 129 } 130 131 for (auto reg2 : reg2_registers) { 132 std::string base4 = base3; 133 134 std::string reg2_string = (this->*GetName2)(*reg2); 135 size_t reg2_index; 136 while ((reg2_index = base4.find(Base::REG2_TOKEN)) != std::string::npos) { 137 base4.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); 138 } 139 140 if (first) { 141 first = false; 142 } else { 143 oss << "\n"; 144 } 145 oss << base4; 146 147 (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c); 148 } 149 } 150 } 151 } 152 } 153 // Add a newline at the end. 154 oss << "\n"; 155 156 return oss.str(); 157 } 158 159 std::string RepeatRRiiC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond), 160 std::vector<std::pair<Imm, Imm>>& immediates, 161 std::string fmt) { 162 return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(), 163 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 164 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 165 immediates, fmt); 166 } 167 168 template <typename Reg1, typename Reg2> 169 std::string RepeatTemplatedRRiiC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond), 170 const std::vector<Reg1*> reg1_registers, 171 const std::vector<Reg2*> reg2_registers, 172 std::string (AssemblerArmTest::*GetName1)(const Reg1&), 173 std::string (AssemblerArmTest::*GetName2)(const Reg2&), 174 std::vector<std::pair<Imm, Imm>>& immediates, 175 std::string fmt) { 176 std::vector<Cond>& cond = GetConditions(); 177 178 WarnOnCombinations(cond.size() * immediates.size() * reg1_registers.size() * 179 reg2_registers.size()); 180 181 std::ostringstream oss; 182 bool first = true; 183 for (Cond& c : cond) { 184 std::string after_cond = fmt; 185 186 size_t cond_index = after_cond.find(COND_TOKEN); 187 if (cond_index != std::string::npos) { 188 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); 189 } 190 191 for (std::pair<Imm, Imm>& pair : immediates) { 192 Imm i = pair.first; 193 Imm j = pair.second; 194 std::string after_imm1 = after_cond; 195 196 size_t imm1_index = after_imm1.find(IMM1_TOKEN); 197 if (imm1_index != std::string::npos) { 198 std::ostringstream sreg; 199 sreg << i; 200 std::string imm_string = sreg.str(); 201 after_imm1.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string); 202 } 203 204 std::string after_imm2 = after_imm1; 205 206 size_t imm2_index = after_imm2.find(IMM2_TOKEN); 207 if (imm2_index != std::string::npos) { 208 std::ostringstream sreg; 209 sreg << j; 210 std::string imm_string = sreg.str(); 211 after_imm2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string); 212 } 213 214 for (auto reg1 : reg1_registers) { 215 std::string after_reg1 = after_imm2; 216 217 std::string reg1_string = (this->*GetName1)(*reg1); 218 size_t reg1_index; 219 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { 220 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); 221 } 222 223 for (auto reg2 : reg2_registers) { 224 std::string after_reg2 = after_reg1; 225 226 std::string reg2_string = (this->*GetName2)(*reg2); 227 size_t reg2_index; 228 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { 229 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); 230 } 231 232 if (first) { 233 first = false; 234 } else { 235 oss << "\n"; 236 } 237 oss << after_reg2; 238 239 (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c); 240 } 241 } 242 } 243 } 244 // Add a newline at the end. 245 oss << "\n"; 246 247 return oss.str(); 248 } 249 250 std::string RepeatRRC(void (Ass::*f)(Reg, Reg, Cond), std::string fmt) { 251 return RepeatTemplatedRRC(f, GetRegisters(), GetRegisters(), GetConditions(), 252 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 253 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 254 fmt); 255 } 256 257 template <typename Reg1, typename Reg2> 258 std::string RepeatTemplatedRRC(void (Ass::*f)(Reg1, Reg2, Cond), 259 const std::vector<Reg1*>& reg1_registers, 260 const std::vector<Reg2*>& reg2_registers, 261 const std::vector<Cond>& cond, 262 std::string (AssemblerArmTest::*GetName1)(const Reg1&), 263 std::string (AssemblerArmTest::*GetName2)(const Reg2&), 264 std::string fmt) { 265 WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size()); 266 267 std::ostringstream oss; 268 bool first = true; 269 for (const Cond& c : cond) { 270 std::string after_cond = fmt; 271 272 size_t cond_index = after_cond.find(COND_TOKEN); 273 if (cond_index != std::string::npos) { 274 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); 275 } 276 277 for (auto reg1 : reg1_registers) { 278 std::string after_reg1 = after_cond; 279 280 std::string reg1_string = (this->*GetName1)(*reg1); 281 size_t reg1_index; 282 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { 283 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); 284 } 285 286 for (auto reg2 : reg2_registers) { 287 std::string after_reg2 = after_reg1; 288 289 std::string reg2_string = (this->*GetName2)(*reg2); 290 size_t reg2_index; 291 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { 292 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); 293 } 294 295 if (first) { 296 first = false; 297 } else { 298 oss << "\n"; 299 } 300 oss << after_reg2; 301 302 (Base::GetAssembler()->*f)(*reg1, *reg2, c); 303 } 304 } 305 } 306 // Add a newline at the end. 307 oss << "\n"; 308 309 return oss.str(); 310 } 311 312 std::string RepeatRRRC(void (Ass::*f)(Reg, Reg, Reg, Cond), std::string fmt) { 313 return RepeatTemplatedRRRC(f, GetRegisters(), GetRegisters(), GetRegisters(), GetConditions(), 314 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 315 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 316 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, 317 fmt); 318 } 319 320 template <typename Reg1, typename Reg2, typename Reg3> 321 std::string RepeatTemplatedRRRC(void (Ass::*f)(Reg1, Reg2, Reg3, Cond), 322 const std::vector<Reg1*>& reg1_registers, 323 const std::vector<Reg2*>& reg2_registers, 324 const std::vector<Reg3*>& reg3_registers, 325 const std::vector<Cond>& cond, 326 std::string (AssemblerArmTest::*GetName1)(const Reg1&), 327 std::string (AssemblerArmTest::*GetName2)(const Reg2&), 328 std::string (AssemblerArmTest::*GetName3)(const Reg3&), 329 std::string fmt) { 330 WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * 331 reg3_registers.size()); 332 333 std::ostringstream oss; 334 bool first = true; 335 for (const Cond& c : cond) { 336 std::string after_cond = fmt; 337 338 size_t cond_index = after_cond.find(COND_TOKEN); 339 if (cond_index != std::string::npos) { 340 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); 341 } 342 343 for (auto reg1 : reg1_registers) { 344 std::string after_reg1 = after_cond; 345 346 std::string reg1_string = (this->*GetName1)(*reg1); 347 size_t reg1_index; 348 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { 349 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); 350 } 351 352 for (auto reg2 : reg2_registers) { 353 std::string after_reg2 = after_reg1; 354 355 std::string reg2_string = (this->*GetName2)(*reg2); 356 size_t reg2_index; 357 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { 358 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); 359 } 360 361 for (auto reg3 : reg3_registers) { 362 std::string after_reg3 = after_reg2; 363 364 std::string reg3_string = (this->*GetName3)(*reg3); 365 size_t reg3_index; 366 while ((reg3_index = after_reg3.find(REG3_TOKEN)) != std::string::npos) { 367 after_reg3.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); 368 } 369 370 if (first) { 371 first = false; 372 } else { 373 oss << "\n"; 374 } 375 oss << after_reg3; 376 377 (Base::GetAssembler()->*f)(*reg1, *reg2, *reg3, c); 378 } 379 } 380 } 381 } 382 // Add a newline at the end. 383 oss << "\n"; 384 385 return oss.str(); 386 } 387 388 template <typename RegT> 389 std::string RepeatTemplatedRSC(void (Ass::*f)(RegT, SOp, Cond), 390 const std::vector<RegT*>& registers, 391 const std::vector<SOp>& shifts, 392 const std::vector<Cond>& cond, 393 std::string (AssemblerArmTest::*GetName)(const RegT&), 394 std::string fmt) { 395 WarnOnCombinations(cond.size() * registers.size() * shifts.size()); 396 397 std::ostringstream oss; 398 bool first = true; 399 for (const Cond& c : cond) { 400 std::string after_cond = fmt; 401 402 size_t cond_index = after_cond.find(COND_TOKEN); 403 if (cond_index != std::string::npos) { 404 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); 405 } 406 407 for (const SOp& shift : shifts) { 408 std::string after_shift = after_cond; 409 410 std::string shift_string = GetShiftString(shift); 411 size_t shift_index; 412 while ((shift_index = after_shift.find(Base::SHIFT_TOKEN)) != std::string::npos) { 413 after_shift.replace(shift_index, ConstexprStrLen(Base::SHIFT_TOKEN), shift_string); 414 } 415 416 for (auto reg : registers) { 417 std::string after_reg = after_shift; 418 419 std::string reg_string = (this->*GetName)(*reg); 420 size_t reg_index; 421 while ((reg_index = after_reg.find(Base::REG_TOKEN)) != std::string::npos) { 422 after_reg.replace(reg_index, ConstexprStrLen(Base::REG_TOKEN), reg_string); 423 } 424 425 if (first) { 426 first = false; 427 } else { 428 oss << "\n"; 429 } 430 oss << after_reg; 431 432 (Base::GetAssembler()->*f)(*reg, shift, c); 433 } 434 } 435 } 436 // Add a newline at the end. 437 oss << "\n"; 438 439 return oss.str(); 440 } 441 442 template <typename Reg1, typename Reg2> 443 std::string RepeatTemplatedRRSC(void (Ass::*f)(Reg1, Reg2, const SOp&, Cond), 444 const std::vector<Reg1*>& reg1_registers, 445 const std::vector<Reg2*>& reg2_registers, 446 const std::vector<SOp>& shifts, 447 const std::vector<Cond>& cond, 448 std::string (AssemblerArmTest::*GetName1)(const Reg1&), 449 std::string (AssemblerArmTest::*GetName2)(const Reg2&), 450 std::string fmt) { 451 WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * shifts.size()); 452 453 std::ostringstream oss; 454 bool first = true; 455 for (const Cond& c : cond) { 456 std::string after_cond = fmt; 457 458 size_t cond_index = after_cond.find(COND_TOKEN); 459 if (cond_index != std::string::npos) { 460 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); 461 } 462 463 for (const SOp& shift : shifts) { 464 std::string after_shift = after_cond; 465 466 std::string shift_string = GetShiftString(shift); 467 size_t shift_index; 468 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) { 469 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string); 470 } 471 472 for (auto reg1 : reg1_registers) { 473 std::string after_reg1 = after_shift; 474 475 std::string reg1_string = (this->*GetName1)(*reg1); 476 size_t reg1_index; 477 while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { 478 after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); 479 } 480 481 for (auto reg2 : reg2_registers) { 482 std::string after_reg2 = after_reg1; 483 484 std::string reg2_string = (this->*GetName2)(*reg2); 485 size_t reg2_index; 486 while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { 487 after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); 488 } 489 490 if (first) { 491 first = false; 492 } else { 493 oss << "\n"; 494 } 495 oss << after_reg2; 496 497 (Base::GetAssembler()->*f)(*reg1, *reg2, shift, c); 498 } 499 } 500 } 501 } 502 // Add a newline at the end. 503 oss << "\n"; 504 505 return oss.str(); 506 } 507 508 protected: 509 explicit AssemblerArmTest() {} 510 511 virtual std::vector<Cond>& GetConditions() = 0; 512 virtual std::string GetConditionString(Cond c) = 0; 513 514 virtual std::vector<SOp>& GetShiftOperands() = 0; 515 virtual std::string GetShiftString(SOp sop) = 0; 516 517 virtual Reg GetPCRegister() = 0; 518 virtual std::vector<Reg*> GetRegistersWithoutPC() { 519 std::vector<Reg*> without_pc = GetRegisters(); 520 Reg pc_reg = GetPCRegister(); 521 522 for (auto it = without_pc.begin(); it != without_pc.end(); ++it) { 523 if (**it == pc_reg) { 524 without_pc.erase(it); 525 break; 526 } 527 } 528 529 return without_pc; 530 } 531 532 static constexpr const char* IMM1_TOKEN = "{imm1}"; 533 static constexpr const char* IMM2_TOKEN = "{imm2}"; 534 static constexpr const char* REG3_TOKEN = "{reg3}"; 535 static constexpr const char* REG4_TOKEN = "{reg4}"; 536 static constexpr const char* COND_TOKEN = "{cond}"; 537 static constexpr const char* SHIFT_TOKEN = "{shift}"; 538 539 private: 540 DISALLOW_COPY_AND_ASSIGN(AssemblerArmTest); 541 }; 542 543 } // namespace art 544 545 #endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_ 546