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 // For use in the template as the default type to get a nonvector registers version. 46 struct NoVectorRegs {}; 47 48 template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs> 49 class AssemblerTest : public testing::Test { 50 public: GetAssembler()51 Ass* GetAssembler() { 52 return assembler_.get(); 53 } 54 55 typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler); 56 DriverFn(TestFn f,const std::string & test_name)57 void DriverFn(TestFn f, const std::string& test_name) { 58 DriverWrapper(f(this, assembler_.get()), test_name); 59 } 60 61 // This driver assumes the assembler has already been called. DriverStr(const std::string & assembly_string,const std::string & test_name)62 void DriverStr(const std::string& assembly_string, const std::string& test_name) { 63 DriverWrapper(assembly_string, test_name); 64 } 65 RepeatR(void (Ass::* f)(Reg),const std::string & fmt)66 std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) { 67 return RepeatTemplatedRegister<Reg>(f, 68 GetRegisters(), 69 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 70 fmt); 71 } 72 Repeatr(void (Ass::* f)(Reg),const std::string & fmt)73 std::string Repeatr(void (Ass::*f)(Reg), const std::string& fmt) { 74 return RepeatTemplatedRegister<Reg>(f, 75 GetRegisters(), 76 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 77 fmt); 78 } 79 RepeatRR(void (Ass::* f)(Reg,Reg),const std::string & fmt)80 std::string RepeatRR(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 81 return RepeatTemplatedRegisters<Reg, Reg>(f, 82 GetRegisters(), 83 GetRegisters(), 84 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 85 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 86 fmt); 87 } 88 RepeatRRNoDupes(void (Ass::* f)(Reg,Reg),const std::string & fmt)89 std::string RepeatRRNoDupes(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 90 return RepeatTemplatedRegistersNoDupes<Reg, Reg>(f, 91 GetRegisters(), 92 GetRegisters(), 93 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 94 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 95 fmt); 96 } 97 Repeatrr(void (Ass::* f)(Reg,Reg),const std::string & fmt)98 std::string Repeatrr(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 99 return RepeatTemplatedRegisters<Reg, Reg>(f, 100 GetRegisters(), 101 GetRegisters(), 102 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 103 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 104 fmt); 105 } 106 RepeatRRR(void (Ass::* f)(Reg,Reg,Reg),const std::string & fmt)107 std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), const std::string& fmt) { 108 return RepeatTemplatedRegisters<Reg, Reg, Reg>(f, 109 GetRegisters(), 110 GetRegisters(), 111 GetRegisters(), 112 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 113 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 114 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 115 fmt); 116 } 117 Repeatrb(void (Ass::* f)(Reg,Reg),const std::string & fmt)118 std::string Repeatrb(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 119 return RepeatTemplatedRegisters<Reg, Reg>(f, 120 GetRegisters(), 121 GetRegisters(), 122 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 123 &AssemblerTest::GetRegName<RegisterView::kUseQuaternaryName>, 124 fmt); 125 } 126 RepeatRr(void (Ass::* f)(Reg,Reg),const std::string & fmt)127 std::string RepeatRr(void (Ass::*f)(Reg, Reg), const std::string& fmt) { 128 return RepeatTemplatedRegisters<Reg, Reg>(f, 129 GetRegisters(), 130 GetRegisters(), 131 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 132 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 133 fmt); 134 } 135 RepeatRI(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)136 std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) { 137 return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt); 138 } 139 Repeatri(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)140 std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, const std::string& fmt) { 141 return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt); 142 } 143 144 template <typename Reg1, typename Reg2, typename ImmType> 145 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, ImmType), 146 int imm_bits, 147 const std::vector<Reg1*> reg1_registers, 148 const std::vector<Reg2*> reg2_registers, 149 std::string (AssemblerTest::*GetName1)(const Reg1&), 150 std::string (AssemblerTest::*GetName2)(const Reg2&), 151 const std::string& fmt, 152 int bias = 0, 153 int multiplier = 1) { 154 std::string str; 155 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 156 157 for (auto reg1 : reg1_registers) { 158 for (auto reg2 : reg2_registers) { 159 for (int64_t imm : imms) { 160 ImmType new_imm = CreateImmediate(imm); 161 (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias); 162 std::string base = fmt; 163 164 std::string reg1_string = (this->*GetName1)(*reg1); 165 size_t reg1_index; 166 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 167 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 168 } 169 170 std::string reg2_string = (this->*GetName2)(*reg2); 171 size_t reg2_index; 172 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 173 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 174 } 175 176 size_t imm_index = base.find(IMM_TOKEN); 177 if (imm_index != std::string::npos) { 178 std::ostringstream sreg; 179 sreg << imm * multiplier + bias; 180 std::string imm_string = sreg.str(); 181 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 182 } 183 184 if (str.size() > 0) { 185 str += "\n"; 186 } 187 str += base; 188 } 189 } 190 } 191 // Add a newline at the end. 192 str += "\n"; 193 return str; 194 } 195 196 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)197 std::string RepeatTemplatedRegistersImmBits(void (Ass::*f)(Reg1, Reg2, Reg3, ImmType), 198 int imm_bits, 199 const std::vector<Reg1*> reg1_registers, 200 const std::vector<Reg2*> reg2_registers, 201 const std::vector<Reg3*> reg3_registers, 202 std::string (AssemblerTest::*GetName1)(const Reg1&), 203 std::string (AssemblerTest::*GetName2)(const Reg2&), 204 std::string (AssemblerTest::*GetName3)(const Reg3&), 205 std::string fmt, 206 int bias) { 207 std::string str; 208 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 209 210 for (auto reg1 : reg1_registers) { 211 for (auto reg2 : reg2_registers) { 212 for (auto reg3 : reg3_registers) { 213 for (int64_t imm : imms) { 214 ImmType new_imm = CreateImmediate(imm); 215 (assembler_.get()->*f)(*reg1, *reg2, *reg3, new_imm + bias); 216 std::string base = fmt; 217 218 std::string reg1_string = (this->*GetName1)(*reg1); 219 size_t reg1_index; 220 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 221 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 222 } 223 224 std::string reg2_string = (this->*GetName2)(*reg2); 225 size_t reg2_index; 226 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 227 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 228 } 229 230 std::string reg3_string = (this->*GetName3)(*reg3); 231 size_t reg3_index; 232 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) { 233 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); 234 } 235 236 size_t imm_index = base.find(IMM_TOKEN); 237 if (imm_index != std::string::npos) { 238 std::ostringstream sreg; 239 sreg << imm + bias; 240 std::string imm_string = sreg.str(); 241 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 242 } 243 244 if (str.size() > 0) { 245 str += "\n"; 246 } 247 str += base; 248 } 249 } 250 } 251 } 252 // Add a newline at the end. 253 str += "\n"; 254 return str; 255 } 256 257 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)258 std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2), 259 const std::vector<Reg1*> reg1_registers, 260 const std::vector<Reg2*> reg2_registers, 261 std::string (AssemblerTest::*GetName1)(const Reg1&), 262 std::string (AssemblerTest::*GetName2)(const Reg2&), 263 int imm_bits, 264 const std::string& fmt) { 265 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 266 267 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); 268 269 std::string str; 270 for (auto reg1 : reg1_registers) { 271 for (auto reg2 : reg2_registers) { 272 for (int64_t imm : imms) { 273 ImmType new_imm = CreateImmediate(imm); 274 (assembler_.get()->*f)(new_imm, *reg1, *reg2); 275 std::string base = fmt; 276 277 std::string reg1_string = (this->*GetName1)(*reg1); 278 size_t reg1_index; 279 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 280 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 281 } 282 283 std::string reg2_string = (this->*GetName2)(*reg2); 284 size_t reg2_index; 285 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 286 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 287 } 288 289 size_t imm_index = base.find(IMM_TOKEN); 290 if (imm_index != std::string::npos) { 291 std::ostringstream sreg; 292 sreg << imm; 293 std::string imm_string = sreg.str(); 294 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 295 } 296 297 if (str.size() > 0) { 298 str += "\n"; 299 } 300 str += base; 301 } 302 } 303 } 304 // Add a newline at the end. 305 str += "\n"; 306 return str; 307 } 308 309 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)310 std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType), 311 int imm_bits, 312 const std::vector<RegType*> registers, 313 std::string (AssemblerTest::*GetName)(const RegType&), 314 const std::string& fmt, 315 int bias) { 316 std::string str; 317 std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); 318 319 for (auto reg : registers) { 320 for (int64_t imm : imms) { 321 ImmType new_imm = CreateImmediate(imm); 322 (assembler_.get()->*f)(*reg, new_imm + bias); 323 std::string base = fmt; 324 325 std::string reg_string = (this->*GetName)(*reg); 326 size_t reg_index; 327 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 328 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 329 } 330 331 size_t imm_index = base.find(IMM_TOKEN); 332 if (imm_index != std::string::npos) { 333 std::ostringstream sreg; 334 sreg << imm + bias; 335 std::string imm_string = sreg.str(); 336 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 337 } 338 339 if (str.size() > 0) { 340 str += "\n"; 341 } 342 str += base; 343 } 344 } 345 // Add a newline at the end. 346 str += "\n"; 347 return str; 348 } 349 350 template <typename ImmType> 351 std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType), 352 int imm_bits, 353 const std::string& fmt, 354 int bias = 0) { 355 return RepeatTemplatedRegistersImmBits<Reg, Reg, ImmType>(f, 356 imm_bits, 357 GetRegisters(), 358 GetRegisters(), 359 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 360 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 361 fmt, 362 bias); 363 } 364 365 template <typename ImmType> 366 std::string RepeatRRRIb(void (Ass::*f)(Reg, Reg, Reg, ImmType), 367 int imm_bits, 368 const std::string& fmt, 369 int bias = 0) { 370 return RepeatTemplatedRegistersImmBits<Reg, Reg, Reg, ImmType>(f, 371 imm_bits, 372 GetRegisters(), 373 GetRegisters(), 374 GetRegisters(), 375 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 376 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 377 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 378 fmt, 379 bias); 380 } 381 382 template <typename ImmType> 383 std::string RepeatRIb(void (Ass::*f)(Reg, ImmType), int imm_bits, std::string fmt, int bias = 0) { 384 return RepeatTemplatedRegisterImmBits<Reg, ImmType>(f, 385 imm_bits, 386 GetRegisters(), 387 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 388 fmt, 389 bias); 390 } 391 392 template <typename ImmType> 393 std::string RepeatFRIb(void (Ass::*f)(FPReg, Reg, ImmType), 394 int imm_bits, 395 const std::string& fmt, 396 int bias = 0) { 397 return RepeatTemplatedRegistersImmBits<FPReg, Reg, ImmType>(f, 398 imm_bits, 399 GetFPRegisters(), 400 GetRegisters(), 401 &AssemblerTest::GetFPRegName, 402 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 403 fmt, 404 bias); 405 } 406 RepeatFF(void (Ass::* f)(FPReg,FPReg),const std::string & fmt)407 std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), const std::string& fmt) { 408 return RepeatTemplatedRegisters<FPReg, FPReg>(f, 409 GetFPRegisters(), 410 GetFPRegisters(), 411 &AssemblerTest::GetFPRegName, 412 &AssemblerTest::GetFPRegName, 413 fmt); 414 } 415 RepeatFFF(void (Ass::* f)(FPReg,FPReg,FPReg),const std::string & fmt)416 std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), const std::string& fmt) { 417 return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f, 418 GetFPRegisters(), 419 GetFPRegisters(), 420 GetFPRegisters(), 421 &AssemblerTest::GetFPRegName, 422 &AssemblerTest::GetFPRegName, 423 &AssemblerTest::GetFPRegName, 424 fmt); 425 } 426 RepeatFFR(void (Ass::* f)(FPReg,FPReg,Reg),const std::string & fmt)427 std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) { 428 return RepeatTemplatedRegisters<FPReg, FPReg, Reg>( 429 f, 430 GetFPRegisters(), 431 GetFPRegisters(), 432 GetRegisters(), 433 &AssemblerTest::GetFPRegName, 434 &AssemblerTest::GetFPRegName, 435 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 436 fmt); 437 } 438 RepeatFFI(void (Ass::* f)(FPReg,FPReg,const Imm &),size_t imm_bytes,const std::string & fmt)439 std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&), 440 size_t imm_bytes, 441 const std::string& fmt) { 442 return RepeatTemplatedRegistersImm<FPReg, FPReg>(f, 443 GetFPRegisters(), 444 GetFPRegisters(), 445 &AssemblerTest::GetFPRegName, 446 &AssemblerTest::GetFPRegName, 447 imm_bytes, 448 fmt); 449 } 450 451 template <typename ImmType> RepeatFFIb(void (Ass::* f)(FPReg,FPReg,ImmType),int imm_bits,const std::string & fmt)452 std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType), 453 int imm_bits, 454 const std::string& fmt) { 455 return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f, 456 imm_bits, 457 GetFPRegisters(), 458 GetFPRegisters(), 459 &AssemblerTest::GetFPRegName, 460 &AssemblerTest::GetFPRegName, 461 fmt); 462 } 463 464 template <typename ImmType> RepeatIbFF(void (Ass::* f)(ImmType,FPReg,FPReg),int imm_bits,const std::string & fmt)465 std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), 466 int imm_bits, 467 const std::string& fmt) { 468 return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f, 469 GetFPRegisters(), 470 GetFPRegisters(), 471 &AssemblerTest::GetFPRegName, 472 &AssemblerTest::GetFPRegName, 473 imm_bits, 474 fmt); 475 } 476 RepeatFR(void (Ass::* f)(FPReg,Reg),const std::string & fmt)477 std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) { 478 return RepeatTemplatedRegisters<FPReg, Reg>(f, 479 GetFPRegisters(), 480 GetRegisters(), 481 &AssemblerTest::GetFPRegName, 482 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 483 fmt); 484 } 485 RepeatFr(void (Ass::* f)(FPReg,Reg),const std::string & fmt)486 std::string RepeatFr(void (Ass::*f)(FPReg, Reg), const std::string& fmt) { 487 return RepeatTemplatedRegisters<FPReg, Reg>(f, 488 GetFPRegisters(), 489 GetRegisters(), 490 &AssemblerTest::GetFPRegName, 491 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 492 fmt); 493 } 494 RepeatRF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)495 std::string RepeatRF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) { 496 return RepeatTemplatedRegisters<Reg, FPReg>(f, 497 GetRegisters(), 498 GetFPRegisters(), 499 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 500 &AssemblerTest::GetFPRegName, 501 fmt); 502 } 503 RepeatrF(void (Ass::* f)(Reg,FPReg),const std::string & fmt)504 std::string RepeatrF(void (Ass::*f)(Reg, FPReg), const std::string& fmt) { 505 return RepeatTemplatedRegisters<Reg, FPReg>(f, 506 GetRegisters(), 507 GetFPRegisters(), 508 &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>, 509 &AssemblerTest::GetFPRegName, 510 fmt); 511 } 512 513 std::string RepeatI(void (Ass::*f)(const Imm&), 514 size_t imm_bytes, 515 const std::string& fmt, 516 bool as_uint = false) { 517 std::string str; 518 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint); 519 520 WarnOnCombinations(imms.size()); 521 522 for (int64_t imm : imms) { 523 Imm new_imm = CreateImmediate(imm); 524 (assembler_.get()->*f)(new_imm); 525 std::string base = fmt; 526 527 size_t imm_index = base.find(IMM_TOKEN); 528 if (imm_index != std::string::npos) { 529 std::ostringstream sreg; 530 sreg << imm; 531 std::string imm_string = sreg.str(); 532 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 533 } 534 535 if (str.size() > 0) { 536 str += "\n"; 537 } 538 str += base; 539 } 540 // Add a newline at the end. 541 str += "\n"; 542 return str; 543 } 544 RepeatVV(void (Ass::* f)(VecReg,VecReg),const std::string & fmt)545 std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) { 546 return RepeatTemplatedRegisters<VecReg, VecReg>(f, 547 GetVectorRegisters(), 548 GetVectorRegisters(), 549 &AssemblerTest::GetVecRegName, 550 &AssemblerTest::GetVecRegName, 551 fmt); 552 } 553 RepeatVVV(void (Ass::* f)(VecReg,VecReg,VecReg),const std::string & fmt)554 std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) { 555 return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f, 556 GetVectorRegisters(), 557 GetVectorRegisters(), 558 GetVectorRegisters(), 559 &AssemblerTest::GetVecRegName, 560 &AssemblerTest::GetVecRegName, 561 &AssemblerTest::GetVecRegName, 562 fmt); 563 } 564 RepeatVR(void (Ass::* f)(VecReg,Reg),const std::string & fmt)565 std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) { 566 return RepeatTemplatedRegisters<VecReg, Reg>( 567 f, 568 GetVectorRegisters(), 569 GetRegisters(), 570 &AssemblerTest::GetVecRegName, 571 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 572 fmt); 573 } 574 575 template <typename ImmType> 576 std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType), 577 int imm_bits, 578 std::string fmt, 579 int bias = 0) { 580 return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f, 581 imm_bits, 582 GetVectorRegisters(), 583 &AssemblerTest::GetVecRegName, 584 fmt, 585 bias); 586 } 587 588 template <typename ImmType> 589 std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType), 590 int imm_bits, 591 const std::string& fmt, 592 int bias = 0, 593 int multiplier = 1) { 594 return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>( 595 f, 596 imm_bits, 597 GetVectorRegisters(), 598 GetRegisters(), 599 &AssemblerTest::GetVecRegName, 600 &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>, 601 fmt, 602 bias, 603 multiplier); 604 } 605 606 template <typename ImmType> 607 std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType), 608 int imm_bits, 609 const std::string& fmt, 610 int bias = 0) { 611 return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f, 612 imm_bits, 613 GetVectorRegisters(), 614 GetVectorRegisters(), 615 &AssemblerTest::GetVecRegName, 616 &AssemblerTest::GetVecRegName, 617 fmt, 618 bias); 619 } 620 621 // This is intended to be run as a test. CheckTools()622 bool CheckTools() { 623 return test_helper_->CheckTools(); 624 } 625 626 // The following functions are public so that TestFn can use them... 627 628 virtual std::vector<Reg*> GetRegisters() = 0; 629 GetFPRegisters()630 virtual std::vector<FPReg*> GetFPRegisters() { 631 UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers"; 632 UNREACHABLE(); 633 } 634 GetVectorRegisters()635 virtual std::vector<VecReg*> GetVectorRegisters() { 636 UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers"; 637 UNREACHABLE(); 638 } 639 640 // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems. GetSecondaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)641 virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 642 UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers"; 643 UNREACHABLE(); 644 } 645 646 // Tertiary register names are the tertiary view on registers, e.g., 16b on 64b systems. GetTertiaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)647 virtual std::string GetTertiaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 648 UNIMPLEMENTED(FATAL) << "Architecture does not support tertiary registers"; 649 UNREACHABLE(); 650 } 651 652 // Quaternary register names are the quaternary view on registers, e.g., 8b on 64b systems. GetQuaternaryRegisterName(const Reg & reg ATTRIBUTE_UNUSED)653 virtual std::string GetQuaternaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) { 654 UNIMPLEMENTED(FATAL) << "Architecture does not support quaternary registers"; 655 UNREACHABLE(); 656 } 657 GetRegisterName(const Reg & reg)658 std::string GetRegisterName(const Reg& reg) { 659 return GetRegName<RegisterView::kUsePrimaryName>(reg); 660 } 661 662 protected: AssemblerTest()663 explicit AssemblerTest() {} 664 SetUp()665 void SetUp() OVERRIDE { 666 arena_.reset(new ArenaAllocator(&pool_)); 667 assembler_.reset(CreateAssembler(arena_.get())); 668 test_helper_.reset( 669 new AssemblerTestInfrastructure(GetArchitectureString(), 670 GetAssemblerCmdName(), 671 GetAssemblerParameters(), 672 GetObjdumpCmdName(), 673 GetObjdumpParameters(), 674 GetDisassembleCmdName(), 675 GetDisassembleParameters(), 676 GetAssemblyHeader())); 677 678 SetUpHelpers(); 679 } 680 TearDown()681 void TearDown() OVERRIDE { 682 test_helper_.reset(); // Clean up the helper. 683 assembler_.reset(); 684 arena_.reset(); 685 } 686 687 // Override this to set up any architecture-specific things, e.g., CPU revision. CreateAssembler(ArenaAllocator * arena)688 virtual Ass* CreateAssembler(ArenaAllocator* arena) { 689 return new (arena) Ass(arena); 690 } 691 692 // Override this to set up any architecture-specific things, e.g., register vectors. SetUpHelpers()693 virtual void SetUpHelpers() {} 694 695 // Get the typically used name for this architecture, e.g., aarch64, x86_64, ... 696 virtual std::string GetArchitectureString() = 0; 697 698 // Get the name of the assembler, e.g., "as" by default. GetAssemblerCmdName()699 virtual std::string GetAssemblerCmdName() { 700 return "as"; 701 } 702 703 // Switches to the assembler command. Default none. GetAssemblerParameters()704 virtual std::string GetAssemblerParameters() { 705 return ""; 706 } 707 708 // Get the name of the objdump, e.g., "objdump" by default. GetObjdumpCmdName()709 virtual std::string GetObjdumpCmdName() { 710 return "objdump"; 711 } 712 713 // Switches to the objdump command. Default is " -h". GetObjdumpParameters()714 virtual std::string GetObjdumpParameters() { 715 return " -h"; 716 } 717 718 // Get the name of the objdump, e.g., "objdump" by default. GetDisassembleCmdName()719 virtual std::string GetDisassembleCmdName() { 720 return "objdump"; 721 } 722 723 // Switches to the objdump command. As it's a binary, one needs to push the architecture and 724 // such to objdump, so it's architecture-specific and there is no default. 725 virtual std::string GetDisassembleParameters() = 0; 726 727 // Create a couple of immediate values up to the number of bytes given. 728 virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) { 729 std::vector<int64_t> res; 730 res.push_back(0); 731 if (!as_uint) { 732 res.push_back(-1); 733 } else { 734 res.push_back(0xFF); 735 } 736 res.push_back(0x12); 737 if (imm_bytes >= 2) { 738 res.push_back(0x1234); 739 if (!as_uint) { 740 res.push_back(-0x1234); 741 } else { 742 res.push_back(0xFFFF); 743 } 744 if (imm_bytes >= 4) { 745 res.push_back(0x12345678); 746 if (!as_uint) { 747 res.push_back(-0x12345678); 748 } else { 749 res.push_back(0xFFFFFFFF); 750 } 751 if (imm_bytes >= 6) { 752 res.push_back(0x123456789ABC); 753 if (!as_uint) { 754 res.push_back(-0x123456789ABC); 755 } 756 if (imm_bytes >= 8) { 757 res.push_back(0x123456789ABCDEF0); 758 if (!as_uint) { 759 res.push_back(-0x123456789ABCDEF0); 760 } else { 761 res.push_back(0xFFFFFFFFFFFFFFFF); 762 } 763 } 764 } 765 } 766 } 767 return res; 768 } 769 770 const int kMaxBitsExhaustiveTest = 8; 771 772 // Create a couple of immediate values up to the number of bits given. 773 virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) { 774 CHECK_GT(imm_bits, 0); 775 CHECK_LE(imm_bits, 64); 776 std::vector<int64_t> res; 777 778 if (imm_bits <= kMaxBitsExhaustiveTest) { 779 if (as_uint) { 780 for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) { 781 res.push_back(static_cast<int64_t>(i)); 782 } 783 } else { 784 for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) { 785 res.push_back(i); 786 } 787 } 788 } else { 789 if (as_uint) { 790 for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest); 791 i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest); 792 i++) { 793 res.push_back(static_cast<int64_t>(i)); 794 } 795 for (int i = 0; i <= imm_bits; i++) { 796 uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) + 797 ((MaxInt<uint64_t>(imm_bits) - 798 (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1)) 799 * i / imm_bits); 800 res.push_back(static_cast<int64_t>(j)); 801 } 802 } else { 803 for (int i = 0; i <= imm_bits; i++) { 804 int64_t j = MinInt<int64_t>(imm_bits) + 805 ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) - 806 MinInt<int64_t>(imm_bits)) 807 * i) / imm_bits); 808 res.push_back(static_cast<int64_t>(j)); 809 } 810 for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest); 811 i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest); 812 i++) { 813 res.push_back(static_cast<int64_t>(i)); 814 } 815 for (int i = 0; i <= imm_bits; i++) { 816 int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) + 817 ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1)) 818 * i / imm_bits); 819 res.push_back(static_cast<int64_t>(j)); 820 } 821 } 822 } 823 824 return res; 825 } 826 827 // Create an immediate from the specific value. 828 virtual Imm CreateImmediate(int64_t imm_value) = 0; 829 830 template <typename RegType> RepeatTemplatedRegister(void (Ass::* f)(RegType),const std::vector<RegType * > registers,std::string (AssemblerTest::* GetName)(const RegType &),const std::string & fmt)831 std::string RepeatTemplatedRegister(void (Ass::*f)(RegType), 832 const std::vector<RegType*> registers, 833 std::string (AssemblerTest::*GetName)(const RegType&), 834 const std::string& fmt) { 835 std::string str; 836 for (auto reg : registers) { 837 (assembler_.get()->*f)(*reg); 838 std::string base = fmt; 839 840 std::string reg_string = (this->*GetName)(*reg); 841 size_t reg_index; 842 if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 843 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 844 } 845 846 if (str.size() > 0) { 847 str += "\n"; 848 } 849 str += base; 850 } 851 // Add a newline at the end. 852 str += "\n"; 853 return str; 854 } 855 856 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)857 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2), 858 const std::vector<Reg1*> reg1_registers, 859 const std::vector<Reg2*> reg2_registers, 860 std::string (AssemblerTest::*GetName1)(const Reg1&), 861 std::string (AssemblerTest::*GetName2)(const Reg2&), 862 const std::string& fmt) { 863 WarnOnCombinations(reg1_registers.size() * reg2_registers.size()); 864 865 std::string str; 866 for (auto reg1 : reg1_registers) { 867 for (auto reg2 : reg2_registers) { 868 (assembler_.get()->*f)(*reg1, *reg2); 869 std::string base = fmt; 870 871 std::string reg1_string = (this->*GetName1)(*reg1); 872 size_t reg1_index; 873 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 874 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 875 } 876 877 std::string reg2_string = (this->*GetName2)(*reg2); 878 size_t reg2_index; 879 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 880 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 881 } 882 883 if (str.size() > 0) { 884 str += "\n"; 885 } 886 str += base; 887 } 888 } 889 // Add a newline at the end. 890 str += "\n"; 891 return str; 892 } 893 894 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)895 std::string RepeatTemplatedRegistersNoDupes(void (Ass::*f)(Reg1, Reg2), 896 const std::vector<Reg1*> reg1_registers, 897 const std::vector<Reg2*> reg2_registers, 898 std::string (AssemblerTest::*GetName1)(const Reg1&), 899 std::string (AssemblerTest::*GetName2)(const Reg2&), 900 const std::string& fmt) { 901 WarnOnCombinations(reg1_registers.size() * reg2_registers.size()); 902 903 std::string str; 904 for (auto reg1 : reg1_registers) { 905 for (auto reg2 : reg2_registers) { 906 if (reg1 == reg2) continue; 907 (assembler_.get()->*f)(*reg1, *reg2); 908 std::string base = fmt; 909 910 std::string reg1_string = (this->*GetName1)(*reg1); 911 size_t reg1_index; 912 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 913 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 914 } 915 916 std::string reg2_string = (this->*GetName2)(*reg2); 917 size_t reg2_index; 918 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 919 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 920 } 921 922 if (str.size() > 0) { 923 str += "\n"; 924 } 925 str += base; 926 } 927 } 928 // Add a newline at the end. 929 str += "\n"; 930 return str; 931 } 932 933 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)934 std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3), 935 const std::vector<Reg1*> reg1_registers, 936 const std::vector<Reg2*> reg2_registers, 937 const std::vector<Reg3*> reg3_registers, 938 std::string (AssemblerTest::*GetName1)(const Reg1&), 939 std::string (AssemblerTest::*GetName2)(const Reg2&), 940 std::string (AssemblerTest::*GetName3)(const Reg3&), 941 const std::string& fmt) { 942 std::string str; 943 for (auto reg1 : reg1_registers) { 944 for (auto reg2 : reg2_registers) { 945 for (auto reg3 : reg3_registers) { 946 (assembler_.get()->*f)(*reg1, *reg2, *reg3); 947 std::string base = fmt; 948 949 std::string reg1_string = (this->*GetName1)(*reg1); 950 size_t reg1_index; 951 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 952 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 953 } 954 955 std::string reg2_string = (this->*GetName2)(*reg2); 956 size_t reg2_index; 957 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 958 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 959 } 960 961 std::string reg3_string = (this->*GetName3)(*reg3); 962 size_t reg3_index; 963 while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) { 964 base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); 965 } 966 967 if (str.size() > 0) { 968 str += "\n"; 969 } 970 str += base; 971 } 972 } 973 } 974 // Add a newline at the end. 975 str += "\n"; 976 return str; 977 } 978 979 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)980 std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&), 981 const std::vector<Reg1*> reg1_registers, 982 const std::vector<Reg2*> reg2_registers, 983 std::string (AssemblerTest::*GetName1)(const Reg1&), 984 std::string (AssemblerTest::*GetName2)(const Reg2&), 985 size_t imm_bytes, 986 const std::string& fmt) { 987 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 988 WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); 989 990 std::string str; 991 for (auto reg1 : reg1_registers) { 992 for (auto reg2 : reg2_registers) { 993 for (int64_t imm : imms) { 994 Imm new_imm = CreateImmediate(imm); 995 (assembler_.get()->*f)(*reg1, *reg2, new_imm); 996 std::string base = fmt; 997 998 std::string reg1_string = (this->*GetName1)(*reg1); 999 size_t reg1_index; 1000 while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { 1001 base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); 1002 } 1003 1004 std::string reg2_string = (this->*GetName2)(*reg2); 1005 size_t reg2_index; 1006 while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { 1007 base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); 1008 } 1009 1010 size_t imm_index = base.find(IMM_TOKEN); 1011 if (imm_index != std::string::npos) { 1012 std::ostringstream sreg; 1013 sreg << imm; 1014 std::string imm_string = sreg.str(); 1015 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 1016 } 1017 1018 if (str.size() > 0) { 1019 str += "\n"; 1020 } 1021 str += base; 1022 } 1023 } 1024 } 1025 // Add a newline at the end. 1026 str += "\n"; 1027 return str; 1028 } 1029 1030 template <RegisterView kRegView> GetRegName(const Reg & reg)1031 std::string GetRegName(const Reg& reg) { 1032 std::ostringstream sreg; 1033 switch (kRegView) { 1034 case RegisterView::kUsePrimaryName: 1035 sreg << reg; 1036 break; 1037 1038 case RegisterView::kUseSecondaryName: 1039 sreg << GetSecondaryRegisterName(reg); 1040 break; 1041 1042 case RegisterView::kUseTertiaryName: 1043 sreg << GetTertiaryRegisterName(reg); 1044 break; 1045 1046 case RegisterView::kUseQuaternaryName: 1047 sreg << GetQuaternaryRegisterName(reg); 1048 break; 1049 } 1050 return sreg.str(); 1051 } 1052 GetFPRegName(const FPReg & reg)1053 std::string GetFPRegName(const FPReg& reg) { 1054 std::ostringstream sreg; 1055 sreg << reg; 1056 return sreg.str(); 1057 } 1058 GetVecRegName(const VecReg & reg)1059 std::string GetVecRegName(const VecReg& reg) { 1060 std::ostringstream sreg; 1061 sreg << reg; 1062 return sreg.str(); 1063 } 1064 1065 // If the assembly file needs a header, return it in a sub-class. GetAssemblyHeader()1066 virtual const char* GetAssemblyHeader() { 1067 return nullptr; 1068 } 1069 WarnOnCombinations(size_t count)1070 void WarnOnCombinations(size_t count) { 1071 if (count > kWarnManyCombinationsThreshold) { 1072 GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow."; 1073 } 1074 } 1075 1076 static constexpr const char* REG_TOKEN = "{reg}"; 1077 static constexpr const char* REG1_TOKEN = "{reg1}"; 1078 static constexpr const char* REG2_TOKEN = "{reg2}"; 1079 static constexpr const char* REG3_TOKEN = "{reg3}"; 1080 static constexpr const char* IMM_TOKEN = "{imm}"; 1081 1082 private: 1083 template <RegisterView kRegView> RepeatRegisterImm(void (Ass::* f)(Reg,const Imm &),size_t imm_bytes,const std::string & fmt)1084 std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), 1085 size_t imm_bytes, 1086 const std::string& fmt) { 1087 const std::vector<Reg*> registers = GetRegisters(); 1088 std::string str; 1089 std::vector<int64_t> imms = CreateImmediateValues(imm_bytes); 1090 1091 WarnOnCombinations(registers.size() * imms.size()); 1092 1093 for (auto reg : registers) { 1094 for (int64_t imm : imms) { 1095 Imm new_imm = CreateImmediate(imm); 1096 (assembler_.get()->*f)(*reg, new_imm); 1097 std::string base = fmt; 1098 1099 std::string reg_string = GetRegName<kRegView>(*reg); 1100 size_t reg_index; 1101 while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) { 1102 base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string); 1103 } 1104 1105 size_t imm_index = base.find(IMM_TOKEN); 1106 if (imm_index != std::string::npos) { 1107 std::ostringstream sreg; 1108 sreg << imm; 1109 std::string imm_string = sreg.str(); 1110 base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); 1111 } 1112 1113 if (str.size() > 0) { 1114 str += "\n"; 1115 } 1116 str += base; 1117 } 1118 } 1119 // Add a newline at the end. 1120 str += "\n"; 1121 return str; 1122 } 1123 1124 // Override this to pad the code with NOPs to a certain size if needed. Pad(std::vector<uint8_t> & data ATTRIBUTE_UNUSED)1125 virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) { 1126 } 1127 DriverWrapper(const std::string & assembly_text,const std::string & test_name)1128 void DriverWrapper(const std::string& assembly_text, const std::string& test_name) { 1129 assembler_->FinalizeCode(); 1130 size_t cs = assembler_->CodeSize(); 1131 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs)); 1132 MemoryRegion code(&(*data)[0], data->size()); 1133 assembler_->FinalizeInstructions(code); 1134 Pad(*data); 1135 test_helper_->Driver(*data, assembly_text, test_name); 1136 } 1137 1138 static constexpr size_t kWarnManyCombinationsThreshold = 500; 1139 1140 ArenaPool pool_; 1141 std::unique_ptr<ArenaAllocator> arena_; 1142 std::unique_ptr<Ass> assembler_; 1143 std::unique_ptr<AssemblerTestInfrastructure> test_helper_; 1144 1145 DISALLOW_COPY_AND_ASSIGN(AssemblerTest); 1146 }; 1147 1148 } // namespace art 1149 1150 #endif // ART_COMPILER_UTILS_ASSEMBLER_TEST_H_ 1151