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 <sys/stat.h> 23 24 #include <cstdio> 25 #include <cstdlib> 26 #include <fstream> 27 #include <iterator> 28 29 #include "base/malloc_arena_pool.h" 30 #include "assembler_test_base.h" 31 #include "common_runtime_test.h" // For ScratchFile 32 33 namespace art { 34 35 // Helper for a constexpr string length. 36 constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) { 37 return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1); 38 } 39 40 enum class RegisterView { // private 41 kUsePrimaryName, 42 kUseSecondaryName, 43 kUseTertiaryName, 44 kUseQuaternaryName, 45 }; 46 47 // For use in the template as the default type to get a nonvector registers version. 48 struct NoVectorRegs {}; 49 50 template<typename Ass, 51 typename Addr, 52 typename Reg, 53 typename FPReg, 54 typename Imm, 55 typename VecReg = NoVectorRegs> 56 class AssemblerTest : public testing::Test { 57 public: GetAssembler()58 Ass* GetAssembler() { 59 return assembler_.get(); 60 } 61 62 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler); 63 DriverFn(TestFn f,const std::string & test_name)64 void DriverFn(TestFn f, const std::string& test_name) { 65 DriverWrapper(f(this, assembler_.get()), test_name); 66 } 67 68 // This driver assumes the assembler has already been called. DriverStr(const std::string & assembly_string,const std::string & test_name)69 void DriverStr(const std::string& assembly_string, const std::string& test_name) { 70 DriverWrapper(assembly_string, test_name); 71 } 72 73 // 74 // Register repeats. 75 // 76 RepeatR(void (Ass::* f)(Reg),const std::string & fmt)77 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) { 78 return RepeatTemplatedRegister<Reg>(f, 79 GetRegisters(), 80 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 81 fmt); 82 } 83 Repeatr(void (Ass::* f)(Reg),const std::string & fmt)84 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) { 85 return RepeatTemplatedRegister<Reg>(f, 86 GetRegisters(), 87 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 88 fmt); 89 } 90 RepeatRR(void (Ass::* f)(Reg,Reg),const std::string & fmt)91 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 92 return RepeatTemplatedRegisters<Reg, Reg>(f, 93 GetRegisters(), 94 GetRegisters(), 95 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 96 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 97 fmt); 98 } 99 RepeatRRNoDupes(void (Ass::* f)(Reg,Reg),const std::string & fmt)100 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 101 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f, 102 GetRegisters(), 103 GetRegisters(), 104 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 105 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 106 fmt); 107 } 108 Repeatrr(void (Ass::* f)(Reg,Reg),const std::string & fmt)109 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 110 return RepeatTemplatedRegisters<Reg, Reg>(f, 111 GetRegisters(), 112 GetRegisters(), 113 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 114 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 115 fmt); 116 } 117 Repeatww(void (Ass::* f)(Reg,Reg),const std::string & fmt)118 std::string Repeatww(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 119 return RepeatTemplatedRegisters<Reg, Reg>(f, 120 GetRegisters(), 121 GetRegisters(), 122 &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>, 123 &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>, 124 fmt); 125 } 126 Repeatbb(void (Ass::* f)(Reg,Reg),const std::string & fmt)127 std::string Repeatbb(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 128 return RepeatTemplatedRegisters<Reg, Reg>(f, 129 GetRegisters(), 130 GetRegisters(), 131 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 132 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 133 fmt); 134 } 135 RepeatRRR(void (Ass::* f)(Reg,Reg,Reg),const std::string & fmt)136 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) { 137 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f, 138 GetRegisters(), 139 GetRegisters(), 140 GetRegisters(), 141 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 142 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 143 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 144 fmt); 145 } 146 Repeatrb(void (Ass::* f)(Reg,Reg),const std::string & fmt)147 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 148 return RepeatTemplatedRegisters<Reg, Reg>(f, 149 GetRegisters(), 150 GetRegisters(), 151 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 152 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 153 fmt); 154 } 155 RepeatRr(void (Ass::* f)(Reg,Reg),const std::string & fmt)156 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 157 return RepeatTemplatedRegisters<Reg, Reg>(f, 158 GetRegisters(), 159 GetRegisters(), 160 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 161 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 162 fmt); 163 } 164 RepeatRI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)165 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) { 166 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt); 167 } 168 RepeatrI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)169 std::string RepeatrI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) { 170 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt); 171 } 172 RepeatwI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)173 std::string RepeatwI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) { 174 return RepeatRegisterImm<RegisterView::kUseTertiaryName>(f, imm_bytes, fmt); 175 } 176 RepeatbI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)177 std::string RepeatbI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) { 178 return RepeatRegisterImm<RegisterView::kUseQuaternaryName>(f, imm_bytes, fmt); 179 } 180 181 template <typename Reg1, typename Reg2, typename ImmType> 182 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType), 183 int imm_bits, 184 const std::vector<Reg1*> reg1_registers, 185 const std::vector<Reg2*> reg2_registers, 186 std::string (AssemblerTest::*GetName1)(const Reg1&), 187 std::string (AssemblerTest::*GetName2)(const Reg2&), 188 const std::string& fmt, 189 int bias = 0, 190 int multiplier = 1) { 191 std::string str; 192 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 193 194 for (auto reg1 : reg1_registers) { 195 for (auto reg2 : reg2_registers) { 196 for (int64_t imm : imms) { 197 ImmType new_imm = CreateImmediate(imm); 198 if (f != nullptr) { 199 (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias); 200 } 201 std::string base = fmt; 202 203 std::string reg1_string = (this->*GetName1)(*reg1); 204 size_t reg1_index; 205 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 206 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 207 } 208 209 std::string reg2_string = (this->*GetName2)(*reg2); 210 size_t reg2_index; 211 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 212 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 213 } 214 215 size_t imm_index = base.find(IMM_TOKEN); 216 if (imm_index != std::string::npos) { 217 std::ostringstream sreg; 218 sreg << imm * multiplier + bias; 219 std::string imm_string = sreg.str(); 220 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 221 } 222 223 if (str.size() > 0) { 224 str += "\n"; 225 } 226 str += base; 227 } 228 } 229 } 230 // Add a newline at the end. 231 str += "\n"; 232 return str; 233 } 234 235 template <typename Reg1, typename Reg2, typename Reg3, typename ImmType> RepeatTemplatedRegistersImmBits(void (Ass::* f)(Reg1,Reg2,Reg3,ImmType),int imm_bits,const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,const std::vector<Reg3 * > reg3_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),std::string (AssemblerTest::* GetName3)(const Reg3 &),std::string fmt,int bias)236 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType), 237 int imm_bits, 238 const std::vector<Reg1*> reg1_registers, 239 const std::vector<Reg2*> reg2_registers, 240 const std::vector<Reg3*> reg3_registers, 241 std::string (AssemblerTest::*GetName1)(const Reg1&), 242 std::string (AssemblerTest::*GetName2)(const Reg2&), 243 std::string (AssemblerTest::*GetName3)(const Reg3&), 244 std::string fmt, 245 int bias) { 246 std::string str; 247 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 248 249 for (auto reg1 : reg1_registers) { 250 for (auto reg2 : reg2_registers) { 251 for (auto reg3 : reg3_registers) { 252 for (int64_t imm : imms) { 253 ImmType new_imm = CreateImmediate(imm); 254 if (f != nullptr) { 255 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias); 256 } 257 std::string base = fmt; 258 259 std::string reg1_string = (this->*GetName1)(*reg1); 260 size_t reg1_index; 261 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 262 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 263 } 264 265 std::string reg2_string = (this->*GetName2)(*reg2); 266 size_t reg2_index; 267 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 268 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 269 } 270 271 std::string reg3_string = (this->*GetName3)(*reg3); 272 size_t reg3_index; 273 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) { 274 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); 275 } 276 277 size_t imm_index = base.find(IMM_TOKEN); 278 if (imm_index != std::string::npos) { 279 std::ostringstream sreg; 280 sreg << imm + bias; 281 std::string imm_string = sreg.str(); 282 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 283 } 284 285 if (str.size() > 0) { 286 str += "\n"; 287 } 288 str += base; 289 } 290 } 291 } 292 } 293 // Add a newline at the end. 294 str += "\n"; 295 return str; 296 } 297 298 template <typename ImmType, typename Reg1, typename Reg2> RepeatTemplatedImmBitsRegisters(void (Ass::* f)(ImmType,Reg1,Reg2),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),int imm_bits,const std::string & fmt)299 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2), 300 const std::vector<Reg1*> reg1_registers, 301 const std::vector<Reg2*> reg2_registers, 302 std::string (AssemblerTest::*GetName1)(const Reg1&), 303 std::string (AssemblerTest::*GetName2)(const Reg2&), 304 int imm_bits, 305 const std::string& fmt) { 306 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 307 308 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); 309 310 std::string str; 311 for (auto reg1 : reg1_registers) { 312 for (auto reg2 : reg2_registers) { 313 for (int64_t imm : imms) { 314 ImmType new_imm = CreateImmediate(imm); 315 if (f != nullptr) { 316 (assembler_.get()->*f)(new_imm, *reg1, *reg2); 317 } 318 std::string base = fmt; 319 320 std::string reg1_string = (this->*GetName1)(*reg1); 321 size_t reg1_index; 322 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 323 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 324 } 325 326 std::string reg2_string = (this->*GetName2)(*reg2); 327 size_t reg2_index; 328 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 329 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 330 } 331 332 size_t imm_index = base.find(IMM_TOKEN); 333 if (imm_index != std::string::npos) { 334 std::ostringstream sreg; 335 sreg << imm; 336 std::string imm_string = sreg.str(); 337 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 338 } 339 340 if (str.size() > 0) { 341 str += "\n"; 342 } 343 str += base; 344 } 345 } 346 } 347 // Add a newline at the end. 348 str += "\n"; 349 return str; 350 } 351 352 template <typename RegType, typename ImmType> RepeatTemplatedRegisterImmBits(void (Ass::* f)(RegType,ImmType),int imm_bits,const std::vector<RegType * > registers,std::string (AssemblerTest::* GetName)(const RegType &),const std::string & fmt,int bias)353 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType), 354 int imm_bits, 355 const std::vector<RegType*> registers, 356 std::string (AssemblerTest::*GetName)(const RegType&), 357 const std::string& fmt, 358 int bias) { 359 std::string str; 360 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 361 362 for (auto reg : registers) { 363 for (int64_t imm : imms) { 364 ImmType new_imm = CreateImmediate(imm); 365 if (f != nullptr) { 366 (assembler_.get()->*f)(*reg, new_imm + bias); 367 } 368 std::string base = fmt; 369 370 std::string reg_string = (this->*GetName)(*reg); 371 size_t reg_index; 372 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 373 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 374 } 375 376 size_t imm_index = base.find(IMM_TOKEN); 377 if (imm_index != std::string::npos) { 378 std::ostringstream sreg; 379 sreg << imm + bias; 380 std::string imm_string = sreg.str(); 381 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 382 } 383 384 if (str.size() > 0) { 385 str += "\n"; 386 } 387 str += base; 388 } 389 } 390 // Add a newline at the end. 391 str += "\n"; 392 return str; 393 } 394 395 template <typename ImmType> 396 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType), 397 int imm_bits, 398 const std::string& fmt, 399 int bias = 0) { 400 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f, 401 imm_bits, 402 GetRegisters(), 403 GetRegisters(), 404 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 405 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 406 fmt, 407 bias); 408 } 409 410 template <typename ImmType> 411 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType), 412 int imm_bits, 413 const std::string& fmt, 414 int bias = 0) { 415 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f, 416 imm_bits, 417 GetRegisters(), 418 GetRegisters(), 419 GetRegisters(), 420 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 421 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 422 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 423 fmt, 424 bias); 425 } 426 427 template <typename ImmType> 428 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) { 429 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f, 430 imm_bits, 431 GetRegisters(), 432 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 433 fmt, 434 bias); 435 } 436 437 template <typename ImmType> 438 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType), 439 int imm_bits, 440 const std::string& fmt, 441 int bias = 0) { 442 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f, 443 imm_bits, 444 GetFPRegisters(), 445 GetRegisters(), 446 &AssemblerTest::GetFPRegName, 447 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 448 fmt, 449 bias); 450 } 451 RepeatFF(void (Ass::* f)(FPReg,FPReg),const std::string & fmt)452 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) { 453 return RepeatTemplatedRegisters<FPReg, FPReg>(f, 454 GetFPRegisters(), 455 GetFPRegisters(), 456 &AssemblerTest::GetFPRegName, 457 &AssemblerTest::GetFPRegName, 458 fmt); 459 } 460 RepeatFFF(void (Ass::* f)(FPReg,FPReg,FPReg),const std::string & fmt)461 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) { 462 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f, 463 GetFPRegisters(), 464 GetFPRegisters(), 465 GetFPRegisters(), 466 &AssemblerTest::GetFPRegName, 467 &AssemblerTest::GetFPRegName, 468 &AssemblerTest::GetFPRegName, 469 fmt); 470 } 471 RepeatFFR(void (Ass::* f)(FPReg,FPReg,Reg),const std::string & fmt)472 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) { 473 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>( 474 f, 475 GetFPRegisters(), 476 GetFPRegisters(), 477 GetRegisters(), 478 &AssemblerTest::GetFPRegName, 479 &AssemblerTest::GetFPRegName, 480 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 481 fmt); 482 } 483 RepeatFFI(void (Ass::* f)(FPReg,FPReg,const Imm &),size_t imm_bytes,const std::string & fmt)484 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&), 485 size_t imm_bytes, 486 const std::string& fmt) { 487 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f, 488 GetFPRegisters(), 489 GetFPRegisters(), 490 &AssemblerTest::GetFPRegName, 491 &AssemblerTest::GetFPRegName, 492 imm_bytes, 493 fmt); 494 } 495 496 template <typename ImmType> RepeatFFIb(void (Ass::* f)(FPReg,FPReg,ImmType),int imm_bits,const std::string & fmt)497 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType), 498 int imm_bits, 499 const std::string& fmt) { 500 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f, 501 imm_bits, 502 GetFPRegisters(), 503 GetFPRegisters(), 504 &AssemblerTest::GetFPRegName, 505 &AssemblerTest::GetFPRegName, 506 fmt); 507 } 508 509 template <typename ImmType> RepeatIbFF(void (Ass::* f)(ImmType,FPReg,FPReg),int imm_bits,const std::string & fmt)510 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), 511 int imm_bits, 512 const std::string& fmt) { 513 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f, 514 GetFPRegisters(), 515 GetFPRegisters(), 516 &AssemblerTest::GetFPRegName, 517 &AssemblerTest::GetFPRegName, 518 imm_bits, 519 fmt); 520 } 521 RepeatFR(void (Ass::* f)(FPReg,Reg),const std::string & fmt)522 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) { 523 return RepeatTemplatedRegisters<FPReg, Reg>(f, 524 GetFPRegisters(), 525 GetRegisters(), 526 &AssemblerTest::GetFPRegName, 527 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 528 fmt); 529 } 530 RepeatFr(void (Ass::* f)(FPReg,Reg),const std::string & fmt)531 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) { 532 return RepeatTemplatedRegisters<FPReg, Reg>(f, 533 GetFPRegisters(), 534 GetRegisters(), 535 &AssemblerTest::GetFPRegName, 536 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 537 fmt); 538 } 539 RepeatRF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)540 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) { 541 return RepeatTemplatedRegisters<Reg, FPReg>(f, 542 GetRegisters(), 543 GetFPRegisters(), 544 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 545 &AssemblerTest::GetFPRegName, 546 fmt); 547 } 548 RepeatrF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)549 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) { 550 return RepeatTemplatedRegisters<Reg, FPReg>(f, 551 GetRegisters(), 552 GetFPRegisters(), 553 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 554 &AssemblerTest::GetFPRegName, 555 fmt); 556 } 557 558 std::string RepeatI(void (Ass::*f)(const Imm&), 559 size_t imm_bytes, 560 const std::string& fmt, 561 bool as_uint = false) { 562 std::string str; 563 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint); 564 565 WarnOnCombinations(imms.size()); 566 567 for (int64_t imm : imms) { 568 Imm new_imm = CreateImmediate(imm); 569 if (f != nullptr) { 570 (assembler_.get()->*f)(new_imm); 571 } 572 std::string base = fmt; 573 574 size_t imm_index = base.find(IMM_TOKEN); 575 if (imm_index != std::string::npos) { 576 std::ostringstream sreg; 577 sreg << imm; 578 std::string imm_string = sreg.str(); 579 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 580 } 581 582 if (str.size() > 0) { 583 str += "\n"; 584 } 585 str += base; 586 } 587 // Add a newline at the end. 588 str += "\n"; 589 return str; 590 } 591 RepeatVV(void (Ass::* f)(VecReg,VecReg),const std::string & fmt)592 std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) { 593 return RepeatTemplatedRegisters<VecReg, VecReg>(f, 594 GetVectorRegisters(), 595 GetVectorRegisters(), 596 &AssemblerTest::GetVecRegName, 597 &AssemblerTest::GetVecRegName, 598 fmt); 599 } 600 RepeatVVV(void (Ass::* f)(VecReg,VecReg,VecReg),const std::string & fmt)601 std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) { 602 return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f, 603 GetVectorRegisters(), 604 GetVectorRegisters(), 605 GetVectorRegisters(), 606 &AssemblerTest::GetVecRegName, 607 &AssemblerTest::GetVecRegName, 608 &AssemblerTest::GetVecRegName, 609 fmt); 610 } 611 RepeatVR(void (Ass::* f)(VecReg,Reg),const std::string & fmt)612 std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) { 613 return RepeatTemplatedRegisters<VecReg, Reg>( 614 f, 615 GetVectorRegisters(), 616 GetRegisters(), 617 &AssemblerTest::GetVecRegName, 618 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 619 fmt); 620 } 621 622 template <typename ImmType> 623 std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType), 624 int imm_bits, 625 std::string fmt, 626 int bias = 0) { 627 return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f, 628 imm_bits, 629 GetVectorRegisters(), 630 &AssemblerTest::GetVecRegName, 631 fmt, 632 bias); 633 } 634 635 template <typename ImmType> 636 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType), 637 int imm_bits, 638 const std::string& fmt, 639 int bias = 0, 640 int multiplier = 1) { 641 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>( 642 f, 643 imm_bits, 644 GetVectorRegisters(), 645 GetRegisters(), 646 &AssemblerTest::GetVecRegName, 647 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 648 fmt, 649 bias, 650 multiplier); 651 } 652 653 template <typename ImmType> 654 std::string RepeatRVIb(void (Ass::*f)(Reg, VecReg, ImmType), 655 int imm_bits, 656 const std::string& fmt, 657 int bias = 0, 658 int multiplier = 1) { 659 return RepeatTemplatedRegistersImmBits<Reg, VecReg, ImmType>( 660 f, 661 imm_bits, 662 GetRegisters(), 663 GetVectorRegisters(), 664 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 665 &AssemblerTest::GetVecRegName, 666 fmt, 667 bias, 668 multiplier); 669 } 670 671 template <typename ImmType> 672 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType), 673 int imm_bits, 674 const std::string& fmt, 675 int bias = 0) { 676 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f, 677 imm_bits, 678 GetVectorRegisters(), 679 GetVectorRegisters(), 680 &AssemblerTest::GetVecRegName, 681 &AssemblerTest::GetVecRegName, 682 fmt, 683 bias); 684 } 685 686 // This is intended to be run as a test. CheckTools()687 bool CheckTools() { 688 return test_helper_->CheckTools(); 689 } 690 691 // The following functions are public so that TestFn can use them... 692 693 // Returns a vector of address used by any of the repeat methods 694 // involving an "A" (e.g. RepeatA). 695 virtual std::vector<Addr> GetAddresses() = 0; 696 697 // Returns a vector of registers used by any of the repeat methods 698 // involving an "R" (e.g. RepeatR). 699 virtual std::vector<Reg*> GetRegisters() = 0; 700 701 // Returns a vector of fp-registers used by any of the repeat methods 702 // involving an "F" (e.g. RepeatFF). GetFPRegisters()703 virtual std::vector<FPReg*> GetFPRegisters() { 704 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers"; 705 UNREACHABLE(); 706 } 707 708 // Returns a vector of dedicated simd-registers used by any of the repeat 709 // methods involving an "V" (e.g. RepeatVV). GetVectorRegisters()710 virtual std::vector<VecReg*> GetVectorRegisters() { 711 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers"; 712 UNREACHABLE(); 713 } 714 715 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems. GetSecondaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)716 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 717 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers"; 718 UNREACHABLE(); 719 } 720 721 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems. GetTertiaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)722 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 723 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers"; 724 UNREACHABLE(); 725 } 726 727 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems. GetQuaternaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)728 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 729 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers"; 730 UNREACHABLE(); 731 } 732 GetRegisterName(const Reg & reg)733 std::string GetRegisterName(const Reg& reg) { 734 return GetRegName<RegisterView::kUsePrimaryName>(reg); 735 } 736 737 protected: AssemblerTest()738 AssemblerTest() {} 739 SetUp()740 void SetUp() override { 741 allocator_.reset(new ArenaAllocator(&pool_)); 742 assembler_.reset(CreateAssembler(allocator_.get())); 743 test_helper_.reset( 744 new AssemblerTestInfrastructure(GetArchitectureString(), 745 GetAssemblerCmdName(), 746 GetAssemblerParameters(), 747 GetObjdumpCmdName(), 748 GetObjdumpParameters(), 749 GetDisassembleCmdName(), 750 GetDisassembleParameters(), 751 GetAssemblyHeader())); 752 753 SetUpHelpers(); 754 } 755 TearDown()756 void TearDown() override { 757 test_helper_.reset(); // Clean up the helper. 758 assembler_.reset(); 759 allocator_.reset(); 760 } 761 762 // Override this to set up any architecture-specific things, e.g., CPU revision. CreateAssembler(ArenaAllocator * allocator)763 virtual Ass* CreateAssembler(ArenaAllocator* allocator) { 764 return new (allocator) Ass(allocator); 765 } 766 767 // Override this to set up any architecture-specific things, e.g., register vectors. SetUpHelpers()768 virtual void SetUpHelpers() {} 769 770 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ... 771 virtual std::string GetArchitectureString() = 0; 772 773 // Get the name of the assembler, e.g., "as" by default. GetAssemblerCmdName()774 virtual std::string GetAssemblerCmdName() { 775 return "as"; 776 } 777 778 // Switches to the assembler command. Default none. GetAssemblerParameters()779 virtual std::string GetAssemblerParameters() { 780 return ""; 781 } 782 783 // Get the name of the objdump, e.g., "objdump" by default. GetObjdumpCmdName()784 virtual std::string GetObjdumpCmdName() { 785 return "objdump"; 786 } 787 788 // Switches to the objdump command. Default is " -h". GetObjdumpParameters()789 virtual std::string GetObjdumpParameters() { 790 return " -h"; 791 } 792 793 // Get the name of the objdump, e.g., "objdump" by default. GetDisassembleCmdName()794 virtual std::string GetDisassembleCmdName() { 795 return "objdump"; 796 } 797 798 // Switches to the objdump command. As it's a binary, one needs to push the architecture and 799 // such to objdump, so it's architecture-specific and there is no default. 800 virtual std::string GetDisassembleParameters() = 0; 801 802 // Create a couple of immediate values up to the number of bytes given. 803 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) { 804 std::vector<int64_t> res; 805 res.push_back(0); 806 if (!as_uint) { 807 res.push_back(-1); 808 } else { 809 res.push_back(0xFF); 810 } 811 res.push_back(0x12); 812 if (imm_bytes >= 2) { 813 res.push_back(0x1234); 814 if (!as_uint) { 815 res.push_back(-0x1234); 816 } else { 817 res.push_back(0xFFFF); 818 } 819 if (imm_bytes >= 4) { 820 res.push_back(0x12345678); 821 if (!as_uint) { 822 res.push_back(-0x12345678); 823 } else { 824 res.push_back(0xFFFFFFFF); 825 } 826 if (imm_bytes >= 6) { 827 res.push_back(0x123456789ABC); 828 if (!as_uint) { 829 res.push_back(-0x123456789ABC); 830 } 831 if (imm_bytes >= 8) { 832 res.push_back(0x123456789ABCDEF0); 833 if (!as_uint) { 834 res.push_back(-0x123456789ABCDEF0); 835 } else { 836 res.push_back(0xFFFFFFFFFFFFFFFF); 837 } 838 } 839 } 840 } 841 } 842 return res; 843 } 844 845 const int kMaxBitsExhaustiveTest = 8; 846 847 // Create a couple of immediate values up to the number of bits given. 848 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) { 849 CHECK_GT(imm_bits, 0); 850 CHECK_LE(imm_bits, 64); 851 std::vector<int64_t> res; 852 853 if (imm_bits <= kMaxBitsExhaustiveTest) { 854 if (as_uint) { 855 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) { 856 res.push_back(static_cast<int64_t>(i)); 857 } 858 } else { 859 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) { 860 res.push_back(i); 861 } 862 } 863 } else { 864 if (as_uint) { 865 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest); 866 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest); 867 i++) { 868 res.push_back(static_cast<int64_t>(i)); 869 } 870 for (int i = 0; i <= imm_bits; i++) { 871 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) + 872 ((MaxInt<uint64_t>(imm_bits) - 873 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1)) 874 * i / imm_bits); 875 res.push_back(static_cast<int64_t>(j)); 876 } 877 } else { 878 for (int i = 0; i <= imm_bits; i++) { 879 int64_t j = MinInt<int64_t>(imm_bits) + 880 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) - 881 MinInt<int64_t>(imm_bits)) 882 * i) / imm_bits); 883 res.push_back(static_cast<int64_t>(j)); 884 } 885 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest); 886 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest); 887 i++) { 888 res.push_back(static_cast<int64_t>(i)); 889 } 890 for (int i = 0; i <= imm_bits; i++) { 891 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) + 892 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1)) 893 * i / imm_bits); 894 res.push_back(static_cast<int64_t>(j)); 895 } 896 } 897 } 898 899 return res; 900 } 901 902 // Create an immediate from the specific value. 903 virtual Imm CreateImmediate(int64_t imm_value) = 0; 904 905 // 906 // Addresses repeats. 907 // 908 909 // Repeats over addresses provided by fixture. RepeatA(void (Ass::* f)(const Addr &),const std::string & fmt)910 std::string RepeatA(void (Ass::*f)(const Addr&), const std::string& fmt) { 911 return RepeatA(f, GetAddresses(), fmt); 912 } 913 914 // Variant that takes explicit vector of addresss 915 // (to test restricted addressing modes set). RepeatA(void (Ass::* f)(const Addr &),const std::vector<Addr> & a,const std::string & fmt)916 std::string RepeatA(void (Ass::*f)(const Addr&), 917 const std::vector<Addr>& a, 918 const std::string& fmt) { 919 return RepeatTemplatedMem<Addr>(f, a, &AssemblerTest::GetAddrName, fmt); 920 } 921 922 // Repeats over addresses and immediates provided by fixture. RepeatAI(void (Ass::* f)(const Addr &,const Imm &),size_t imm_bytes,const std::string & fmt)923 std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&), 924 size_t imm_bytes, 925 const std::string& fmt) { 926 return RepeatAI(f, imm_bytes, GetAddresses(), fmt); 927 } 928 929 // Variant that takes explicit vector of addresss 930 // (to test restricted addressing modes set). RepeatAI(void (Ass::* f)(const Addr &,const Imm &),size_t imm_bytes,const std::vector<Addr> & a,const std::string & fmt)931 std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&), 932 size_t imm_bytes, 933 const std::vector<Addr>& a, 934 const std::string& fmt) { 935 return RepeatTemplatedMemImm<Addr>(f, imm_bytes, a, &AssemblerTest::GetAddrName, fmt); 936 } 937 938 // Repeats over registers and addresses provided by fixture. RepeatRA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)939 std::string RepeatRA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) { 940 return RepeatRA(f, GetAddresses(), fmt); 941 } 942 943 // Variant that takes explicit vector of addresss 944 // (to test restricted addressing modes set). RepeatRA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)945 std::string RepeatRA(void (Ass::*f)(Reg, const Addr&), 946 const std::vector<Addr>& a, 947 const std::string& fmt) { 948 return RepeatTemplatedRegMem<Reg, Addr>( 949 f, 950 GetRegisters(), 951 a, 952 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 953 &AssemblerTest::GetAddrName, 954 fmt); 955 } 956 957 // Repeats over secondary registers and addresses provided by fixture. RepeatrA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)958 std::string RepeatrA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) { 959 return RepeatrA(f, GetAddresses(), fmt); 960 } 961 962 // Variant that takes explicit vector of addresss 963 // (to test restricted addressing modes set). RepeatrA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)964 std::string RepeatrA(void (Ass::*f)(Reg, const Addr&), 965 const std::vector<Addr>& a, 966 const std::string& fmt) { 967 return RepeatTemplatedRegMem<Reg, Addr>( 968 f, 969 GetRegisters(), 970 a, 971 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 972 &AssemblerTest::GetAddrName, 973 fmt); 974 } 975 976 // Repeats over tertiary registers and addresses provided by fixture. RepeatwA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)977 std::string RepeatwA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) { 978 return RepeatwA(f, GetAddresses(), fmt); 979 } 980 981 // Variant that takes explicit vector of addresss 982 // (to test restricted addressing modes set). RepeatwA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)983 std::string RepeatwA(void (Ass::*f)(Reg, const Addr&), 984 const std::vector<Addr>& a, 985 const std::string& fmt) { 986 return RepeatTemplatedRegMem<Reg, Addr>( 987 f, 988 GetRegisters(), 989 a, 990 &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>, 991 &AssemblerTest::GetAddrName, 992 fmt); 993 } 994 995 // Repeats over quaternary registers and addresses provided by fixture. RepeatbA(void (Ass::* f)(Reg,const Addr &),const std::string & fmt)996 std::string RepeatbA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) { 997 return RepeatbA(f, GetAddresses(), fmt); 998 } 999 1000 // Variant that takes explicit vector of addresss 1001 // (to test restricted addressing modes set). RepeatbA(void (Ass::* f)(Reg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)1002 std::string RepeatbA(void (Ass::*f)(Reg, const Addr&), 1003 const std::vector<Addr>& a, 1004 const std::string& fmt) { 1005 return RepeatTemplatedRegMem<Reg, Addr>( 1006 f, 1007 GetRegisters(), 1008 a, 1009 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 1010 &AssemblerTest::GetAddrName, 1011 fmt); 1012 } 1013 1014 // Repeats over fp-registers and addresses provided by fixture. RepeatFA(void (Ass::* f)(FPReg,const Addr &),const std::string & fmt)1015 std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&), const std::string& fmt) { 1016 return RepeatFA(f, GetAddresses(), fmt); 1017 } 1018 1019 // Variant that takes explicit vector of addresss 1020 // (to test restricted addressing modes set). RepeatFA(void (Ass::* f)(FPReg,const Addr &),const std::vector<Addr> & a,const std::string & fmt)1021 std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&), 1022 const std::vector<Addr>& a, 1023 const std::string& fmt) { 1024 return RepeatTemplatedRegMem<FPReg, Addr>( 1025 f, 1026 GetFPRegisters(), 1027 a, 1028 &AssemblerTest::GetFPRegName, 1029 &AssemblerTest::GetAddrName, 1030 fmt); 1031 } 1032 1033 // Repeats over addresses and registers provided by fixture. RepeatAR(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1034 std::string RepeatAR(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) { 1035 return RepeatAR(f, GetAddresses(), fmt); 1036 } 1037 1038 // Variant that takes explicit vector of addresss 1039 // (to test restricted addressing modes set). RepeatAR(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1040 std::string RepeatAR(void (Ass::*f)(const Addr&, Reg), 1041 const std::vector<Addr>& a, 1042 const std::string& fmt) { 1043 return RepeatTemplatedMemReg<Addr, Reg>( 1044 f, 1045 a, 1046 GetRegisters(), 1047 &AssemblerTest::GetAddrName, 1048 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 1049 fmt); 1050 } 1051 1052 // Repeats over addresses and secondary registers provided by fixture. RepeatAr(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1053 std::string RepeatAr(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) { 1054 return RepeatAr(f, GetAddresses(), fmt); 1055 } 1056 1057 // Variant that takes explicit vector of addresss 1058 // (to test restricted addressing modes set). RepeatAr(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1059 std::string RepeatAr(void (Ass::*f)(const Addr&, Reg), 1060 const std::vector<Addr>& a, 1061 const std::string& fmt) { 1062 return RepeatTemplatedMemReg<Addr, Reg>( 1063 f, 1064 a, 1065 GetRegisters(), 1066 &AssemblerTest::GetAddrName, 1067 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 1068 fmt); 1069 } 1070 1071 // Repeats over addresses and tertiary registers provided by fixture. RepeatAw(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1072 std::string RepeatAw(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) { 1073 return RepeatAw(f, GetAddresses(), fmt); 1074 } 1075 1076 // Variant that takes explicit vector of addresss 1077 // (to test restricted addressing modes set). RepeatAw(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1078 std::string RepeatAw(void (Ass::*f)(const Addr&, Reg), 1079 const std::vector<Addr>& a, 1080 const std::string& fmt) { 1081 return RepeatTemplatedMemReg<Addr, Reg>( 1082 f, 1083 a, 1084 GetRegisters(), 1085 &AssemblerTest::GetAddrName, 1086 &AssemblerTest::GetRegName<RegisterView::kUseTertiaryName>, 1087 fmt); 1088 } 1089 1090 // Repeats over addresses and quaternary registers provided by fixture. RepeatAb(void (Ass::* f)(const Addr &,Reg),const std::string & fmt)1091 std::string RepeatAb(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) { 1092 return RepeatAb(f, GetAddresses(), fmt); 1093 } 1094 1095 // Variant that takes explicit vector of addresss 1096 // (to test restricted addressing modes set). RepeatAb(void (Ass::* f)(const Addr &,Reg),const std::vector<Addr> & a,const std::string & fmt)1097 std::string RepeatAb(void (Ass::*f)(const Addr&, Reg), 1098 const std::vector<Addr>& a, 1099 const std::string& fmt) { 1100 return RepeatTemplatedMemReg<Addr, Reg>( 1101 f, 1102 a, 1103 GetRegisters(), 1104 &AssemblerTest::GetAddrName, 1105 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 1106 fmt); 1107 } 1108 1109 // Repeats over addresses and fp-registers provided by fixture. RepeatAF(void (Ass::* f)(const Addr &,FPReg),const std::string & fmt)1110 std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg), const std::string& fmt) { 1111 return RepeatAF(f, GetAddresses(), fmt); 1112 } 1113 1114 // Variant that takes explicit vector of addresss 1115 // (to test restricted addressing modes set). RepeatAF(void (Ass::* f)(const Addr &,FPReg),const std::vector<Addr> & a,const std::string & fmt)1116 std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg), 1117 const std::vector<Addr>& a, 1118 const std::string& fmt) { 1119 return RepeatTemplatedMemReg<Addr, FPReg>( 1120 f, 1121 a, 1122 GetFPRegisters(), 1123 &AssemblerTest::GetAddrName, 1124 &AssemblerTest::GetFPRegName, 1125 fmt); 1126 } 1127 1128 template <typename AddrType> RepeatTemplatedMem(void (Ass::* f)(const AddrType &),const std::vector<AddrType> addresses,std::string (AssemblerTest::* GetAName)(const AddrType &),const std::string & fmt)1129 std::string RepeatTemplatedMem(void (Ass::*f)(const AddrType&), 1130 const std::vector<AddrType> addresses, 1131 std::string (AssemblerTest::*GetAName)(const AddrType&), 1132 const std::string& fmt) { 1133 WarnOnCombinations(addresses.size()); 1134 std::string str; 1135 for (auto addr : addresses) { 1136 if (f != nullptr) { 1137 (assembler_.get()->*f)(addr); 1138 } 1139 std::string base = fmt; 1140 1141 std::string addr_string = (this->*GetAName)(addr); 1142 size_t addr_index; 1143 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) { 1144 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string); 1145 } 1146 1147 if (str.size() > 0) { 1148 str += "\n"; 1149 } 1150 str += base; 1151 } 1152 // Add a newline at the end. 1153 str += "\n"; 1154 return str; 1155 } 1156 1157 template <typename AddrType> RepeatTemplatedMemImm(void (Ass::* f)(const AddrType &,const Imm &),size_t imm_bytes,const std::vector<AddrType> addresses,std::string (AssemblerTest::* GetAName)(const AddrType &),const std::string & fmt)1158 std::string RepeatTemplatedMemImm(void (Ass::*f)(const AddrType&, const Imm&), 1159 size_t imm_bytes, 1160 const std::vector<AddrType> addresses, 1161 std::string (AssemblerTest::*GetAName)(const AddrType&), 1162 const std::string& fmt) { 1163 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 1164 WarnOnCombinations(addresses.size() * imms.size()); 1165 std::string str; 1166 for (auto addr : addresses) { 1167 for (int64_t imm : imms) { 1168 Imm new_imm = CreateImmediate(imm); 1169 if (f != nullptr) { 1170 (assembler_.get()->*f)(addr, new_imm); 1171 } 1172 std::string base = fmt; 1173 1174 std::string addr_string = (this->*GetAName)(addr); 1175 size_t addr_index; 1176 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) { 1177 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string); 1178 } 1179 1180 size_t imm_index = base.find(IMM_TOKEN); 1181 if (imm_index != std::string::npos) { 1182 std::ostringstream sreg; 1183 sreg << imm; 1184 std::string imm_string = sreg.str(); 1185 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 1186 } 1187 1188 if (str.size() > 0) { 1189 str += "\n"; 1190 } 1191 str += base; 1192 } 1193 } 1194 // Add a newline at the end. 1195 str += "\n"; 1196 return str; 1197 } 1198 1199 template <typename RegType, typename AddrType> RepeatTemplatedRegMem(void (Ass::* f)(RegType,const AddrType &),const std::vector<RegType * > registers,const std::vector<AddrType> addresses,std::string (AssemblerTest::* GetRName)(const RegType &),std::string (AssemblerTest::* GetAName)(const AddrType &),const std::string & fmt)1200 std::string RepeatTemplatedRegMem(void (Ass::*f)(RegType, const AddrType&), 1201 const std::vector<RegType*> registers, 1202 const std::vector<AddrType> addresses, 1203 std::string (AssemblerTest::*GetRName)(const RegType&), 1204 std::string (AssemblerTest::*GetAName)(const AddrType&), 1205 const std::string& fmt) { 1206 WarnOnCombinations(addresses.size() * registers.size()); 1207 std::string str; 1208 for (auto reg : registers) { 1209 for (auto addr : addresses) { 1210 if (f != nullptr) { 1211 (assembler_.get()->*f)(*reg, addr); 1212 } 1213 std::string base = fmt; 1214 1215 std::string reg_string = (this->*GetRName)(*reg); 1216 size_t reg_index; 1217 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 1218 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 1219 } 1220 1221 std::string addr_string = (this->*GetAName)(addr); 1222 size_t addr_index; 1223 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) { 1224 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string); 1225 } 1226 1227 if (str.size() > 0) { 1228 str += "\n"; 1229 } 1230 str += base; 1231 } 1232 } 1233 // Add a newline at the end. 1234 str += "\n"; 1235 return str; 1236 } 1237 1238 template <typename AddrType, typename RegType> RepeatTemplatedMemReg(void (Ass::* f)(const AddrType &,RegType),const std::vector<AddrType> addresses,const std::vector<RegType * > registers,std::string (AssemblerTest::* GetAName)(const AddrType &),std::string (AssemblerTest::* GetRName)(const RegType &),const std::string & fmt)1239 std::string RepeatTemplatedMemReg(void (Ass::*f)(const AddrType&, RegType), 1240 const std::vector<AddrType> addresses, 1241 const std::vector<RegType*> registers, 1242 std::string (AssemblerTest::*GetAName)(const AddrType&), 1243 std::string (AssemblerTest::*GetRName)(const RegType&), 1244 const std::string& fmt) { 1245 WarnOnCombinations(addresses.size() * registers.size()); 1246 std::string str; 1247 for (auto addr : addresses) { 1248 for (auto reg : registers) { 1249 if (f != nullptr) { 1250 (assembler_.get()->*f)(addr, *reg); 1251 } 1252 std::string base = fmt; 1253 1254 std::string addr_string = (this->*GetAName)(addr); 1255 size_t addr_index; 1256 if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) { 1257 base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string); 1258 } 1259 1260 std::string reg_string = (this->*GetRName)(*reg); 1261 size_t reg_index; 1262 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 1263 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 1264 } 1265 1266 if (str.size() > 0) { 1267 str += "\n"; 1268 } 1269 str += base; 1270 } 1271 } 1272 // Add a newline at the end. 1273 str += "\n"; 1274 return str; 1275 } 1276 1277 // 1278 // Register repeats. 1279 // 1280 1281 template <typename RegType> RepeatTemplatedRegister(void (Ass::* f)(RegType),const std::vector<RegType * > registers,std::string (AssemblerTest::* GetName)(const RegType &),const std::string & fmt)1282 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType), 1283 const std::vector<RegType*> registers, 1284 std::string (AssemblerTest::*GetName)(const RegType&), 1285 const std::string& fmt) { 1286 std::string str; 1287 for (auto reg : registers) { 1288 if (f != nullptr) { 1289 (assembler_.get()->*f)(*reg); 1290 } 1291 std::string base = fmt; 1292 1293 std::string reg_string = (this->*GetName)(*reg); 1294 size_t reg_index; 1295 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 1296 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 1297 } 1298 1299 if (str.size() > 0) { 1300 str += "\n"; 1301 } 1302 str += base; 1303 } 1304 // Add a newline at the end. 1305 str += "\n"; 1306 return str; 1307 } 1308 1309 template <typename Reg1, typename Reg2> RepeatTemplatedRegisters(void (Ass::* f)(Reg1,Reg2),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),const std::string & fmt)1310 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2), 1311 const std::vector<Reg1*> reg1_registers, 1312 const std::vector<Reg2*> reg2_registers, 1313 std::string (AssemblerTest::*GetName1)(const Reg1&), 1314 std::string (AssemblerTest::*GetName2)(const Reg2&), 1315 const std::string& fmt) { 1316 WarnOnCombinations(reg1_registers.size() * reg2_registers.size()); 1317 1318 std::string str; 1319 for (auto reg1 : reg1_registers) { 1320 for (auto reg2 : reg2_registers) { 1321 if (f != nullptr) { 1322 (assembler_.get()->*f)(*reg1, *reg2); 1323 } 1324 std::string base = fmt; 1325 1326 std::string reg1_string = (this->*GetName1)(*reg1); 1327 size_t reg1_index; 1328 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 1329 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 1330 } 1331 1332 std::string reg2_string = (this->*GetName2)(*reg2); 1333 size_t reg2_index; 1334 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 1335 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 1336 } 1337 1338 if (str.size() > 0) { 1339 str += "\n"; 1340 } 1341 str += base; 1342 } 1343 } 1344 // Add a newline at the end. 1345 str += "\n"; 1346 return str; 1347 } 1348 1349 template <typename Reg1, typename Reg2> RepeatTemplatedRegistersNoDupes(void (Ass::* f)(Reg1,Reg2),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),const std::string & fmt)1350 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2), 1351 const std::vector<Reg1*> reg1_registers, 1352 const std::vector<Reg2*> reg2_registers, 1353 std::string (AssemblerTest::*GetName1)(const Reg1&), 1354 std::string (AssemblerTest::*GetName2)(const Reg2&), 1355 const std::string& fmt) { 1356 WarnOnCombinations(reg1_registers.size() * reg2_registers.size()); 1357 1358 std::string str; 1359 for (auto reg1 : reg1_registers) { 1360 for (auto reg2 : reg2_registers) { 1361 if (reg1 == reg2) continue; 1362 if (f != nullptr) { 1363 (assembler_.get()->*f)(*reg1, *reg2); 1364 } 1365 std::string base = fmt; 1366 1367 std::string reg1_string = (this->*GetName1)(*reg1); 1368 size_t reg1_index; 1369 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 1370 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 1371 } 1372 1373 std::string reg2_string = (this->*GetName2)(*reg2); 1374 size_t reg2_index; 1375 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 1376 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 1377 } 1378 1379 if (str.size() > 0) { 1380 str += "\n"; 1381 } 1382 str += base; 1383 } 1384 } 1385 // Add a newline at the end. 1386 str += "\n"; 1387 return str; 1388 } 1389 1390 template <typename Reg1, typename Reg2, typename Reg3> RepeatTemplatedRegisters(void (Ass::* f)(Reg1,Reg2,Reg3),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,const std::vector<Reg3 * > reg3_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),std::string (AssemblerTest::* GetName3)(const Reg3 &),const std::string & fmt)1391 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3), 1392 const std::vector<Reg1*> reg1_registers, 1393 const std::vector<Reg2*> reg2_registers, 1394 const std::vector<Reg3*> reg3_registers, 1395 std::string (AssemblerTest::*GetName1)(const Reg1&), 1396 std::string (AssemblerTest::*GetName2)(const Reg2&), 1397 std::string (AssemblerTest::*GetName3)(const Reg3&), 1398 const std::string& fmt) { 1399 std::string str; 1400 for (auto reg1 : reg1_registers) { 1401 for (auto reg2 : reg2_registers) { 1402 for (auto reg3 : reg3_registers) { 1403 if (f != nullptr) { 1404 (assembler_.get()->*f)(*reg1, *reg2, *reg3); 1405 } 1406 std::string base = fmt; 1407 1408 std::string reg1_string = (this->*GetName1)(*reg1); 1409 size_t reg1_index; 1410 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 1411 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 1412 } 1413 1414 std::string reg2_string = (this->*GetName2)(*reg2); 1415 size_t reg2_index; 1416 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 1417 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 1418 } 1419 1420 std::string reg3_string = (this->*GetName3)(*reg3); 1421 size_t reg3_index; 1422 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) { 1423 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); 1424 } 1425 1426 if (str.size() > 0) { 1427 str += "\n"; 1428 } 1429 str += base; 1430 } 1431 } 1432 } 1433 // Add a newline at the end. 1434 str += "\n"; 1435 return str; 1436 } 1437 1438 template <typename Reg1, typename Reg2> RepeatTemplatedRegistersImm(void (Ass::* f)(Reg1,Reg2,const Imm &),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerTest::* GetName1)(const Reg1 &),std::string (AssemblerTest::* GetName2)(const Reg2 &),size_t imm_bytes,const std::string & fmt)1439 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&), 1440 const std::vector<Reg1*> reg1_registers, 1441 const std::vector<Reg2*> reg2_registers, 1442 std::string (AssemblerTest::*GetName1)(const Reg1&), 1443 std::string (AssemblerTest::*GetName2)(const Reg2&), 1444 size_t imm_bytes, 1445 const std::string& fmt) { 1446 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 1447 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); 1448 1449 std::string str; 1450 for (auto reg1 : reg1_registers) { 1451 for (auto reg2 : reg2_registers) { 1452 for (int64_t imm : imms) { 1453 Imm new_imm = CreateImmediate(imm); 1454 if (f != nullptr) { 1455 (assembler_.get()->*f)(*reg1, *reg2, new_imm); 1456 } 1457 std::string base = fmt; 1458 1459 std::string reg1_string = (this->*GetName1)(*reg1); 1460 size_t reg1_index; 1461 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 1462 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 1463 } 1464 1465 std::string reg2_string = (this->*GetName2)(*reg2); 1466 size_t reg2_index; 1467 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 1468 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 1469 } 1470 1471 size_t imm_index = base.find(IMM_TOKEN); 1472 if (imm_index != std::string::npos) { 1473 std::ostringstream sreg; 1474 sreg << imm; 1475 std::string imm_string = sreg.str(); 1476 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 1477 } 1478 1479 if (str.size() > 0) { 1480 str += "\n"; 1481 } 1482 str += base; 1483 } 1484 } 1485 } 1486 // Add a newline at the end. 1487 str += "\n"; 1488 return str; 1489 } 1490 GetAddrName(const Addr & addr)1491 std::string GetAddrName(const Addr& addr) { 1492 std::ostringstream saddr; 1493 saddr << addr; 1494 return saddr.str(); 1495 } 1496 1497 template <RegisterView kRegView> GetRegName(const Reg & reg)1498 std::string GetRegName(const Reg& reg) { 1499 std::ostringstream sreg; 1500 switch (kRegView) { 1501 case RegisterView::kUsePrimaryName: 1502 sreg << reg; 1503 break; 1504 1505 case RegisterView::kUseSecondaryName: 1506 sreg << GetSecondaryRegisterName(reg); 1507 break; 1508 1509 case RegisterView::kUseTertiaryName: 1510 sreg << GetTertiaryRegisterName(reg); 1511 break; 1512 1513 case RegisterView::kUseQuaternaryName: 1514 sreg << GetQuaternaryRegisterName(reg); 1515 break; 1516 } 1517 return sreg.str(); 1518 } 1519 GetFPRegName(const FPReg & reg)1520 std::string GetFPRegName(const FPReg& reg) { 1521 std::ostringstream sreg; 1522 sreg << reg; 1523 return sreg.str(); 1524 } 1525 GetVecRegName(const VecReg & reg)1526 std::string GetVecRegName(const VecReg& reg) { 1527 std::ostringstream sreg; 1528 sreg << reg; 1529 return sreg.str(); 1530 } 1531 1532 // If the assembly file needs a header, return it in a sub-class. GetAssemblyHeader()1533 virtual const char* GetAssemblyHeader() { 1534 return nullptr; 1535 } 1536 WarnOnCombinations(size_t count)1537 void WarnOnCombinations(size_t count) { 1538 if (count > kWarnManyCombinationsThreshold) { 1539 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow."; 1540 } 1541 } 1542 1543 static constexpr const char* ADDRESS_TOKEN = "{mem}"; 1544 static constexpr const char* REG_TOKEN = "{reg}"; 1545 static constexpr const char* REG1_TOKEN = "{reg1}"; 1546 static constexpr const char* REG2_TOKEN = "{reg2}"; 1547 static constexpr const char* REG3_TOKEN = "{reg3}"; 1548 static constexpr const char* IMM_TOKEN = "{imm}"; 1549 1550 private: 1551 template <RegisterView kRegView> RepeatRegisterImm(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)1552 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), 1553 size_t imm_bytes, 1554 const std::string& fmt) { 1555 const std::vector<Reg*> registers = GetRegisters(); 1556 std::string str; 1557 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 1558 1559 WarnOnCombinations(registers.size() * imms.size()); 1560 1561 for (auto reg : registers) { 1562 for (int64_t imm : imms) { 1563 Imm new_imm = CreateImmediate(imm); 1564 if (f != nullptr) { 1565 (assembler_.get()->*f)(*reg, new_imm); 1566 } 1567 std::string base = fmt; 1568 1569 std::string reg_string = GetRegName<kRegView>(*reg); 1570 size_t reg_index; 1571 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 1572 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 1573 } 1574 1575 size_t imm_index = base.find(IMM_TOKEN); 1576 if (imm_index != std::string::npos) { 1577 std::ostringstream sreg; 1578 sreg << imm; 1579 std::string imm_string = sreg.str(); 1580 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 1581 } 1582 1583 if (str.size() > 0) { 1584 str += "\n"; 1585 } 1586 str += base; 1587 } 1588 } 1589 // Add a newline at the end. 1590 str += "\n"; 1591 return str; 1592 } 1593 1594 // Override this to pad the code with NOPs to a certain size if needed. Pad(std::vector<uint8_t> & data ATTRIBUTE_UNUSED)1595 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) { 1596 } 1597 DriverWrapper(const std::string & assembly_text,const std::string & test_name)1598 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) { 1599 assembler_->FinalizeCode(); 1600 size_t cs = assembler_->CodeSize(); 1601 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs)); 1602 MemoryRegion code(&(*data)[0], data->size()); 1603 assembler_->FinalizeInstructions(code); 1604 Pad(*data); 1605 test_helper_->Driver(*data, assembly_text, test_name); 1606 } 1607 1608 static constexpr size_t kWarnManyCombinationsThreshold = 500; 1609 1610 MallocArenaPool pool_; 1611 std::unique_ptr<ArenaAllocator> allocator_; 1612 std::unique_ptr<Ass> assembler_; 1613 std::unique_ptr<AssemblerTestInfrastructure> test_helper_; 1614 1615 DISALLOW_COPY_AND_ASSIGN(AssemblerTest); 1616 }; 1617 1618 } // namespace art 1619 1620 #endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_ 1621