assembler_thumb_test.cc revision 8baf0d9263f914aee8ca91df92660342ace9e671
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 27namespace art { 28namespace 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. 43static constexpr bool kPrintResults = false; 44#endif 45 46static const char* TOOL_PREFIX = "arm-linux-androideabi-"; 47 48void SetAndroidData() { 49 const char* data = getenv("ANDROID_DATA"); 50 if (data == nullptr) { 51 setenv("ANDROID_DATA", "/tmp", 1); 52 } 53} 54 55int 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 68std::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 136void 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[256]; 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 232TEST(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 249TEST(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 264TEST(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 279TEST(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 size_t cs = __ CodeSize(); 316 std::vector<uint8_t> managed_code(cs); 317 MemoryRegion code(&managed_code[0], managed_code.size()); 318 __ FinalizeInstructions(code); 319 dump(managed_code, "DataProcessingRegister"); 320 delete assembler; 321} 322 323TEST(Thumb2AssemblerTest, DataProcessingImmediate) { 324 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 325 326 __ mov(R0, ShifterOperand(0x55)); 327 __ mvn(R0, ShifterOperand(0x55)); 328 __ add(R0, R1, ShifterOperand(0x55)); 329 __ sub(R0, R1, ShifterOperand(0x55)); 330 __ and_(R0, R1, ShifterOperand(0x55)); 331 __ orr(R0, R1, ShifterOperand(0x55)); 332 __ eor(R0, R1, ShifterOperand(0x55)); 333 __ bic(R0, R1, ShifterOperand(0x55)); 334 __ adc(R0, R1, ShifterOperand(0x55)); 335 __ sbc(R0, R1, ShifterOperand(0x55)); 336 __ rsb(R0, R1, ShifterOperand(0x55)); 337 338 __ tst(R0, ShifterOperand(0x55)); 339 __ teq(R0, ShifterOperand(0x55)); 340 __ cmp(R0, ShifterOperand(0x55)); 341 __ cmn(R0, ShifterOperand(0x55)); 342 343 __ add(R0, R1, ShifterOperand(5)); 344 __ sub(R0, R1, ShifterOperand(5)); 345 346 __ movs(R0, ShifterOperand(0x55)); 347 __ mvns(R0, ShifterOperand(0x55)); 348 349 size_t cs = __ CodeSize(); 350 std::vector<uint8_t> managed_code(cs); 351 MemoryRegion code(&managed_code[0], managed_code.size()); 352 __ FinalizeInstructions(code); 353 dump(managed_code, "DataProcessingImmediate"); 354 delete assembler; 355} 356 357TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediate) { 358 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 359 360 __ mov(R0, ShifterOperand(0x550055)); 361 __ mvn(R0, ShifterOperand(0x550055)); 362 __ add(R0, R1, ShifterOperand(0x550055)); 363 __ sub(R0, R1, ShifterOperand(0x550055)); 364 __ and_(R0, R1, ShifterOperand(0x550055)); 365 __ orr(R0, R1, ShifterOperand(0x550055)); 366 __ eor(R0, R1, ShifterOperand(0x550055)); 367 __ bic(R0, R1, ShifterOperand(0x550055)); 368 __ adc(R0, R1, ShifterOperand(0x550055)); 369 __ sbc(R0, R1, ShifterOperand(0x550055)); 370 __ rsb(R0, R1, ShifterOperand(0x550055)); 371 372 __ tst(R0, ShifterOperand(0x550055)); 373 __ teq(R0, ShifterOperand(0x550055)); 374 __ cmp(R0, ShifterOperand(0x550055)); 375 __ cmn(R0, ShifterOperand(0x550055)); 376 377 size_t cs = __ CodeSize(); 378 std::vector<uint8_t> managed_code(cs); 379 MemoryRegion code(&managed_code[0], managed_code.size()); 380 __ FinalizeInstructions(code); 381 dump(managed_code, "DataProcessingModifiedImmediate"); 382 delete assembler; 383} 384 385 386TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediates) { 387 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 388 389 __ mov(R0, ShifterOperand(0x550055)); 390 __ mov(R0, ShifterOperand(0x55005500)); 391 __ mov(R0, ShifterOperand(0x55555555)); 392 __ mov(R0, ShifterOperand(0xd5000000)); // rotated to first position 393 __ mov(R0, ShifterOperand(0x6a000000)); // rotated to second position 394 __ mov(R0, ShifterOperand(0x350)); // rotated to 2nd last position 395 __ mov(R0, ShifterOperand(0x1a8)); // rotated to last position 396 397 size_t cs = __ CodeSize(); 398 std::vector<uint8_t> managed_code(cs); 399 MemoryRegion code(&managed_code[0], managed_code.size()); 400 __ FinalizeInstructions(code); 401 dump(managed_code, "DataProcessingModifiedImmediates"); 402 delete assembler; 403} 404 405TEST(Thumb2AssemblerTest, DataProcessingShiftedRegister) { 406 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 407 408 __ mov(R3, ShifterOperand(R4, LSL, 4)); 409 __ mov(R3, ShifterOperand(R4, LSR, 5)); 410 __ mov(R3, ShifterOperand(R4, ASR, 6)); 411 __ mov(R3, ShifterOperand(R4, ROR, 7)); 412 __ mov(R3, ShifterOperand(R4, ROR)); 413 414 // 32 bit variants. 415 __ mov(R8, ShifterOperand(R4, LSL, 4)); 416 __ mov(R8, ShifterOperand(R4, LSR, 5)); 417 __ mov(R8, ShifterOperand(R4, ASR, 6)); 418 __ mov(R8, ShifterOperand(R4, ROR, 7)); 419 __ mov(R8, ShifterOperand(R4, RRX)); 420 421 size_t cs = __ CodeSize(); 422 std::vector<uint8_t> managed_code(cs); 423 MemoryRegion code(&managed_code[0], managed_code.size()); 424 __ FinalizeInstructions(code); 425 dump(managed_code, "DataProcessingShiftedRegister"); 426 delete assembler; 427} 428 429 430TEST(Thumb2AssemblerTest, BasicLoad) { 431 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 432 433 __ ldr(R3, Address(R4, 24)); 434 __ ldrb(R3, Address(R4, 24)); 435 __ ldrh(R3, Address(R4, 24)); 436 __ ldrsb(R3, Address(R4, 24)); 437 __ ldrsh(R3, Address(R4, 24)); 438 439 __ ldr(R3, Address(SP, 24)); 440 441 // 32 bit variants 442 __ ldr(R8, Address(R4, 24)); 443 __ ldrb(R8, Address(R4, 24)); 444 __ ldrh(R8, Address(R4, 24)); 445 __ ldrsb(R8, Address(R4, 24)); 446 __ ldrsh(R8, Address(R4, 24)); 447 448 size_t cs = __ CodeSize(); 449 std::vector<uint8_t> managed_code(cs); 450 MemoryRegion code(&managed_code[0], managed_code.size()); 451 __ FinalizeInstructions(code); 452 dump(managed_code, "BasicLoad"); 453 delete assembler; 454} 455 456 457TEST(Thumb2AssemblerTest, BasicStore) { 458 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 459 460 __ str(R3, Address(R4, 24)); 461 __ strb(R3, Address(R4, 24)); 462 __ strh(R3, Address(R4, 24)); 463 464 __ str(R3, Address(SP, 24)); 465 466 // 32 bit variants. 467 __ str(R8, Address(R4, 24)); 468 __ strb(R8, Address(R4, 24)); 469 __ strh(R8, Address(R4, 24)); 470 471 size_t cs = __ CodeSize(); 472 std::vector<uint8_t> managed_code(cs); 473 MemoryRegion code(&managed_code[0], managed_code.size()); 474 __ FinalizeInstructions(code); 475 dump(managed_code, "BasicStore"); 476 delete assembler; 477} 478 479TEST(Thumb2AssemblerTest, ComplexLoad) { 480 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 481 482 __ ldr(R3, Address(R4, 24, Address::Mode::Offset)); 483 __ ldr(R3, Address(R4, 24, Address::Mode::PreIndex)); 484 __ ldr(R3, Address(R4, 24, Address::Mode::PostIndex)); 485 __ ldr(R3, Address(R4, 24, Address::Mode::NegOffset)); 486 __ ldr(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 487 __ ldr(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 488 489 __ ldrb(R3, Address(R4, 24, Address::Mode::Offset)); 490 __ ldrb(R3, Address(R4, 24, Address::Mode::PreIndex)); 491 __ ldrb(R3, Address(R4, 24, Address::Mode::PostIndex)); 492 __ ldrb(R3, Address(R4, 24, Address::Mode::NegOffset)); 493 __ ldrb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 494 __ ldrb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 495 496 __ ldrh(R3, Address(R4, 24, Address::Mode::Offset)); 497 __ ldrh(R3, Address(R4, 24, Address::Mode::PreIndex)); 498 __ ldrh(R3, Address(R4, 24, Address::Mode::PostIndex)); 499 __ ldrh(R3, Address(R4, 24, Address::Mode::NegOffset)); 500 __ ldrh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 501 __ ldrh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 502 503 __ ldrsb(R3, Address(R4, 24, Address::Mode::Offset)); 504 __ ldrsb(R3, Address(R4, 24, Address::Mode::PreIndex)); 505 __ ldrsb(R3, Address(R4, 24, Address::Mode::PostIndex)); 506 __ ldrsb(R3, Address(R4, 24, Address::Mode::NegOffset)); 507 __ ldrsb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 508 __ ldrsb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 509 510 __ ldrsh(R3, Address(R4, 24, Address::Mode::Offset)); 511 __ ldrsh(R3, Address(R4, 24, Address::Mode::PreIndex)); 512 __ ldrsh(R3, Address(R4, 24, Address::Mode::PostIndex)); 513 __ ldrsh(R3, Address(R4, 24, Address::Mode::NegOffset)); 514 __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 515 __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 516 517 size_t cs = __ CodeSize(); 518 std::vector<uint8_t> managed_code(cs); 519 MemoryRegion code(&managed_code[0], managed_code.size()); 520 __ FinalizeInstructions(code); 521 dump(managed_code, "ComplexLoad"); 522 delete assembler; 523} 524 525 526TEST(Thumb2AssemblerTest, ComplexStore) { 527 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 528 529 __ str(R3, Address(R4, 24, Address::Mode::Offset)); 530 __ str(R3, Address(R4, 24, Address::Mode::PreIndex)); 531 __ str(R3, Address(R4, 24, Address::Mode::PostIndex)); 532 __ str(R3, Address(R4, 24, Address::Mode::NegOffset)); 533 __ str(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 534 __ str(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 535 536 __ strb(R3, Address(R4, 24, Address::Mode::Offset)); 537 __ strb(R3, Address(R4, 24, Address::Mode::PreIndex)); 538 __ strb(R3, Address(R4, 24, Address::Mode::PostIndex)); 539 __ strb(R3, Address(R4, 24, Address::Mode::NegOffset)); 540 __ strb(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 541 __ strb(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 542 543 __ strh(R3, Address(R4, 24, Address::Mode::Offset)); 544 __ strh(R3, Address(R4, 24, Address::Mode::PreIndex)); 545 __ strh(R3, Address(R4, 24, Address::Mode::PostIndex)); 546 __ strh(R3, Address(R4, 24, Address::Mode::NegOffset)); 547 __ strh(R3, Address(R4, 24, Address::Mode::NegPreIndex)); 548 __ strh(R3, Address(R4, 24, Address::Mode::NegPostIndex)); 549 550 size_t cs = __ CodeSize(); 551 std::vector<uint8_t> managed_code(cs); 552 MemoryRegion code(&managed_code[0], managed_code.size()); 553 __ FinalizeInstructions(code); 554 dump(managed_code, "ComplexStore"); 555 delete assembler; 556} 557 558TEST(Thumb2AssemblerTest, NegativeLoadStore) { 559 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 560 561 __ ldr(R3, Address(R4, -24, Address::Mode::Offset)); 562 __ ldr(R3, Address(R4, -24, Address::Mode::PreIndex)); 563 __ ldr(R3, Address(R4, -24, Address::Mode::PostIndex)); 564 __ ldr(R3, Address(R4, -24, Address::Mode::NegOffset)); 565 __ ldr(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 566 __ ldr(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 567 568 __ ldrb(R3, Address(R4, -24, Address::Mode::Offset)); 569 __ ldrb(R3, Address(R4, -24, Address::Mode::PreIndex)); 570 __ ldrb(R3, Address(R4, -24, Address::Mode::PostIndex)); 571 __ ldrb(R3, Address(R4, -24, Address::Mode::NegOffset)); 572 __ ldrb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 573 __ ldrb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 574 575 __ ldrh(R3, Address(R4, -24, Address::Mode::Offset)); 576 __ ldrh(R3, Address(R4, -24, Address::Mode::PreIndex)); 577 __ ldrh(R3, Address(R4, -24, Address::Mode::PostIndex)); 578 __ ldrh(R3, Address(R4, -24, Address::Mode::NegOffset)); 579 __ ldrh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 580 __ ldrh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 581 582 __ ldrsb(R3, Address(R4, -24, Address::Mode::Offset)); 583 __ ldrsb(R3, Address(R4, -24, Address::Mode::PreIndex)); 584 __ ldrsb(R3, Address(R4, -24, Address::Mode::PostIndex)); 585 __ ldrsb(R3, Address(R4, -24, Address::Mode::NegOffset)); 586 __ ldrsb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 587 __ ldrsb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 588 589 __ ldrsh(R3, Address(R4, -24, Address::Mode::Offset)); 590 __ ldrsh(R3, Address(R4, -24, Address::Mode::PreIndex)); 591 __ ldrsh(R3, Address(R4, -24, Address::Mode::PostIndex)); 592 __ ldrsh(R3, Address(R4, -24, Address::Mode::NegOffset)); 593 __ ldrsh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 594 __ ldrsh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 595 596 __ str(R3, Address(R4, -24, Address::Mode::Offset)); 597 __ str(R3, Address(R4, -24, Address::Mode::PreIndex)); 598 __ str(R3, Address(R4, -24, Address::Mode::PostIndex)); 599 __ str(R3, Address(R4, -24, Address::Mode::NegOffset)); 600 __ str(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 601 __ str(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 602 603 __ strb(R3, Address(R4, -24, Address::Mode::Offset)); 604 __ strb(R3, Address(R4, -24, Address::Mode::PreIndex)); 605 __ strb(R3, Address(R4, -24, Address::Mode::PostIndex)); 606 __ strb(R3, Address(R4, -24, Address::Mode::NegOffset)); 607 __ strb(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 608 __ strb(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 609 610 __ strh(R3, Address(R4, -24, Address::Mode::Offset)); 611 __ strh(R3, Address(R4, -24, Address::Mode::PreIndex)); 612 __ strh(R3, Address(R4, -24, Address::Mode::PostIndex)); 613 __ strh(R3, Address(R4, -24, Address::Mode::NegOffset)); 614 __ strh(R3, Address(R4, -24, Address::Mode::NegPreIndex)); 615 __ strh(R3, Address(R4, -24, Address::Mode::NegPostIndex)); 616 617 size_t cs = __ CodeSize(); 618 std::vector<uint8_t> managed_code(cs); 619 MemoryRegion code(&managed_code[0], managed_code.size()); 620 __ FinalizeInstructions(code); 621 dump(managed_code, "NegativeLoadStore"); 622 delete assembler; 623} 624 625TEST(Thumb2AssemblerTest, SimpleLoadStoreDual) { 626 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 627 628 __ strd(R2, Address(R0, 24, Address::Mode::Offset)); 629 __ ldrd(R2, Address(R0, 24, Address::Mode::Offset)); 630 631 size_t cs = __ CodeSize(); 632 std::vector<uint8_t> managed_code(cs); 633 MemoryRegion code(&managed_code[0], managed_code.size()); 634 __ FinalizeInstructions(code); 635 dump(managed_code, "SimpleLoadStoreDual"); 636 delete assembler; 637} 638 639TEST(Thumb2AssemblerTest, ComplexLoadStoreDual) { 640 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 641 642 __ strd(R2, Address(R0, 24, Address::Mode::Offset)); 643 __ strd(R2, Address(R0, 24, Address::Mode::PreIndex)); 644 __ strd(R2, Address(R0, 24, Address::Mode::PostIndex)); 645 __ strd(R2, Address(R0, 24, Address::Mode::NegOffset)); 646 __ strd(R2, Address(R0, 24, Address::Mode::NegPreIndex)); 647 __ strd(R2, Address(R0, 24, Address::Mode::NegPostIndex)); 648 649 __ ldrd(R2, Address(R0, 24, Address::Mode::Offset)); 650 __ ldrd(R2, Address(R0, 24, Address::Mode::PreIndex)); 651 __ ldrd(R2, Address(R0, 24, Address::Mode::PostIndex)); 652 __ ldrd(R2, Address(R0, 24, Address::Mode::NegOffset)); 653 __ ldrd(R2, Address(R0, 24, Address::Mode::NegPreIndex)); 654 __ ldrd(R2, Address(R0, 24, Address::Mode::NegPostIndex)); 655 656 size_t cs = __ CodeSize(); 657 std::vector<uint8_t> managed_code(cs); 658 MemoryRegion code(&managed_code[0], managed_code.size()); 659 __ FinalizeInstructions(code); 660 dump(managed_code, "ComplexLoadStoreDual"); 661 delete assembler; 662} 663 664TEST(Thumb2AssemblerTest, NegativeLoadStoreDual) { 665 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 666 667 __ strd(R2, Address(R0, -24, Address::Mode::Offset)); 668 __ strd(R2, Address(R0, -24, Address::Mode::PreIndex)); 669 __ strd(R2, Address(R0, -24, Address::Mode::PostIndex)); 670 __ strd(R2, Address(R0, -24, Address::Mode::NegOffset)); 671 __ strd(R2, Address(R0, -24, Address::Mode::NegPreIndex)); 672 __ strd(R2, Address(R0, -24, Address::Mode::NegPostIndex)); 673 674 __ ldrd(R2, Address(R0, -24, Address::Mode::Offset)); 675 __ ldrd(R2, Address(R0, -24, Address::Mode::PreIndex)); 676 __ ldrd(R2, Address(R0, -24, Address::Mode::PostIndex)); 677 __ ldrd(R2, Address(R0, -24, Address::Mode::NegOffset)); 678 __ ldrd(R2, Address(R0, -24, Address::Mode::NegPreIndex)); 679 __ ldrd(R2, Address(R0, -24, Address::Mode::NegPostIndex)); 680 681 size_t cs = __ CodeSize(); 682 std::vector<uint8_t> managed_code(cs); 683 MemoryRegion code(&managed_code[0], managed_code.size()); 684 __ FinalizeInstructions(code); 685 dump(managed_code, "NegativeLoadStoreDual"); 686 delete assembler; 687} 688 689TEST(Thumb2AssemblerTest, SimpleBranch) { 690 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 691 692 Label l1; 693 __ mov(R0, ShifterOperand(2)); 694 __ Bind(&l1); 695 __ mov(R1, ShifterOperand(1)); 696 __ b(&l1); 697 Label l2; 698 __ b(&l2); 699 __ mov(R1, ShifterOperand(2)); 700 __ Bind(&l2); 701 __ mov(R0, ShifterOperand(3)); 702 703 Label l3; 704 __ mov(R0, ShifterOperand(2)); 705 __ Bind(&l3); 706 __ mov(R1, ShifterOperand(1)); 707 __ b(&l3, EQ); 708 709 Label l4; 710 __ b(&l4, EQ); 711 __ mov(R1, ShifterOperand(2)); 712 __ Bind(&l4); 713 __ mov(R0, ShifterOperand(3)); 714 715 // 2 linked labels. 716 Label l5; 717 __ b(&l5); 718 __ mov(R1, ShifterOperand(4)); 719 __ b(&l5); 720 __ mov(R1, ShifterOperand(5)); 721 __ Bind(&l5); 722 __ mov(R0, ShifterOperand(6)); 723 724 size_t cs = __ CodeSize(); 725 std::vector<uint8_t> managed_code(cs); 726 MemoryRegion code(&managed_code[0], managed_code.size()); 727 __ FinalizeInstructions(code); 728 dump(managed_code, "SimpleBranch"); 729 delete assembler; 730} 731 732TEST(Thumb2AssemblerTest, LongBranch) { 733 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 734 assembler->Force32Bit(); 735 // 32 bit branches. 736 Label l1; 737 __ mov(R0, ShifterOperand(2)); 738 __ Bind(&l1); 739 __ mov(R1, ShifterOperand(1)); 740 __ b(&l1); 741 742 Label l2; 743 __ b(&l2); 744 __ mov(R1, ShifterOperand(2)); 745 __ Bind(&l2); 746 __ mov(R0, ShifterOperand(3)); 747 748 Label l3; 749 __ mov(R0, ShifterOperand(2)); 750 __ Bind(&l3); 751 __ mov(R1, ShifterOperand(1)); 752 __ b(&l3, EQ); 753 754 Label l4; 755 __ b(&l4, EQ); 756 __ mov(R1, ShifterOperand(2)); 757 __ Bind(&l4); 758 __ mov(R0, ShifterOperand(3)); 759 760 // 2 linked labels. 761 Label l5; 762 __ b(&l5); 763 __ mov(R1, ShifterOperand(4)); 764 __ b(&l5); 765 __ mov(R1, ShifterOperand(5)); 766 __ Bind(&l5); 767 __ mov(R0, ShifterOperand(6)); 768 769 size_t cs = __ CodeSize(); 770 std::vector<uint8_t> managed_code(cs); 771 MemoryRegion code(&managed_code[0], managed_code.size()); 772 __ FinalizeInstructions(code); 773 dump(managed_code, "LongBranch"); 774 delete assembler; 775} 776 777TEST(Thumb2AssemblerTest, LoadMultiple) { 778 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 779 780 // 16 bit. 781 __ ldm(DB_W, R4, (1 << R0 | 1 << R3)); 782 783 // 32 bit. 784 __ ldm(DB_W, R4, (1 << LR | 1 << R11)); 785 __ ldm(DB, R4, (1 << LR | 1 << R11)); 786 787 // Single reg is converted to ldr 788 __ ldm(DB_W, R4, (1 << R5)); 789 790 size_t cs = __ CodeSize(); 791 std::vector<uint8_t> managed_code(cs); 792 MemoryRegion code(&managed_code[0], managed_code.size()); 793 __ FinalizeInstructions(code); 794 dump(managed_code, "LoadMultiple"); 795 delete assembler; 796} 797 798TEST(Thumb2AssemblerTest, StoreMultiple) { 799 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 800 801 // 16 bit. 802 __ stm(IA_W, R4, (1 << R0 | 1 << R3)); 803 804 // 32 bit. 805 __ stm(IA_W, R4, (1 << LR | 1 << R11)); 806 __ stm(IA, R4, (1 << LR | 1 << R11)); 807 808 // Single reg is converted to str 809 __ stm(IA_W, R4, (1 << R5)); 810 __ stm(IA, R4, (1 << R5)); 811 812 size_t cs = __ CodeSize(); 813 std::vector<uint8_t> managed_code(cs); 814 MemoryRegion code(&managed_code[0], managed_code.size()); 815 __ FinalizeInstructions(code); 816 dump(managed_code, "StoreMultiple"); 817 delete assembler; 818} 819 820TEST(Thumb2AssemblerTest, MovWMovT) { 821 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 822 823 __ movw(R4, 0); // 16 bit. 824 __ movw(R4, 0x34); // 16 bit. 825 __ movw(R9, 0x34); // 32 bit due to high register. 826 __ movw(R3, 0x1234); // 32 bit due to large value. 827 __ movw(R9, 0xffff); // 32 bit due to large value and high register. 828 829 // Always 32 bit. 830 __ movt(R0, 0); 831 __ movt(R0, 0x1234); 832 __ movt(R1, 0xffff); 833 834 size_t cs = __ CodeSize(); 835 std::vector<uint8_t> managed_code(cs); 836 MemoryRegion code(&managed_code[0], managed_code.size()); 837 __ FinalizeInstructions(code); 838 dump(managed_code, "MovWMovT"); 839 delete assembler; 840} 841 842TEST(Thumb2AssemblerTest, SpecialAddSub) { 843 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 844 845 __ add(R2, SP, ShifterOperand(0x50)); // 16 bit. 846 __ add(SP, SP, ShifterOperand(0x50)); // 16 bit. 847 __ add(R8, SP, ShifterOperand(0x50)); // 32 bit. 848 849 __ add(R2, SP, ShifterOperand(0xf00)); // 32 bit due to imm size. 850 __ add(SP, SP, ShifterOperand(0xf00)); // 32 bit due to imm size. 851 852 __ sub(SP, SP, ShifterOperand(0x50)); // 16 bit 853 __ sub(R0, SP, ShifterOperand(0x50)); // 32 bit 854 __ sub(R8, SP, ShifterOperand(0x50)); // 32 bit. 855 856 __ sub(SP, SP, ShifterOperand(0xf00)); // 32 bit due to imm size 857 858 size_t cs = __ CodeSize(); 859 std::vector<uint8_t> managed_code(cs); 860 MemoryRegion code(&managed_code[0], managed_code.size()); 861 __ FinalizeInstructions(code); 862 dump(managed_code, "SpecialAddSub"); 863 delete assembler; 864} 865 866TEST(Thumb2AssemblerTest, StoreToOffset) { 867 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 868 869 __ StoreToOffset(kStoreWord, R2, R4, 12); // Simple 870 __ StoreToOffset(kStoreWord, R2, R4, 0x2000); // Offset too big. 871 872 size_t cs = __ CodeSize(); 873 std::vector<uint8_t> managed_code(cs); 874 MemoryRegion code(&managed_code[0], managed_code.size()); 875 __ FinalizeInstructions(code); 876 dump(managed_code, "StoreToOffset"); 877 delete assembler; 878} 879 880 881TEST(Thumb2AssemblerTest, IfThen) { 882 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 883 884 __ it(EQ); 885 __ mov(R1, ShifterOperand(1), EQ); 886 887 __ it(EQ, kItThen); 888 __ mov(R1, ShifterOperand(1), EQ); 889 __ mov(R2, ShifterOperand(2), EQ); 890 891 __ it(EQ, kItElse); 892 __ mov(R1, ShifterOperand(1), EQ); 893 __ mov(R2, ShifterOperand(2), NE); 894 895 __ it(EQ, kItThen, kItElse); 896 __ mov(R1, ShifterOperand(1), EQ); 897 __ mov(R2, ShifterOperand(2), EQ); 898 __ mov(R3, ShifterOperand(3), NE); 899 900 __ it(EQ, kItElse, kItElse); 901 __ mov(R1, ShifterOperand(1), EQ); 902 __ mov(R2, ShifterOperand(2), NE); 903 __ mov(R3, ShifterOperand(3), NE); 904 905 __ it(EQ, kItThen, kItThen, kItElse); 906 __ mov(R1, ShifterOperand(1), EQ); 907 __ mov(R2, ShifterOperand(2), EQ); 908 __ mov(R3, ShifterOperand(3), EQ); 909 __ mov(R4, ShifterOperand(4), NE); 910 911 size_t cs = __ CodeSize(); 912 std::vector<uint8_t> managed_code(cs); 913 MemoryRegion code(&managed_code[0], managed_code.size()); 914 __ FinalizeInstructions(code); 915 dump(managed_code, "IfThen"); 916 delete assembler; 917} 918 919TEST(Thumb2AssemblerTest, CbzCbnz) { 920 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 921 922 Label l1; 923 __ cbz(R2, &l1); 924 __ mov(R1, ShifterOperand(3)); 925 __ mov(R2, ShifterOperand(3)); 926 __ Bind(&l1); 927 __ mov(R2, ShifterOperand(4)); 928 929 Label l2; 930 __ cbnz(R2, &l2); 931 __ mov(R8, ShifterOperand(3)); 932 __ mov(R2, ShifterOperand(3)); 933 __ Bind(&l2); 934 __ mov(R2, ShifterOperand(4)); 935 936 size_t cs = __ CodeSize(); 937 std::vector<uint8_t> managed_code(cs); 938 MemoryRegion code(&managed_code[0], managed_code.size()); 939 __ FinalizeInstructions(code); 940 dump(managed_code, "CbzCbnz"); 941 delete assembler; 942} 943 944TEST(Thumb2AssemblerTest, Multiply) { 945 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 946 947 __ mul(R0, R1, R0); 948 __ mul(R0, R1, R2); 949 __ mul(R8, R9, R8); 950 __ mul(R8, R9, R10); 951 952 __ mla(R0, R1, R2, R3); 953 __ mla(R8, R9, R8, R9); 954 955 __ mls(R0, R1, R2, R3); 956 __ mls(R8, R9, R8, R9); 957 958 __ umull(R0, R1, R2, R3); 959 __ umull(R8, R9, R10, R11); 960 961 size_t cs = __ CodeSize(); 962 std::vector<uint8_t> managed_code(cs); 963 MemoryRegion code(&managed_code[0], managed_code.size()); 964 __ FinalizeInstructions(code); 965 dump(managed_code, "Multiply"); 966 delete assembler; 967} 968 969TEST(Thumb2AssemblerTest, Divide) { 970 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 971 972 __ sdiv(R0, R1, R2); 973 __ sdiv(R8, R9, R10); 974 975 __ udiv(R0, R1, R2); 976 __ udiv(R8, R9, R10); 977 978 size_t cs = __ CodeSize(); 979 std::vector<uint8_t> managed_code(cs); 980 MemoryRegion code(&managed_code[0], managed_code.size()); 981 __ FinalizeInstructions(code); 982 dump(managed_code, "Divide"); 983 delete assembler; 984} 985 986TEST(Thumb2AssemblerTest, VMov) { 987 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 988 989 __ vmovs(S1, 1.0); 990 __ vmovd(D1, 1.0); 991 992 __ vmovs(S1, S2); 993 __ vmovd(D1, D2); 994 995 size_t cs = __ CodeSize(); 996 std::vector<uint8_t> managed_code(cs); 997 MemoryRegion code(&managed_code[0], managed_code.size()); 998 __ FinalizeInstructions(code); 999 dump(managed_code, "VMov"); 1000 delete assembler; 1001} 1002 1003 1004TEST(Thumb2AssemblerTest, BasicFloatingPoint) { 1005 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1006 1007 __ vadds(S0, S1, S2); 1008 __ vsubs(S0, S1, S2); 1009 __ vmuls(S0, S1, S2); 1010 __ vmlas(S0, S1, S2); 1011 __ vmlss(S0, S1, S2); 1012 __ vdivs(S0, S1, S2); 1013 __ vabss(S0, S1); 1014 __ vnegs(S0, S1); 1015 __ vsqrts(S0, S1); 1016 1017 __ vaddd(D0, D1, D2); 1018 __ vsubd(D0, D1, D2); 1019 __ vmuld(D0, D1, D2); 1020 __ vmlad(D0, D1, D2); 1021 __ vmlsd(D0, D1, D2); 1022 __ vdivd(D0, D1, D2); 1023 __ vabsd(D0, D1); 1024 __ vnegd(D0, D1); 1025 __ vsqrtd(D0, D1); 1026 1027 size_t cs = __ CodeSize(); 1028 std::vector<uint8_t> managed_code(cs); 1029 MemoryRegion code(&managed_code[0], managed_code.size()); 1030 __ FinalizeInstructions(code); 1031 dump(managed_code, "BasicFloatingPoint"); 1032 delete assembler; 1033} 1034 1035TEST(Thumb2AssemblerTest, FloatingPointConversions) { 1036 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1037 1038 __ vcvtsd(S2, D2); 1039 __ vcvtds(D2, S2); 1040 1041 __ vcvtis(S1, S2); 1042 __ vcvtsi(S1, S2); 1043 1044 __ vcvtid(S1, D2); 1045 __ vcvtdi(D1, S2); 1046 1047 __ vcvtus(S1, S2); 1048 __ vcvtsu(S1, S2); 1049 1050 __ vcvtud(S1, D2); 1051 __ vcvtdu(D1, S2); 1052 1053 size_t cs = __ CodeSize(); 1054 std::vector<uint8_t> managed_code(cs); 1055 MemoryRegion code(&managed_code[0], managed_code.size()); 1056 __ FinalizeInstructions(code); 1057 dump(managed_code, "FloatingPointConversions"); 1058 delete assembler; 1059} 1060 1061TEST(Thumb2AssemblerTest, FloatingPointComparisons) { 1062 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1063 1064 __ vcmps(S0, S1); 1065 __ vcmpd(D0, D1); 1066 1067 __ vcmpsz(S2); 1068 __ vcmpdz(D2); 1069 1070 size_t cs = __ CodeSize(); 1071 std::vector<uint8_t> managed_code(cs); 1072 MemoryRegion code(&managed_code[0], managed_code.size()); 1073 __ FinalizeInstructions(code); 1074 dump(managed_code, "FloatingPointComparisons"); 1075 delete assembler; 1076} 1077 1078TEST(Thumb2AssemblerTest, Calls) { 1079 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1080 1081 __ blx(LR); 1082 __ bx(LR); 1083 1084 size_t cs = __ CodeSize(); 1085 std::vector<uint8_t> managed_code(cs); 1086 MemoryRegion code(&managed_code[0], managed_code.size()); 1087 __ FinalizeInstructions(code); 1088 dump(managed_code, "Calls"); 1089 delete assembler; 1090} 1091 1092TEST(Thumb2AssemblerTest, Breakpoint) { 1093 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1094 1095 __ bkpt(0); 1096 1097 size_t cs = __ CodeSize(); 1098 std::vector<uint8_t> managed_code(cs); 1099 MemoryRegion code(&managed_code[0], managed_code.size()); 1100 __ FinalizeInstructions(code); 1101 dump(managed_code, "Breakpoint"); 1102 delete assembler; 1103} 1104 1105TEST(Thumb2AssemblerTest, StrR1) { 1106 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1107 1108 __ str(R1, Address(SP, 68)); 1109 __ str(R1, Address(SP, 1068)); 1110 1111 size_t cs = __ CodeSize(); 1112 std::vector<uint8_t> managed_code(cs); 1113 MemoryRegion code(&managed_code[0], managed_code.size()); 1114 __ FinalizeInstructions(code); 1115 dump(managed_code, "StrR1"); 1116 delete assembler; 1117} 1118 1119TEST(Thumb2AssemblerTest, VPushPop) { 1120 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1121 1122 __ vpushs(S2, 4); 1123 __ vpushd(D2, 4); 1124 1125 __ vpops(S2, 4); 1126 __ vpopd(D2, 4); 1127 1128 size_t cs = __ CodeSize(); 1129 std::vector<uint8_t> managed_code(cs); 1130 MemoryRegion code(&managed_code[0], managed_code.size()); 1131 __ FinalizeInstructions(code); 1132 dump(managed_code, "VPushPop"); 1133 delete assembler; 1134} 1135 1136TEST(Thumb2AssemblerTest, Max16BitBranch) { 1137 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1138 1139 Label l1; 1140 __ b(&l1); 1141 for (int i = 0 ; i < (1 << 11) ; i += 2) { 1142 __ mov(R3, ShifterOperand(i & 0xff)); 1143 } 1144 __ Bind(&l1); 1145 __ mov(R1, ShifterOperand(R2)); 1146 1147 size_t cs = __ CodeSize(); 1148 std::vector<uint8_t> managed_code(cs); 1149 MemoryRegion code(&managed_code[0], managed_code.size()); 1150 __ FinalizeInstructions(code); 1151 dump(managed_code, "Max16BitBranch"); 1152 delete assembler; 1153} 1154 1155TEST(Thumb2AssemblerTest, Branch32) { 1156 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1157 1158 Label l1; 1159 __ b(&l1); 1160 for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { 1161 __ mov(R3, ShifterOperand(i & 0xff)); 1162 } 1163 __ Bind(&l1); 1164 __ mov(R1, ShifterOperand(R2)); 1165 1166 size_t cs = __ CodeSize(); 1167 std::vector<uint8_t> managed_code(cs); 1168 MemoryRegion code(&managed_code[0], managed_code.size()); 1169 __ FinalizeInstructions(code); 1170 dump(managed_code, "Branch32"); 1171 delete assembler; 1172} 1173 1174TEST(Thumb2AssemblerTest, CompareAndBranchMax) { 1175 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1176 1177 Label l1; 1178 __ cbz(R4, &l1); 1179 for (int i = 0 ; i < (1 << 7) ; i += 2) { 1180 __ mov(R3, ShifterOperand(i & 0xff)); 1181 } 1182 __ Bind(&l1); 1183 __ mov(R1, ShifterOperand(R2)); 1184 1185 size_t cs = __ CodeSize(); 1186 std::vector<uint8_t> managed_code(cs); 1187 MemoryRegion code(&managed_code[0], managed_code.size()); 1188 __ FinalizeInstructions(code); 1189 dump(managed_code, "CompareAndBranchMax"); 1190 delete assembler; 1191} 1192 1193TEST(Thumb2AssemblerTest, CompareAndBranchRelocation16) { 1194 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1195 1196 Label l1; 1197 __ cbz(R4, &l1); 1198 for (int i = 0 ; i < (1 << 7) + 2 ; i += 2) { 1199 __ mov(R3, ShifterOperand(i & 0xff)); 1200 } 1201 __ Bind(&l1); 1202 __ mov(R1, ShifterOperand(R2)); 1203 1204 size_t cs = __ CodeSize(); 1205 std::vector<uint8_t> managed_code(cs); 1206 MemoryRegion code(&managed_code[0], managed_code.size()); 1207 __ FinalizeInstructions(code); 1208 dump(managed_code, "CompareAndBranchRelocation16"); 1209 delete assembler; 1210} 1211 1212TEST(Thumb2AssemblerTest, CompareAndBranchRelocation32) { 1213 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1214 1215 Label l1; 1216 __ cbz(R4, &l1); 1217 for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { 1218 __ mov(R3, ShifterOperand(i & 0xff)); 1219 } 1220 __ Bind(&l1); 1221 __ mov(R1, ShifterOperand(R2)); 1222 1223 size_t cs = __ CodeSize(); 1224 std::vector<uint8_t> managed_code(cs); 1225 MemoryRegion code(&managed_code[0], managed_code.size()); 1226 __ FinalizeInstructions(code); 1227 dump(managed_code, "CompareAndBranchRelocation32"); 1228 delete assembler; 1229} 1230 1231TEST(Thumb2AssemblerTest, MixedBranch32) { 1232 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1233 1234 Label l1; 1235 Label l2; 1236 __ b(&l1); // Forwards. 1237 __ Bind(&l2); 1238 1239 // Space to force relocation. 1240 for (int i = 0 ; i < (1 << 11) + 2 ; i += 2) { 1241 __ mov(R3, ShifterOperand(i & 0xff)); 1242 } 1243 __ b(&l2); // Backwards. 1244 __ Bind(&l1); 1245 __ mov(R1, ShifterOperand(R2)); 1246 1247 size_t cs = __ CodeSize(); 1248 std::vector<uint8_t> managed_code(cs); 1249 MemoryRegion code(&managed_code[0], managed_code.size()); 1250 __ FinalizeInstructions(code); 1251 dump(managed_code, "MixedBranch32"); 1252 delete assembler; 1253} 1254 1255TEST(Thumb2AssemblerTest, Shifts) { 1256 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1257 1258 // 16 bit 1259 __ Lsl(R0, R1, 5); 1260 __ Lsr(R0, R1, 5); 1261 __ Asr(R0, R1, 5); 1262 1263 __ Lsl(R0, R0, R1); 1264 __ Lsr(R0, R0, R1); 1265 __ Asr(R0, R0, R1); 1266 1267 // 32 bit due to high registers. 1268 __ Lsl(R8, R1, 5); 1269 __ Lsr(R0, R8, 5); 1270 __ Asr(R8, R1, 5); 1271 __ Ror(R0, R8, 5); 1272 1273 // 32 bit due to different Rd and Rn. 1274 __ Lsl(R0, R1, R2); 1275 __ Lsr(R0, R1, R2); 1276 __ Asr(R0, R1, R2); 1277 __ Ror(R0, R1, R2); 1278 1279 // 32 bit due to use of high registers. 1280 __ Lsl(R8, R1, R2); 1281 __ Lsr(R0, R8, R2); 1282 __ Asr(R0, R1, R8); 1283 1284 // S bit (all 32 bit) 1285 1286 // 32 bit due to high registers. 1287 __ Lsl(R8, R1, 5, true); 1288 __ Lsr(R0, R8, 5, true); 1289 __ Asr(R8, R1, 5, true); 1290 __ Ror(R0, R8, 5, true); 1291 1292 // 32 bit due to different Rd and Rn. 1293 __ Lsl(R0, R1, R2, true); 1294 __ Lsr(R0, R1, R2, true); 1295 __ Asr(R0, R1, R2, true); 1296 __ Ror(R0, R1, R2, true); 1297 1298 // 32 bit due to use of high registers. 1299 __ Lsl(R8, R1, R2, true); 1300 __ Lsr(R0, R8, R2, true); 1301 __ Asr(R0, R1, R8, true); 1302 1303 size_t cs = __ CodeSize(); 1304 std::vector<uint8_t> managed_code(cs); 1305 MemoryRegion code(&managed_code[0], managed_code.size()); 1306 __ FinalizeInstructions(code); 1307 dump(managed_code, "Shifts"); 1308 delete assembler; 1309} 1310 1311TEST(Thumb2AssemblerTest, LoadStoreRegOffset) { 1312 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1313 1314 // 16 bit. 1315 __ ldr(R0, Address(R1, R2)); 1316 __ str(R0, Address(R1, R2)); 1317 1318 // 32 bit due to shift. 1319 __ ldr(R0, Address(R1, R2, LSL, 1)); 1320 __ str(R0, Address(R1, R2, LSL, 1)); 1321 1322 __ ldr(R0, Address(R1, R2, LSL, 3)); 1323 __ str(R0, Address(R1, R2, LSL, 3)); 1324 1325 // 32 bit due to high register use. 1326 __ ldr(R8, Address(R1, R2)); 1327 __ str(R8, Address(R1, R2)); 1328 1329 __ ldr(R1, Address(R8, R2)); 1330 __ str(R2, Address(R8, R2)); 1331 1332 __ ldr(R0, Address(R1, R8)); 1333 __ str(R0, Address(R1, R8)); 1334 1335 size_t cs = __ CodeSize(); 1336 std::vector<uint8_t> managed_code(cs); 1337 MemoryRegion code(&managed_code[0], managed_code.size()); 1338 __ FinalizeInstructions(code); 1339 dump(managed_code, "LoadStoreRegOffset"); 1340 delete assembler; 1341} 1342 1343TEST(Thumb2AssemblerTest, LoadStoreLiteral) { 1344 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1345 1346 __ ldr(R0, Address(4)); 1347 __ str(R0, Address(4)); 1348 1349 __ ldr(R0, Address(-8)); 1350 __ str(R0, Address(-8)); 1351 1352 // Limits. 1353 __ ldr(R0, Address(0x3ff)); // 10 bits (16 bit). 1354 __ ldr(R0, Address(0x7ff)); // 11 bits (32 bit). 1355 __ str(R0, Address(0x3ff)); // 32 bit (no 16 bit str(literal)). 1356 __ str(R0, Address(0x7ff)); // 11 bits (32 bit). 1357 1358 size_t cs = __ CodeSize(); 1359 std::vector<uint8_t> managed_code(cs); 1360 MemoryRegion code(&managed_code[0], managed_code.size()); 1361 __ FinalizeInstructions(code); 1362 dump(managed_code, "LoadStoreLiteral"); 1363 delete assembler; 1364} 1365 1366TEST(Thumb2AssemblerTest, LoadStoreLimits) { 1367 arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2)); 1368 1369 __ ldr(R0, Address(R4, 124)); // 16 bit. 1370 __ ldr(R0, Address(R4, 128)); // 32 bit. 1371 1372 __ ldrb(R0, Address(R4, 31)); // 16 bit. 1373 __ ldrb(R0, Address(R4, 32)); // 32 bit. 1374 1375 __ ldrh(R0, Address(R4, 62)); // 16 bit. 1376 __ ldrh(R0, Address(R4, 64)); // 32 bit. 1377 1378 __ ldrsb(R0, Address(R4, 31)); // 32 bit. 1379 __ ldrsb(R0, Address(R4, 32)); // 32 bit. 1380 1381 __ ldrsh(R0, Address(R4, 62)); // 32 bit. 1382 __ ldrsh(R0, Address(R4, 64)); // 32 bit. 1383 1384 __ str(R0, Address(R4, 124)); // 16 bit. 1385 __ str(R0, Address(R4, 128)); // 32 bit. 1386 1387 __ strb(R0, Address(R4, 31)); // 16 bit. 1388 __ strb(R0, Address(R4, 32)); // 32 bit. 1389 1390 __ strh(R0, Address(R4, 62)); // 16 bit. 1391 __ strh(R0, Address(R4, 64)); // 32 bit. 1392 1393 size_t cs = __ CodeSize(); 1394 std::vector<uint8_t> managed_code(cs); 1395 MemoryRegion code(&managed_code[0], managed_code.size()); 1396 __ FinalizeInstructions(code); 1397 dump(managed_code, "LoadStoreLimits"); 1398 delete assembler; 1399} 1400 1401#undef __ 1402} // namespace arm 1403} // namespace art 1404