1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <dirent.h> 18 #include <fstream> 19 #include <sys/types.h> 20 #include <map> 21 22 #include "gtest/gtest.h" 23 #include "utils/arm/assembler_thumb2.h" 24 #include "base/hex_dump.h" 25 #include "common_runtime_test.h" 26 27 namespace art { 28 namespace arm { 29 30 // Include results file (generated manually) 31 #include "assembler_thumb_test_expected.cc.inc" 32 33 #ifndef HAVE_ANDROID_OS 34 // This controls whether the results are printed to the 35 // screen or compared against the expected output. 36 // To generate new expected output, set this to true and 37 // copy the output into the .cc.inc file in the form 38 // of the other results. 39 // 40 // When this is false, the results are not printed to the 41 // output, but are compared against the expected results 42 // in the .cc.inc file. 43 static constexpr bool kPrintResults = false; 44 #endif 45 46 static const char* TOOL_PREFIX = "arm-linux-androideabi-"; 47 48 void SetAndroidData() { 49 const char* data = getenv("ANDROID_DATA"); 50 if (data == nullptr) { 51 setenv("ANDROID_DATA", "/tmp", 1); 52 } 53 } 54 55 int CompareIgnoringSpace(const char* s1, const char* s2) { 56 while (*s1 != '\0') { 57 while (isspace(*s1)) ++s1; 58 while (isspace(*s2)) ++s2; 59 if (*s1 == '\0' || *s1 != *s2) { 60 break; 61 } 62 ++s1; 63 ++s2; 64 } 65 return *s1 - *s2; 66 } 67 68 std::string GetAndroidToolsDir() { 69 std::string root; 70 const char* android_build_top = getenv("ANDROID_BUILD_TOP"); 71 if (android_build_top != nullptr) { 72 root += android_build_top; 73 } else { 74 // Not set by build server, so default to current directory 75 char* cwd = getcwd(nullptr, 0); 76 setenv("ANDROID_BUILD_TOP", cwd, 1); 77 root += cwd; 78 free(cwd); 79 } 80 81 // Look for "prebuilts" 82 std::string toolsdir = root; 83 struct stat st; 84 while (toolsdir != "") { 85 std::string prebuilts = toolsdir + "/prebuilts"; 86 if (stat(prebuilts.c_str(), &st) == 0) { 87 // Found prebuilts. 88 toolsdir += "/prebuilts/gcc/linux-x86/arm"; 89 break; 90 } 91 // Not present, move up one dir. 92 size_t slash = toolsdir.rfind('/'); 93 if (slash == std::string::npos) { 94 toolsdir = ""; 95 } else { 96 toolsdir = toolsdir.substr(0, slash-1); 97 } 98 } 99 bool statok = stat(toolsdir.c_str(), &st) == 0; 100 if (!statok) { 101 return ""; // Use path. 102 } 103 104 DIR* dir = opendir(toolsdir.c_str()); 105 if (dir == nullptr) { 106 return ""; // Use path. 107 } 108 109 struct dirent* entry; 110 std::string founddir; 111 double maxversion = 0; 112 113 // Find the latest version of the arm-eabi tools (biggest version number). 114 // Suffix on toolsdir will be something like "arm-eabi-4.8" 115 while ((entry = readdir(dir)) != nullptr) { 116 std::string subdir = toolsdir + std::string("/") + std::string(entry->d_name); 117 size_t eabi = subdir.find(TOOL_PREFIX); 118 if (eabi != std::string::npos) { 119 std::string suffix = subdir.substr(eabi + strlen(TOOL_PREFIX)); 120 double version = strtod(suffix.c_str(), nullptr); 121 if (version > maxversion) { 122 maxversion = version; 123 founddir = subdir; 124 } 125 } 126 } 127 closedir(dir); 128 bool found = founddir != ""; 129 if (!found) { 130 return ""; // Use path. 131 } 132 133 return founddir + "/bin/"; 134 } 135 136 void dump(std::vector<uint8_t>& code, const char* testname) { 137 // This will only work on the host. There is no as, objcopy or objdump on the 138 // device. 139 #ifndef HAVE_ANDROID_OS 140 static bool results_ok = false; 141 static std::string toolsdir; 142 143 if (!results_ok) { 144 setup_results(); 145 toolsdir = GetAndroidToolsDir(); 146 SetAndroidData(); 147 results_ok = true; 148 } 149 150 ScratchFile file; 151 152 const char* filename = file.GetFilename().c_str(); 153 154 std::ofstream out(filename); 155 if (out) { 156 out << ".section \".text\"\n"; 157 out << ".syntax unified\n"; 158 out << ".arch armv7-a\n"; 159 out << ".thumb\n"; 160 out << ".thumb_func\n"; 161 out << ".type " << testname << ", #function\n"; 162 out << ".global " << testname << "\n"; 163 out << testname << ":\n"; 164 out << ".fnstart\n"; 165 166 for (uint32_t i = 0 ; i < code.size(); ++i) { 167 out << ".byte " << (static_cast<int>(code[i]) & 0xff) << "\n"; 168 } 169 out << ".fnend\n"; 170 out << ".size " << testname << ", .-" << testname << "\n"; 171 } 172 out.close(); 173 174 char cmd[1024]; 175 176 // Assemble the .S 177 snprintf(cmd, sizeof(cmd), "%s%sas %s -o %s.o", toolsdir.c_str(), TOOL_PREFIX, filename, filename); 178 system(cmd); 179 180 // Remove the $d symbols to prevent the disassembler dumping the instructions 181 // as .word 182 snprintf(cmd, sizeof(cmd), "%s%sobjcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), TOOL_PREFIX, 183 filename, filename); 184 system(cmd); 185 186 // Disassemble. 187 188 snprintf(cmd, sizeof(cmd), "%s%sobjdump -d %s.oo | grep '^ *[0-9a-f][0-9a-f]*:'", 189 toolsdir.c_str(), TOOL_PREFIX, filename); 190 if (kPrintResults) { 191 // Print the results only, don't check. This is used to generate new output for inserting 192 // into the .inc file. 193 system(cmd); 194 } else { 195 // Check the results match the appropriate results in the .inc file. 196 FILE *fp = popen(cmd, "r"); 197 ASSERT_TRUE(fp != nullptr); 198 199 std::map<std::string, const char**>::iterator results = test_results.find(testname); 200 ASSERT_NE(results, test_results.end()); 201 202 uint32_t lineindex = 0; 203 204 while (!feof(fp)) { 205 char testline[256]; 206 char *s = fgets(testline, sizeof(testline), fp); 207 if (s == nullptr) { 208 break; 209 } 210 if (CompareIgnoringSpace(results->second[lineindex], testline) != 0) { 211 LOG(FATAL) << "Output is not as expected at line: " << lineindex 212 << results->second[lineindex] << "/" << testline; 213 } 214 ++lineindex; 215 } 216 // Check that we are at the end. 217 ASSERT_TRUE(results->second[lineindex] == nullptr); 218 fclose(fp); 219 } 220 221 char buf[FILENAME_MAX]; 222 snprintf(buf, sizeof(buf), "%s.o", filename); 223 unlink(buf); 224 225 snprintf(buf, sizeof(buf), "%s.oo", filename); 226 unlink(buf); 227 #endif 228 } 229 230 #define __ assembler-> 231 232 TEST(Thumb2AssemblerTest, SimpleMov) { 233 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 234 235 __ mov(R0, ShifterOperand(R1)); 236 __ mov(R8, ShifterOperand(R9)); 237 238 __ mov(R0, ShifterOperand(1)); 239 __ mov(R8, ShifterOperand(9)); 240 241 size_t cs = __ CodeSize(); 242 std::vector<uint8_t> managed_code(cs); 243 MemoryRegion code(&managed_code[0], managed_code.size()); 244 __ FinalizeInstructions(code); 245 dump(managed_code, "SimpleMov"); 246 delete assembler; 247 } 248 249 TEST(Thumb2AssemblerTest, SimpleMov32) { 250 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 251 assembler->Force32Bit(); 252 253 __ mov(R0, ShifterOperand(R1)); 254 __ mov(R8, ShifterOperand(R9)); 255 256 size_t cs = __ CodeSize(); 257 std::vector<uint8_t> managed_code(cs); 258 MemoryRegion code(&managed_code[0], managed_code.size()); 259 __ FinalizeInstructions(code); 260 dump(managed_code, "SimpleMov32"); 261 delete assembler; 262 } 263 264 TEST(Thumb2AssemblerTest, SimpleMovAdd) { 265 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 266 267 __ mov(R0, ShifterOperand(R1)); 268 __ add(R0, R1, ShifterOperand(R2)); 269 __ add(R0, R1, ShifterOperand()); 270 271 size_t cs = __ CodeSize(); 272 std::vector<uint8_t> managed_code(cs); 273 MemoryRegion code(&managed_code[0], managed_code.size()); 274 __ FinalizeInstructions(code); 275 dump(managed_code, "SimpleMovAdd"); 276 delete assembler; 277 } 278 279 TEST(Thumb2AssemblerTest, DataProcessingRegister) { 280 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 281 282 __ mov(R0, ShifterOperand(R1)); 283 __ mvn(R0, ShifterOperand(R1)); 284 285 // 32 bit variants. 286 __ add(R0, R1, ShifterOperand(R2)); 287 __ sub(R0, R1, ShifterOperand(R2)); 288 __ and_(R0, R1, ShifterOperand(R2)); 289 __ orr(R0, R1, ShifterOperand(R2)); 290 __ eor(R0, R1, ShifterOperand(R2)); 291 __ bic(R0, R1, ShifterOperand(R2)); 292 __ adc(R0, R1, ShifterOperand(R2)); 293 __ sbc(R0, R1, ShifterOperand(R2)); 294 __ rsb(R0, R1, ShifterOperand(R2)); 295 296 // 16 bit variants. 297 __ add(R0, R1, ShifterOperand()); 298 __ sub(R0, R1, ShifterOperand()); 299 __ and_(R0, R1, ShifterOperand()); 300 __ orr(R0, R1, ShifterOperand()); 301 __ eor(R0, R1, ShifterOperand()); 302 __ bic(R0, R1, ShifterOperand()); 303 __ adc(R0, R1, ShifterOperand()); 304 __ sbc(R0, R1, ShifterOperand()); 305 __ rsb(R0, R1, ShifterOperand()); 306 307 __ tst(R0, ShifterOperand(R1)); 308 __ teq(R0, ShifterOperand(R1)); 309 __ cmp(R0, ShifterOperand(R1)); 310 __ cmn(R0, ShifterOperand(R1)); 311 312 __ movs(R0, ShifterOperand(R1)); 313 __ mvns(R0, ShifterOperand(R1)); 314 315 // 32 bit variants. 316 __ add(R12, R1, ShifterOperand(R0)); 317 318 size_t cs = __ CodeSize(); 319 std::vector<uint8_t> managed_code(cs); 320 MemoryRegion code(&managed_code[0], managed_code.size()); 321 __ FinalizeInstructions(code); 322 dump(managed_code, "DataProcessingRegister"); 323 delete assembler; 324 } 325 326 TEST(Thumb2AssemblerTest, DataProcessingImmediate) { 327 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 328 329 __ mov(R0, ShifterOperand(0x55)); 330 __ mvn(R0, ShifterOperand(0x55)); 331 __ add(R0, R1, ShifterOperand(0x55)); 332 __ sub(R0, R1, ShifterOperand(0x55)); 333 __ and_(R0, R1, ShifterOperand(0x55)); 334 __ orr(R0, R1, ShifterOperand(0x55)); 335 __ eor(R0, R1, ShifterOperand(0x55)); 336 __ bic(R0, R1, ShifterOperand(0x55)); 337 __ adc(R0, R1, ShifterOperand(0x55)); 338 __ sbc(R0, R1, ShifterOperand(0x55)); 339 __ rsb(R0, R1, ShifterOperand(0x55)); 340 341 __ tst(R0, ShifterOperand(0x55)); 342 __ teq(R0, ShifterOperand(0x55)); 343 __ cmp(R0, ShifterOperand(0x55)); 344 __ cmn(R0, ShifterOperand(0x55)); 345 346 __ add(R0, R1, ShifterOperand(5)); 347 __ sub(R0, R1, ShifterOperand(5)); 348 349 __ movs(R0, ShifterOperand(0x55)); 350 __ mvns(R0, ShifterOperand(0x55)); 351 352 size_t cs = __ CodeSize(); 353 std::vector<uint8_t> managed_code(cs); 354 MemoryRegion code(&managed_code[0], managed_code.size()); 355 __ FinalizeInstructions(code); 356 dump(managed_code, "DataProcessingImmediate"); 357 delete assembler; 358 } 359 360 TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediate) { 361 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 362 363 __ mov(R0, ShifterOperand(0x550055)); 364 __ mvn(R0, ShifterOperand(0x550055)); 365 __ add(R0, R1, ShifterOperand(0x550055)); 366 __ sub(R0, R1, ShifterOperand(0x550055)); 367 __ and_(R0, R1, ShifterOperand(0x550055)); 368 __ orr(R0, R1, ShifterOperand(0x550055)); 369 __ eor(R0, R1, ShifterOperand(0x550055)); 370 __ bic(R0, R1, ShifterOperand(0x550055)); 371 __ adc(R0, R1, ShifterOperand(0x550055)); 372 __ sbc(R0, R1, ShifterOperand(0x550055)); 373 __ rsb(R0, R1, ShifterOperand(0x550055)); 374 375 __ tst(R0, ShifterOperand(0x550055)); 376 __ teq(R0, ShifterOperand(0x550055)); 377 __ cmp(R0, ShifterOperand(0x550055)); 378 __ cmn(R0, ShifterOperand(0x550055)); 379 380 size_t cs = __ CodeSize(); 381 std::vector<uint8_t> managed_code(cs); 382 MemoryRegion code(&managed_code[0], managed_code.size()); 383 __ FinalizeInstructions(code); 384 dump(managed_code, "DataProcessingModifiedImmediate"); 385 delete assembler; 386 } 387 388 389 TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediates) { 390 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 391 392 __ mov(R0, ShifterOperand(0x550055)); 393 __ mov(R0, ShifterOperand(0x55005500)); 394 __ mov(R0, ShifterOperand(0x55555555)); 395 __ mov(R0, ShifterOperand(0xd5000000)); // rotated to first position 396 __ mov(R0, ShifterOperand(0x6a000000)); // rotated to second position 397 __ mov(R0, ShifterOperand(0x350)); // rotated to 2nd last position 398 __ mov(R0, ShifterOperand(0x1a8)); // rotated to last position 399 400 size_t cs = __ CodeSize(); 401 std::vector<uint8_t> managed_code(cs); 402 MemoryRegion code(&managed_code[0], managed_code.size()); 403 __ FinalizeInstructions(code); 404 dump(managed_code, "DataProcessingModifiedImmediates"); 405 delete assembler; 406 } 407 408 TEST(Thumb2AssemblerTest, DataProcessingShiftedRegister) { 409 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 410 411 __ mov(R3, ShifterOperand(R4, LSL, 4)); 412 __ mov(R3, ShifterOperand(R4, LSR, 5)); 413 __ mov(R3, ShifterOperand(R4, ASR, 6)); 414 __ mov(R3, ShifterOperand(R4, ROR, 7)); 415 __ mov(R3, ShifterOperand(R4, ROR)); 416 417 // 32 bit variants. 418 __ mov(R8, ShifterOperand(R4, LSL, 4)); 419 __ mov(R8, ShifterOperand(R4, LSR, 5)); 420 __ mov(R8, ShifterOperand(R4, ASR, 6)); 421 __ mov(R8, ShifterOperand(R4, ROR, 7)); 422 __ mov(R8, ShifterOperand(R4, RRX)); 423 424 size_t cs = __ CodeSize(); 425 std::vector<uint8_t> managed_code(cs); 426 MemoryRegion code(&managed_code[0], managed_code.size()); 427 __ FinalizeInstructions(code); 428 dump(managed_code, "DataProcessingShiftedRegister"); 429 delete assembler; 430 } 431 432 433 TEST(Thumb2AssemblerTest, BasicLoad) { 434 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 435 436 __ ldr(R3, Address(R4, 24)); 437 __ ldrb(R3, Address(R4, 24)); 438 __ ldrh(R3, Address(R4, 24)); 439 __ ldrsb(R3, Address(R4, 24)); 440 __ ldrsh(R3, Address(R4, 24)); 441 442 __ ldr(R3, Address(SP, 24)); 443 444 // 32 bit variants 445 __ ldr(R8, Address(R4, 24)); 446 __ ldrb(R8, Address(R4, 24)); 447 __ ldrh(R8, Address(R4, 24)); 448 __ ldrsb(R8, Address(R4, 24)); 449 __ ldrsh(R8, Address(R4, 24)); 450 451 size_t cs = __ CodeSize(); 452 std::vector<uint8_t> managed_code(cs); 453 MemoryRegion code(&managed_code[0], managed_code.size()); 454 __ FinalizeInstructions(code); 455 dump(managed_code, "BasicLoad"); 456 delete assembler; 457 } 458 459 460 TEST(Thumb2AssemblerTest, BasicStore) { 461 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 462 463 __ str(R3, Address(R4, 24)); 464 __ strb(R3, Address(R4, 24)); 465 __ strh(R3, Address(R4, 24)); 466 467 __ str(R3, Address(SP, 24)); 468 469 // 32 bit variants. 470 __ str(R8, Address(R4, 24)); 471 __ strb(R8, Address(R4, 24)); 472 __ strh(R8, Address(R4, 24)); 473 474 size_t cs = __ CodeSize(); 475 std::vector<uint8_t> managed_code(cs); 476 MemoryRegion code(&managed_code[0], managed_code.size()); 477 __ FinalizeInstructions(code); 478 dump(managed_code, "BasicStore"); 479 delete assembler; 480 } 481 482 TEST(Thumb2AssemblerTest, ComplexLoad) { 483 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 484 485 __ ldr(R3, Address(R4, 24, Address::Mode::Offset)); 486 __ ldr(R3, Address(R4, 24, Address::Mode::PreIndex)); 487 __ ldr(R3, Address(R4, 24, Address::Mode::PostIndex)); 488 __ ldr(R3, Address(R4, 24, Address::Mode::NegOffset)); 489 __ ldr(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 490 __ ldr(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 491 492 __ ldrb(R3, Address(R4, 24, Address::Mode::Offset)); 493 __ ldrb(R3, Address(R4, 24, Address::Mode::PreIndex)); 494 __ ldrb(R3, Address(R4, 24, Address::Mode::PostIndex)); 495 __ ldrb(R3, Address(R4, 24, Address::Mode::NegOffset)); 496 __ ldrb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 497 __ ldrb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 498 499 __ ldrh(R3, Address(R4, 24, Address::Mode::Offset)); 500 __ ldrh(R3, Address(R4, 24, Address::Mode::PreIndex)); 501 __ ldrh(R3, Address(R4, 24, Address::Mode::PostIndex)); 502 __ ldrh(R3, Address(R4, 24, Address::Mode::NegOffset)); 503 __ ldrh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 504 __ ldrh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 505 506 __ ldrsb(R3, Address(R4, 24, Address::Mode::Offset)); 507 __ ldrsb(R3, Address(R4, 24, Address::Mode::PreIndex)); 508 __ ldrsb(R3, Address(R4, 24, Address::Mode::PostIndex)); 509 __ ldrsb(R3, Address(R4, 24, Address::Mode::NegOffset)); 510 __ ldrsb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 511 __ ldrsb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 512 513 __ ldrsh(R3, Address(R4, 24, Address::Mode::Offset)); 514 __ ldrsh(R3, Address(R4, 24, Address::Mode::PreIndex)); 515 __ ldrsh(R3, Address(R4, 24, Address::Mode::PostIndex)); 516 __ ldrsh(R3, Address(R4, 24, Address::Mode::NegOffset)); 517 __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 518 __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 519 520 size_t cs = __ CodeSize(); 521 std::vector<uint8_t> managed_code(cs); 522 MemoryRegion code(&managed_code[0], managed_code.size()); 523 __ FinalizeInstructions(code); 524 dump(managed_code, "ComplexLoad"); 525 delete assembler; 526 } 527 528 529 TEST(Thumb2AssemblerTest, ComplexStore) { 530 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 531 532 __ str(R3, Address(R4, 24, Address::Mode::Offset)); 533 __ str(R3, Address(R4, 24, Address::Mode::PreIndex)); 534 __ str(R3, Address(R4, 24, Address::Mode::PostIndex)); 535 __ str(R3, Address(R4, 24, Address::Mode::NegOffset)); 536 __ str(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 537 __ str(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 538 539 __ strb(R3, Address(R4, 24, Address::Mode::Offset)); 540 __ strb(R3, Address(R4, 24, Address::Mode::PreIndex)); 541 __ strb(R3, Address(R4, 24, Address::Mode::PostIndex)); 542 __ strb(R3, Address(R4, 24, Address::Mode::NegOffset)); 543 __ strb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 544 __ strb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 545 546 __ strh(R3, Address(R4, 24, Address::Mode::Offset)); 547 __ strh(R3, Address(R4, 24, Address::Mode::PreIndex)); 548 __ strh(R3, Address(R4, 24, Address::Mode::PostIndex)); 549 __ strh(R3, Address(R4, 24, Address::Mode::NegOffset)); 550 __ strh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 551 __ strh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 552 553 size_t cs = __ CodeSize(); 554 std::vector<uint8_t> managed_code(cs); 555 MemoryRegion code(&managed_code[0], managed_code.size()); 556 __ FinalizeInstructions(code); 557 dump(managed_code, "ComplexStore"); 558 delete assembler; 559 } 560 561 TEST(Thumb2AssemblerTest, NegativeLoadStore) { 562 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 563 564 __ ldr(R3, Address(R4, -24, Address::Mode::Offset)); 565 __ ldr(R3, Address(R4, -24, Address::Mode::PreIndex)); 566 __ ldr(R3, Address(R4, -24, Address::Mode::PostIndex)); 567 __ ldr(R3, Address(R4, -24, Address::Mode::NegOffset)); 568 __ ldr(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 569 __ ldr(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 570 571 __ ldrb(R3, Address(R4, -24, Address::Mode::Offset)); 572 __ ldrb(R3, Address(R4, -24, Address::Mode::PreIndex)); 573 __ ldrb(R3, Address(R4, -24, Address::Mode::PostIndex)); 574 __ ldrb(R3, Address(R4, -24, Address::Mode::NegOffset)); 575 __ ldrb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 576 __ ldrb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 577 578 __ ldrh(R3, Address(R4, -24, Address::Mode::Offset)); 579 __ ldrh(R3, Address(R4, -24, Address::Mode::PreIndex)); 580 __ ldrh(R3, Address(R4, -24, Address::Mode::PostIndex)); 581 __ ldrh(R3, Address(R4, -24, Address::Mode::NegOffset)); 582 __ ldrh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 583 __ ldrh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 584 585 __ ldrsb(R3, Address(R4, -24, Address::Mode::Offset)); 586 __ ldrsb(R3, Address(R4, -24, Address::Mode::PreIndex)); 587 __ ldrsb(R3, Address(R4, -24, Address::Mode::PostIndex)); 588 __ ldrsb(R3, Address(R4, -24, Address::Mode::NegOffset)); 589 __ ldrsb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 590 __ ldrsb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 591 592 __ ldrsh(R3, Address(R4, -24, Address::Mode::Offset)); 593 __ ldrsh(R3, Address(R4, -24, Address::Mode::PreIndex)); 594 __ ldrsh(R3, Address(R4, -24, Address::Mode::PostIndex)); 595 __ ldrsh(R3, Address(R4, -24, Address::Mode::NegOffset)); 596 __ ldrsh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 597 __ ldrsh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 598 599 __ str(R3, Address(R4, -24, Address::Mode::Offset)); 600 __ str(R3, Address(R4, -24, Address::Mode::PreIndex)); 601 __ str(R3, Address(R4, -24, Address::Mode::PostIndex)); 602 __ str(R3, Address(R4, -24, Address::Mode::NegOffset)); 603 __ str(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 604 __ str(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 605 606 __ strb(R3, Address(R4, -24, Address::Mode::Offset)); 607 __ strb(R3, Address(R4, -24, Address::Mode::PreIndex)); 608 __ strb(R3, Address(R4, -24, Address::Mode::PostIndex)); 609 __ strb(R3, Address(R4, -24, Address::Mode::NegOffset)); 610 __ strb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 611 __ strb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 612 613 __ strh(R3, Address(R4, -24, Address::Mode::Offset)); 614 __ strh(R3, Address(R4, -24, Address::Mode::PreIndex)); 615 __ strh(R3, Address(R4, -24, Address::Mode::PostIndex)); 616 __ strh(R3, Address(R4, -24, Address::Mode::NegOffset)); 617 __ strh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 618 __ strh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 619 620 size_t cs = __ CodeSize(); 621 std::vector<uint8_t> managed_code(cs); 622 MemoryRegion code(&managed_code[0], managed_code.size()); 623 __ FinalizeInstructions(code); 624 dump(managed_code, "NegativeLoadStore"); 625 delete assembler; 626 } 627 628 TEST(Thumb2AssemblerTest, SimpleLoadStoreDual) { 629 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 630 631 __ strd(R2, Address(R0, 24, Address::Mode::Offset)); 632 __ ldrd(R2, Address(R0, 24, Address::Mode::Offset)); 633 634 size_t cs = __ CodeSize(); 635 std::vector<uint8_t> managed_code(cs); 636 MemoryRegion code(&managed_code[0], managed_code.size()); 637 __ FinalizeInstructions(code); 638 dump(managed_code, "SimpleLoadStoreDual"); 639 delete assembler; 640 } 641 642 TEST(Thumb2AssemblerTest, ComplexLoadStoreDual) { 643 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 644 645 __ strd(R2, Address(R0, 24, Address::Mode::Offset)); 646 __ strd(R2, Address(R0, 24, Address::Mode::PreIndex)); 647 __ strd(R2, Address(R0, 24, Address::Mode::PostIndex)); 648 __ strd(R2, Address(R0, 24, Address::Mode::NegOffset)); 649 __ strd(R2, Address(R0, 24, Address::Mode::NegPreIndex)); 650 __ strd(R2, Address(R0, 24, Address::Mode::NegPostIndex)); 651 652 __ ldrd(R2, Address(R0, 24, Address::Mode::Offset)); 653 __ ldrd(R2, Address(R0, 24, Address::Mode::PreIndex)); 654 __ ldrd(R2, Address(R0, 24, Address::Mode::PostIndex)); 655 __ ldrd(R2, Address(R0, 24, Address::Mode::NegOffset)); 656 __ ldrd(R2, Address(R0, 24, Address::Mode::NegPreIndex)); 657 __ ldrd(R2, Address(R0, 24, Address::Mode::NegPostIndex)); 658 659 size_t cs = __ CodeSize(); 660 std::vector<uint8_t> managed_code(cs); 661 MemoryRegion code(&managed_code[0], managed_code.size()); 662 __ FinalizeInstructions(code); 663 dump(managed_code, "ComplexLoadStoreDual"); 664 delete assembler; 665 } 666 667 TEST(Thumb2AssemblerTest, NegativeLoadStoreDual) { 668 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 669 670 __ strd(R2, Address(R0, -24, Address::Mode::Offset)); 671 __ strd(R2, Address(R0, -24, Address::Mode::PreIndex)); 672 __ strd(R2, Address(R0, -24, Address::Mode::PostIndex)); 673 __ strd(R2, Address(R0, -24, Address::Mode::NegOffset)); 674 __ strd(R2, Address(R0, -24, Address::Mode::NegPreIndex)); 675 __ strd(R2, Address(R0, -24, Address::Mode::NegPostIndex)); 676 677 __ ldrd(R2, Address(R0, -24, Address::Mode::Offset)); 678 __ ldrd(R2, Address(R0, -24, Address::Mode::PreIndex)); 679 __ ldrd(R2, Address(R0, -24, Address::Mode::PostIndex)); 680 __ ldrd(R2, Address(R0, -24, Address::Mode::NegOffset)); 681 __ ldrd(R2, Address(R0, -24, Address::Mode::NegPreIndex)); 682 __ ldrd(R2, Address(R0, -24, Address::Mode::NegPostIndex)); 683 684 size_t cs = __ CodeSize(); 685 std::vector<uint8_t> managed_code(cs); 686 MemoryRegion code(&managed_code[0], managed_code.size()); 687 __ FinalizeInstructions(code); 688 dump(managed_code, "NegativeLoadStoreDual"); 689 delete assembler; 690 } 691 692 TEST(Thumb2AssemblerTest, SimpleBranch) { 693 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 694 695 Label l1; 696 __ mov(R0, ShifterOperand(2)); 697 __ Bind(&l1); 698 __ mov(R1, ShifterOperand(1)); 699 __ b(&l1); 700 Label l2; 701 __ b(&l2); 702 __ mov(R1, ShifterOperand(2)); 703 __ Bind(&l2); 704 __ mov(R0, ShifterOperand(3)); 705 706 Label l3; 707 __ mov(R0, ShifterOperand(2)); 708 __ Bind(&l3); 709 __ mov(R1, ShifterOperand(1)); 710 __ b(&l3, EQ); 711 712 Label l4; 713 __ b(&l4, EQ); 714 __ mov(R1, ShifterOperand(2)); 715 __ Bind(&l4); 716 __ mov(R0, ShifterOperand(3)); 717 718 // 2 linked labels. 719 Label l5; 720 __ b(&l5); 721 __ mov(R1, ShifterOperand(4)); 722 __ b(&l5); 723 __ mov(R1, ShifterOperand(5)); 724 __ Bind(&l5); 725 __ mov(R0, ShifterOperand(6)); 726 727 size_t cs = __ CodeSize(); 728 std::vector<uint8_t> managed_code(cs); 729 MemoryRegion code(&managed_code[0], managed_code.size()); 730 __ FinalizeInstructions(code); 731 dump(managed_code, "SimpleBranch"); 732 delete assembler; 733 } 734 735 TEST(Thumb2AssemblerTest, LongBranch) { 736 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 737 assembler->Force32Bit(); 738 // 32 bit branches. 739 Label l1; 740 __ mov(R0, ShifterOperand(2)); 741 __ Bind(&l1); 742 __ mov(R1, ShifterOperand(1)); 743 __ b(&l1); 744 745 Label l2; 746 __ b(&l2); 747 __ mov(R1, ShifterOperand(2)); 748 __ Bind(&l2); 749 __ mov(R0, ShifterOperand(3)); 750 751 Label l3; 752 __ mov(R0, ShifterOperand(2)); 753 __ Bind(&l3); 754 __ mov(R1, ShifterOperand(1)); 755 __ b(&l3, EQ); 756 757 Label l4; 758 __ b(&l4, EQ); 759 __ mov(R1, ShifterOperand(2)); 760 __ Bind(&l4); 761 __ mov(R0, ShifterOperand(3)); 762 763 // 2 linked labels. 764 Label l5; 765 __ b(&l5); 766 __ mov(R1, ShifterOperand(4)); 767 __ b(&l5); 768 __ mov(R1, ShifterOperand(5)); 769 __ Bind(&l5); 770 __ mov(R0, ShifterOperand(6)); 771 772 size_t cs = __ CodeSize(); 773 std::vector<uint8_t> managed_code(cs); 774 MemoryRegion code(&managed_code[0], managed_code.size()); 775 __ FinalizeInstructions(code); 776 dump(managed_code, "LongBranch"); 777 delete assembler; 778 } 779 780 TEST(Thumb2AssemblerTest, LoadMultiple) { 781 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 782 783 // 16 bit. 784 __ ldm(DB_W, R4, (1 << R0 | 1 << R3)); 785 786 // 32 bit. 787 __ ldm(DB_W, R4, (1 << LR | 1 << R11)); 788 __ ldm(DB, R4, (1 << LR | 1 << R11)); 789 790 // Single reg is converted to ldr 791 __ ldm(DB_W, R4, (1 << R5)); 792 793 size_t cs = __ CodeSize(); 794 std::vector<uint8_t> managed_code(cs); 795 MemoryRegion code(&managed_code[0], managed_code.size()); 796 __ FinalizeInstructions(code); 797 dump(managed_code, "LoadMultiple"); 798 delete assembler; 799 } 800 801 TEST(Thumb2AssemblerTest, StoreMultiple) { 802 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 803 804 // 16 bit. 805 __ stm(IA_W, R4, (1 << R0 | 1 << R3)); 806 807 // 32 bit. 808 __ stm(IA_W, R4, (1 << LR | 1 << R11)); 809 __ stm(IA, R4, (1 << LR | 1 << R11)); 810 811 // Single reg is converted to str 812 __ stm(IA_W, R4, (1 << R5)); 813 __ stm(IA, R4, (1 << R5)); 814 815 size_t cs = __ CodeSize(); 816 std::vector<uint8_t> managed_code(cs); 817 MemoryRegion code(&managed_code[0], managed_code.size()); 818 __ FinalizeInstructions(code); 819 dump(managed_code, "StoreMultiple"); 820 delete assembler; 821 } 822 823 TEST(Thumb2AssemblerTest, MovWMovT) { 824 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 825 826 __ movw(R4, 0); // 16 bit. 827 __ movw(R4, 0x34); // 16 bit. 828 __ movw(R9, 0x34); // 32 bit due to high register. 829 __ movw(R3, 0x1234); // 32 bit due to large value. 830 __ movw(R9, 0xffff); // 32 bit due to large value and high register. 831 832 // Always 32 bit. 833 __ movt(R0, 0); 834 __ movt(R0, 0x1234); 835 __ movt(R1, 0xffff); 836 837 size_t cs = __ CodeSize(); 838 std::vector<uint8_t> managed_code(cs); 839 MemoryRegion code(&managed_code[0], managed_code.size()); 840 __ FinalizeInstructions(code); 841 dump(managed_code, "MovWMovT"); 842 delete assembler; 843 } 844 845 TEST(Thumb2AssemblerTest, SpecialAddSub) { 846 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 847 848 __ add(R2, SP, ShifterOperand(0x50)); // 16 bit. 849 __ add(SP, SP, ShifterOperand(0x50)); // 16 bit. 850 __ add(R8, SP, ShifterOperand(0x50)); // 32 bit. 851 852 __ add(R2, SP, ShifterOperand(0xf00)); // 32 bit due to imm size. 853 __ add(SP, SP, ShifterOperand(0xf00)); // 32 bit due to imm size. 854 855 __ sub(SP, SP, ShifterOperand(0x50)); // 16 bit 856 __ sub(R0, SP, ShifterOperand(0x50)); // 32 bit 857 __ sub(R8, SP, ShifterOperand(0x50)); // 32 bit. 858 859 __ sub(SP, SP, ShifterOperand(0xf00)); // 32 bit due to imm size 860 861 size_t cs = __ CodeSize(); 862 std::vector<uint8_t> managed_code(cs); 863 MemoryRegion code(&managed_code[0], managed_code.size()); 864 __ FinalizeInstructions(code); 865 dump(managed_code, "SpecialAddSub"); 866 delete assembler; 867 } 868 869 TEST(Thumb2AssemblerTest, StoreToOffset) { 870 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 871 872 __ StoreToOffset(kStoreWord, R2, R4, 12); // Simple 873 __ StoreToOffset(kStoreWord, R2, R4, 0x2000); // Offset too big. 874 __ StoreToOffset(kStoreWord, R0, R12, 12); 875 __ StoreToOffset(kStoreHalfword, R0, R12, 12); 876 __ StoreToOffset(kStoreByte, R2, R12, 12); 877 878 size_t cs = __ CodeSize(); 879 std::vector<uint8_t> managed_code(cs); 880 MemoryRegion code(&managed_code[0], managed_code.size()); 881 __ FinalizeInstructions(code); 882 dump(managed_code, "StoreToOffset"); 883 delete assembler; 884 } 885 886 887 TEST(Thumb2AssemblerTest, IfThen) { 888 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 889 890 __ it(EQ); 891 __ mov(R1, ShifterOperand(1), EQ); 892 893 __ it(EQ, kItThen); 894 __ mov(R1, ShifterOperand(1), EQ); 895 __ mov(R2, ShifterOperand(2), EQ); 896 897 __ it(EQ, kItElse); 898 __ mov(R1, ShifterOperand(1), EQ); 899 __ mov(R2, ShifterOperand(2), NE); 900 901 __ it(EQ, kItThen, kItElse); 902 __ mov(R1, ShifterOperand(1), EQ); 903 __ mov(R2, ShifterOperand(2), EQ); 904 __ mov(R3, ShifterOperand(3), NE); 905 906 __ it(EQ, kItElse, kItElse); 907 __ mov(R1, ShifterOperand(1), EQ); 908 __ mov(R2, ShifterOperand(2), NE); 909 __ mov(R3, ShifterOperand(3), NE); 910 911 __ it(EQ, kItThen, kItThen, kItElse); 912 __ mov(R1, ShifterOperand(1), EQ); 913 __ mov(R2, ShifterOperand(2), EQ); 914 __ mov(R3, ShifterOperand(3), EQ); 915 __ mov(R4, ShifterOperand(4), NE); 916 917 size_t cs = __ CodeSize(); 918 std::vector<uint8_t> managed_code(cs); 919 MemoryRegion code(&managed_code[0], managed_code.size()); 920 __ FinalizeInstructions(code); 921 dump(managed_code, "IfThen"); 922 delete assembler; 923 } 924 925 TEST(Thumb2AssemblerTest, CbzCbnz) { 926 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 927 928 Label l1; 929 __ cbz(R2, &l1); 930 __ mov(R1, ShifterOperand(3)); 931 __ mov(R2, ShifterOperand(3)); 932 __ Bind(&l1); 933 __ mov(R2, ShifterOperand(4)); 934 935 Label l2; 936 __ cbnz(R2, &l2); 937 __ mov(R8, ShifterOperand(3)); 938 __ mov(R2, ShifterOperand(3)); 939 __ Bind(&l2); 940 __ mov(R2, ShifterOperand(4)); 941 942 size_t cs = __ CodeSize(); 943 std::vector<uint8_t> managed_code(cs); 944 MemoryRegion code(&managed_code[0], managed_code.size()); 945 __ FinalizeInstructions(code); 946 dump(managed_code, "CbzCbnz"); 947 delete assembler; 948 } 949 950 TEST(Thumb2AssemblerTest, Multiply) { 951 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 952 953 __ mul(R0, R1, R0); 954 __ mul(R0, R1, R2); 955 __ mul(R8, R9, R8); 956 __ mul(R8, R9, R10); 957 958 __ mla(R0, R1, R2, R3); 959 __ mla(R8, R9, R8, R9); 960 961 __ mls(R0, R1, R2, R3); 962 __ mls(R8, R9, R8, R9); 963 964 __ umull(R0, R1, R2, R3); 965 __ umull(R8, R9, R10, R11); 966 967 size_t cs = __ CodeSize(); 968 std::vector<uint8_t> managed_code(cs); 969 MemoryRegion code(&managed_code[0], managed_code.size()); 970 __ FinalizeInstructions(code); 971 dump(managed_code, "Multiply"); 972 delete assembler; 973 } 974 975 TEST(Thumb2AssemblerTest, Divide) { 976 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 977 978 __ sdiv(R0, R1, R2); 979 __ sdiv(R8, R9, R10); 980 981 __ udiv(R0, R1, R2); 982 __ udiv(R8, R9, R10); 983 984 size_t cs = __ CodeSize(); 985 std::vector<uint8_t> managed_code(cs); 986 MemoryRegion code(&managed_code[0], managed_code.size()); 987 __ FinalizeInstructions(code); 988 dump(managed_code, "Divide"); 989 delete assembler; 990 } 991 992 TEST(Thumb2AssemblerTest, VMov) { 993 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 994 995 __ vmovs(S1, 1.0); 996 __ vmovd(D1, 1.0); 997 998 __ vmovs(S1, S2); 999 __ vmovd(D1, D2); 1000 1001 size_t cs = __ CodeSize(); 1002 std::vector<uint8_t> managed_code(cs); 1003 MemoryRegion code(&managed_code[0], managed_code.size()); 1004 __ FinalizeInstructions(code); 1005 dump(managed_code, "VMov"); 1006 delete assembler; 1007 } 1008 1009 1010 TEST(Thumb2AssemblerTest, BasicFloatingPoint) { 1011 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1012 1013 __ vadds(S0, S1, S2); 1014 __ vsubs(S0, S1, S2); 1015 __ vmuls(S0, S1, S2); 1016 __ vmlas(S0, S1, S2); 1017 __ vmlss(S0, S1, S2); 1018 __ vdivs(S0, S1, S2); 1019 __ vabss(S0, S1); 1020 __ vnegs(S0, S1); 1021 __ vsqrts(S0, S1); 1022 1023 __ vaddd(D0, D1, D2); 1024 __ vsubd(D0, D1, D2); 1025 __ vmuld(D0, D1, D2); 1026 __ vmlad(D0, D1, D2); 1027 __ vmlsd(D0, D1, D2); 1028 __ vdivd(D0, D1, D2); 1029 __ vabsd(D0, D1); 1030 __ vnegd(D0, D1); 1031 __ vsqrtd(D0, D1); 1032 1033 size_t cs = __ CodeSize(); 1034 std::vector<uint8_t> managed_code(cs); 1035 MemoryRegion code(&managed_code[0], managed_code.size()); 1036 __ FinalizeInstructions(code); 1037 dump(managed_code, "BasicFloatingPoint"); 1038 delete assembler; 1039 } 1040 1041 TEST(Thumb2AssemblerTest, FloatingPointConversions) { 1042 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1043 1044 __ vcvtsd(S2, D2); 1045 __ vcvtds(D2, S2); 1046 1047 __ vcvtis(S1, S2); 1048 __ vcvtsi(S1, S2); 1049 1050 __ vcvtid(S1, D2); 1051 __ vcvtdi(D1, S2); 1052 1053 __ vcvtus(S1, S2); 1054 __ vcvtsu(S1, S2); 1055 1056 __ vcvtud(S1, D2); 1057 __ vcvtdu(D1, S2); 1058 1059 size_t cs = __ CodeSize(); 1060 std::vector<uint8_t> managed_code(cs); 1061 MemoryRegion code(&managed_code[0], managed_code.size()); 1062 __ FinalizeInstructions(code); 1063 dump(managed_code, "FloatingPointConversions"); 1064 delete assembler; 1065 } 1066 1067 TEST(Thumb2AssemblerTest, FloatingPointComparisons) { 1068 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1069 1070 __ vcmps(S0, S1); 1071 __ vcmpd(D0, D1); 1072 1073 __ vcmpsz(S2); 1074 __ vcmpdz(D2); 1075 1076 size_t cs = __ CodeSize(); 1077 std::vector<uint8_t> managed_code(cs); 1078 MemoryRegion code(&managed_code[0], managed_code.size()); 1079 __ FinalizeInstructions(code); 1080 dump(managed_code, "FloatingPointComparisons"); 1081 delete assembler; 1082 } 1083 1084 TEST(Thumb2AssemblerTest, Calls) { 1085 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1086 1087 __ blx(LR); 1088 __ bx(LR); 1089 1090 size_t cs = __ CodeSize(); 1091 std::vector<uint8_t> managed_code(cs); 1092 MemoryRegion code(&managed_code[0], managed_code.size()); 1093 __ FinalizeInstructions(code); 1094 dump(managed_code, "Calls"); 1095 delete assembler; 1096 } 1097 1098 TEST(Thumb2AssemblerTest, Breakpoint) { 1099 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1100 1101 __ bkpt(0); 1102 1103 size_t cs = __ CodeSize(); 1104 std::vector<uint8_t> managed_code(cs); 1105 MemoryRegion code(&managed_code[0], managed_code.size()); 1106 __ FinalizeInstructions(code); 1107 dump(managed_code, "Breakpoint"); 1108 delete assembler; 1109 } 1110 1111 TEST(Thumb2AssemblerTest, StrR1) { 1112 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1113 1114 __ str(R1, Address(SP, 68)); 1115 __ str(R1, Address(SP, 1068)); 1116 1117 size_t cs = __ CodeSize(); 1118 std::vector<uint8_t> managed_code(cs); 1119 MemoryRegion code(&managed_code[0], managed_code.size()); 1120 __ FinalizeInstructions(code); 1121 dump(managed_code, "StrR1"); 1122 delete assembler; 1123 } 1124 1125 TEST(Thumb2AssemblerTest, VPushPop) { 1126 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1127 1128 __ vpushs(S2, 4); 1129 __ vpushd(D2, 4); 1130 1131 __ vpops(S2, 4); 1132 __ vpopd(D2, 4); 1133 1134 size_t cs = __ CodeSize(); 1135 std::vector<uint8_t> managed_code(cs); 1136 MemoryRegion code(&managed_code[0], managed_code.size()); 1137 __ FinalizeInstructions(code); 1138 dump(managed_code, "VPushPop"); 1139 delete assembler; 1140 } 1141 1142 TEST(Thumb2AssemblerTest, Max16BitBranch) { 1143 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1144 1145 Label l1; 1146 __ b(&l1); 1147 for (int i = 0 ; i < (1 << 11) ; i += 2) { 1148 __ mov(R3, ShifterOperand(i & 0xff)); 1149 } 1150 __ Bind(&l1); 1151 __ mov(R1, ShifterOperand(R2)); 1152 1153 size_t cs = __ CodeSize(); 1154 std::vector<uint8_t> managed_code(cs); 1155 MemoryRegion code(&managed_code[0], managed_code.size()); 1156 __ FinalizeInstructions(code); 1157 dump(managed_code, "Max16BitBranch"); 1158 delete assembler; 1159 } 1160 1161 TEST(Thumb2AssemblerTest, Branch32) { 1162 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1163 1164 Label l1; 1165 __ b(&l1); 1166 for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { 1167 __ mov(R3, ShifterOperand(i & 0xff)); 1168 } 1169 __ Bind(&l1); 1170 __ mov(R1, ShifterOperand(R2)); 1171 1172 size_t cs = __ CodeSize(); 1173 std::vector<uint8_t> managed_code(cs); 1174 MemoryRegion code(&managed_code[0], managed_code.size()); 1175 __ FinalizeInstructions(code); 1176 dump(managed_code, "Branch32"); 1177 delete assembler; 1178 } 1179 1180 TEST(Thumb2AssemblerTest, CompareAndBranchMax) { 1181 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1182 1183 Label l1; 1184 __ cbz(R4, &l1); 1185 for (int i = 0 ; i < (1 << 7) ; i += 2) { 1186 __ mov(R3, ShifterOperand(i & 0xff)); 1187 } 1188 __ Bind(&l1); 1189 __ mov(R1, ShifterOperand(R2)); 1190 1191 size_t cs = __ CodeSize(); 1192 std::vector<uint8_t> managed_code(cs); 1193 MemoryRegion code(&managed_code[0], managed_code.size()); 1194 __ FinalizeInstructions(code); 1195 dump(managed_code, "CompareAndBranchMax"); 1196 delete assembler; 1197 } 1198 1199 TEST(Thumb2AssemblerTest, CompareAndBranchRelocation16) { 1200 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1201 1202 Label l1; 1203 __ cbz(R4, &l1); 1204 for (int i = 0 ; i < (1 << 7) + 2 ; i += 2) { 1205 __ mov(R3, ShifterOperand(i & 0xff)); 1206 } 1207 __ Bind(&l1); 1208 __ mov(R1, ShifterOperand(R2)); 1209 1210 size_t cs = __ CodeSize(); 1211 std::vector<uint8_t> managed_code(cs); 1212 MemoryRegion code(&managed_code[0], managed_code.size()); 1213 __ FinalizeInstructions(code); 1214 dump(managed_code, "CompareAndBranchRelocation16"); 1215 delete assembler; 1216 } 1217 1218 TEST(Thumb2AssemblerTest, CompareAndBranchRelocation32) { 1219 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1220 1221 Label l1; 1222 __ cbz(R4, &l1); 1223 for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { 1224 __ mov(R3, ShifterOperand(i & 0xff)); 1225 } 1226 __ Bind(&l1); 1227 __ mov(R1, ShifterOperand(R2)); 1228 1229 size_t cs = __ CodeSize(); 1230 std::vector<uint8_t> managed_code(cs); 1231 MemoryRegion code(&managed_code[0], managed_code.size()); 1232 __ FinalizeInstructions(code); 1233 dump(managed_code, "CompareAndBranchRelocation32"); 1234 delete assembler; 1235 } 1236 1237 TEST(Thumb2AssemblerTest, MixedBranch32) { 1238 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1239 1240 Label l1; 1241 Label l2; 1242 __ b(&l1); // Forwards. 1243 __ Bind(&l2); 1244 1245 // Space to force relocation. 1246 for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { 1247 __ mov(R3, ShifterOperand(i & 0xff)); 1248 } 1249 __ b(&l2); // Backwards. 1250 __ Bind(&l1); 1251 __ mov(R1, ShifterOperand(R2)); 1252 1253 size_t cs = __ CodeSize(); 1254 std::vector<uint8_t> managed_code(cs); 1255 MemoryRegion code(&managed_code[0], managed_code.size()); 1256 __ FinalizeInstructions(code); 1257 dump(managed_code, "MixedBranch32"); 1258 delete assembler; 1259 } 1260 1261 TEST(Thumb2AssemblerTest, Shifts) { 1262 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1263 1264 // 16 bit 1265 __ Lsl(R0, R1, 5); 1266 __ Lsr(R0, R1, 5); 1267 __ Asr(R0, R1, 5); 1268 1269 __ Lsl(R0, R0, R1); 1270 __ Lsr(R0, R0, R1); 1271 __ Asr(R0, R0, R1); 1272 1273 // 32 bit due to high registers. 1274 __ Lsl(R8, R1, 5); 1275 __ Lsr(R0, R8, 5); 1276 __ Asr(R8, R1, 5); 1277 __ Ror(R0, R8, 5); 1278 1279 // 32 bit due to different Rd and Rn. 1280 __ Lsl(R0, R1, R2); 1281 __ Lsr(R0, R1, R2); 1282 __ Asr(R0, R1, R2); 1283 __ Ror(R0, R1, R2); 1284 1285 // 32 bit due to use of high registers. 1286 __ Lsl(R8, R1, R2); 1287 __ Lsr(R0, R8, R2); 1288 __ Asr(R0, R1, R8); 1289 1290 // S bit (all 32 bit) 1291 1292 // 32 bit due to high registers. 1293 __ Lsl(R8, R1, 5, true); 1294 __ Lsr(R0, R8, 5, true); 1295 __ Asr(R8, R1, 5, true); 1296 __ Ror(R0, R8, 5, true); 1297 1298 // 32 bit due to different Rd and Rn. 1299 __ Lsl(R0, R1, R2, true); 1300 __ Lsr(R0, R1, R2, true); 1301 __ Asr(R0, R1, R2, true); 1302 __ Ror(R0, R1, R2, true); 1303 1304 // 32 bit due to use of high registers. 1305 __ Lsl(R8, R1, R2, true); 1306 __ Lsr(R0, R8, R2, true); 1307 __ Asr(R0, R1, R8, true); 1308 1309 size_t cs = __ CodeSize(); 1310 std::vector<uint8_t> managed_code(cs); 1311 MemoryRegion code(&managed_code[0], managed_code.size()); 1312 __ FinalizeInstructions(code); 1313 dump(managed_code, "Shifts"); 1314 delete assembler; 1315 } 1316 1317 TEST(Thumb2AssemblerTest, LoadStoreRegOffset) { 1318 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1319 1320 // 16 bit. 1321 __ ldr(R0, Address(R1, R2)); 1322 __ str(R0, Address(R1, R2)); 1323 1324 // 32 bit due to shift. 1325 __ ldr(R0, Address(R1, R2, LSL, 1)); 1326 __ str(R0, Address(R1, R2, LSL, 1)); 1327 1328 __ ldr(R0, Address(R1, R2, LSL, 3)); 1329 __ str(R0, Address(R1, R2, LSL, 3)); 1330 1331 // 32 bit due to high register use. 1332 __ ldr(R8, Address(R1, R2)); 1333 __ str(R8, Address(R1, R2)); 1334 1335 __ ldr(R1, Address(R8, R2)); 1336 __ str(R2, Address(R8, R2)); 1337 1338 __ ldr(R0, Address(R1, R8)); 1339 __ str(R0, Address(R1, R8)); 1340 1341 size_t cs = __ CodeSize(); 1342 std::vector<uint8_t> managed_code(cs); 1343 MemoryRegion code(&managed_code[0], managed_code.size()); 1344 __ FinalizeInstructions(code); 1345 dump(managed_code, "LoadStoreRegOffset"); 1346 delete assembler; 1347 } 1348 1349 TEST(Thumb2AssemblerTest, LoadStoreLiteral) { 1350 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1351 1352 __ ldr(R0, Address(4)); 1353 __ str(R0, Address(4)); 1354 1355 __ ldr(R0, Address(-8)); 1356 __ str(R0, Address(-8)); 1357 1358 // Limits. 1359 __ ldr(R0, Address(0x3ff)); // 10 bits (16 bit). 1360 __ ldr(R0, Address(0x7ff)); // 11 bits (32 bit). 1361 __ str(R0, Address(0x3ff)); // 32 bit (no 16 bit str(literal)). 1362 __ str(R0, Address(0x7ff)); // 11 bits (32 bit). 1363 1364 size_t cs = __ CodeSize(); 1365 std::vector<uint8_t> managed_code(cs); 1366 MemoryRegion code(&managed_code[0], managed_code.size()); 1367 __ FinalizeInstructions(code); 1368 dump(managed_code, "LoadStoreLiteral"); 1369 delete assembler; 1370 } 1371 1372 TEST(Thumb2AssemblerTest, LoadStoreLimits) { 1373 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1374 1375 __ ldr(R0, Address(R4, 124)); // 16 bit. 1376 __ ldr(R0, Address(R4, 128)); // 32 bit. 1377 1378 __ ldrb(R0, Address(R4, 31)); // 16 bit. 1379 __ ldrb(R0, Address(R4, 32)); // 32 bit. 1380 1381 __ ldrh(R0, Address(R4, 62)); // 16 bit. 1382 __ ldrh(R0, Address(R4, 64)); // 32 bit. 1383 1384 __ ldrsb(R0, Address(R4, 31)); // 32 bit. 1385 __ ldrsb(R0, Address(R4, 32)); // 32 bit. 1386 1387 __ ldrsh(R0, Address(R4, 62)); // 32 bit. 1388 __ ldrsh(R0, Address(R4, 64)); // 32 bit. 1389 1390 __ str(R0, Address(R4, 124)); // 16 bit. 1391 __ str(R0, Address(R4, 128)); // 32 bit. 1392 1393 __ strb(R0, Address(R4, 31)); // 16 bit. 1394 __ strb(R0, Address(R4, 32)); // 32 bit. 1395 1396 __ strh(R0, Address(R4, 62)); // 16 bit. 1397 __ strh(R0, Address(R4, 64)); // 32 bit. 1398 1399 size_t cs = __ CodeSize(); 1400 std::vector<uint8_t> managed_code(cs); 1401 MemoryRegion code(&managed_code[0], managed_code.size()); 1402 __ FinalizeInstructions(code); 1403 dump(managed_code, "LoadStoreLimits"); 1404 delete assembler; 1405 } 1406 1407 #undef __ 1408 } // namespace arm 1409 } // namespace art 1410