assembler_thumb2_test.cc revision 9ee23f4273efed8d6378f6ad8e63c65e30a17139
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 "assembler_thumb2.h" 18 19#include "base/stl_util.h" 20#include "utils/assembler_test.h" 21 22namespace art { 23 24class AssemblerThumb2Test : public AssemblerTest<arm::Thumb2Assembler, 25 arm::Register, arm::SRegister, 26 uint32_t> { 27 protected: 28 std::string GetArchitectureString() OVERRIDE { 29 return "arm"; 30 } 31 32 std::string GetAssemblerParameters() OVERRIDE { 33 return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon -mthumb"; 34 } 35 36 const char* GetAssemblyHeader() OVERRIDE { 37 return kThumb2AssemblyHeader; 38 } 39 40 std::string GetDisassembleParameters() OVERRIDE { 41 return " -D -bbinary -marm --disassembler-options=force-thumb --no-show-raw-insn"; 42 } 43 44 void SetUpHelpers() OVERRIDE { 45 if (registers_.size() == 0) { 46 registers_.insert(end(registers_), 47 { // NOLINT(whitespace/braces) 48 new arm::Register(arm::R0), 49 new arm::Register(arm::R1), 50 new arm::Register(arm::R2), 51 new arm::Register(arm::R3), 52 new arm::Register(arm::R4), 53 new arm::Register(arm::R5), 54 new arm::Register(arm::R6), 55 new arm::Register(arm::R7), 56 new arm::Register(arm::R8), 57 new arm::Register(arm::R9), 58 new arm::Register(arm::R10), 59 new arm::Register(arm::R11), 60 new arm::Register(arm::R12), 61 new arm::Register(arm::R13), 62 new arm::Register(arm::R14), 63 new arm::Register(arm::R15) 64 }); 65 } 66 } 67 68 void TearDown() OVERRIDE { 69 AssemblerTest::TearDown(); 70 STLDeleteElements(®isters_); 71 } 72 73 std::vector<arm::Register*> GetRegisters() OVERRIDE { 74 return registers_; 75 } 76 77 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE { 78 return imm_value; 79 } 80 81 std::string RepeatInsn(size_t count, const std::string& insn) { 82 std::string result; 83 for (; count != 0u; --count) { 84 result += insn; 85 } 86 return result; 87 } 88 89 private: 90 std::vector<arm::Register*> registers_; 91 92 static constexpr const char* kThumb2AssemblyHeader = ".syntax unified\n.thumb\n"; 93}; 94 95TEST_F(AssemblerThumb2Test, Toolchain) { 96 EXPECT_TRUE(CheckTools()); 97} 98 99#define __ GetAssembler()-> 100 101TEST_F(AssemblerThumb2Test, Sbfx) { 102 __ sbfx(arm::R0, arm::R1, 0, 1); 103 __ sbfx(arm::R0, arm::R1, 0, 8); 104 __ sbfx(arm::R0, arm::R1, 0, 16); 105 __ sbfx(arm::R0, arm::R1, 0, 32); 106 107 __ sbfx(arm::R0, arm::R1, 8, 1); 108 __ sbfx(arm::R0, arm::R1, 8, 8); 109 __ sbfx(arm::R0, arm::R1, 8, 16); 110 __ sbfx(arm::R0, arm::R1, 8, 24); 111 112 __ sbfx(arm::R0, arm::R1, 16, 1); 113 __ sbfx(arm::R0, arm::R1, 16, 8); 114 __ sbfx(arm::R0, arm::R1, 16, 16); 115 116 __ sbfx(arm::R0, arm::R1, 31, 1); 117 118 const char* expected = 119 "sbfx r0, r1, #0, #1\n" 120 "sbfx r0, r1, #0, #8\n" 121 "sbfx r0, r1, #0, #16\n" 122 "sbfx r0, r1, #0, #32\n" 123 124 "sbfx r0, r1, #8, #1\n" 125 "sbfx r0, r1, #8, #8\n" 126 "sbfx r0, r1, #8, #16\n" 127 "sbfx r0, r1, #8, #24\n" 128 129 "sbfx r0, r1, #16, #1\n" 130 "sbfx r0, r1, #16, #8\n" 131 "sbfx r0, r1, #16, #16\n" 132 133 "sbfx r0, r1, #31, #1\n"; 134 DriverStr(expected, "sbfx"); 135} 136 137TEST_F(AssemblerThumb2Test, Ubfx) { 138 __ ubfx(arm::R0, arm::R1, 0, 1); 139 __ ubfx(arm::R0, arm::R1, 0, 8); 140 __ ubfx(arm::R0, arm::R1, 0, 16); 141 __ ubfx(arm::R0, arm::R1, 0, 32); 142 143 __ ubfx(arm::R0, arm::R1, 8, 1); 144 __ ubfx(arm::R0, arm::R1, 8, 8); 145 __ ubfx(arm::R0, arm::R1, 8, 16); 146 __ ubfx(arm::R0, arm::R1, 8, 24); 147 148 __ ubfx(arm::R0, arm::R1, 16, 1); 149 __ ubfx(arm::R0, arm::R1, 16, 8); 150 __ ubfx(arm::R0, arm::R1, 16, 16); 151 152 __ ubfx(arm::R0, arm::R1, 31, 1); 153 154 const char* expected = 155 "ubfx r0, r1, #0, #1\n" 156 "ubfx r0, r1, #0, #8\n" 157 "ubfx r0, r1, #0, #16\n" 158 "ubfx r0, r1, #0, #32\n" 159 160 "ubfx r0, r1, #8, #1\n" 161 "ubfx r0, r1, #8, #8\n" 162 "ubfx r0, r1, #8, #16\n" 163 "ubfx r0, r1, #8, #24\n" 164 165 "ubfx r0, r1, #16, #1\n" 166 "ubfx r0, r1, #16, #8\n" 167 "ubfx r0, r1, #16, #16\n" 168 169 "ubfx r0, r1, #31, #1\n"; 170 DriverStr(expected, "ubfx"); 171} 172 173TEST_F(AssemblerThumb2Test, Vmstat) { 174 __ vmstat(); 175 176 const char* expected = "vmrs APSR_nzcv, FPSCR\n"; 177 178 DriverStr(expected, "vmrs"); 179} 180 181TEST_F(AssemblerThumb2Test, ldrexd) { 182 __ ldrexd(arm::R0, arm::R1, arm::R0); 183 __ ldrexd(arm::R0, arm::R1, arm::R1); 184 __ ldrexd(arm::R0, arm::R1, arm::R2); 185 __ ldrexd(arm::R5, arm::R3, arm::R7); 186 187 const char* expected = 188 "ldrexd r0, r1, [r0]\n" 189 "ldrexd r0, r1, [r1]\n" 190 "ldrexd r0, r1, [r2]\n" 191 "ldrexd r5, r3, [r7]\n"; 192 DriverStr(expected, "ldrexd"); 193} 194 195TEST_F(AssemblerThumb2Test, strexd) { 196 __ strexd(arm::R9, arm::R0, arm::R1, arm::R0); 197 __ strexd(arm::R9, arm::R0, arm::R1, arm::R1); 198 __ strexd(arm::R9, arm::R0, arm::R1, arm::R2); 199 __ strexd(arm::R9, arm::R5, arm::R3, arm::R7); 200 201 const char* expected = 202 "strexd r9, r0, r1, [r0]\n" 203 "strexd r9, r0, r1, [r1]\n" 204 "strexd r9, r0, r1, [r2]\n" 205 "strexd r9, r5, r3, [r7]\n"; 206 DriverStr(expected, "strexd"); 207} 208 209TEST_F(AssemblerThumb2Test, LdrdStrd) { 210 __ ldrd(arm::R0, arm::Address(arm::R2, 8)); 211 __ ldrd(arm::R0, arm::Address(arm::R12)); 212 __ strd(arm::R0, arm::Address(arm::R2, 8)); 213 214 const char* expected = 215 "ldrd r0, r1, [r2, #8]\n" 216 "ldrd r0, r1, [r12]\n" 217 "strd r0, r1, [r2, #8]\n"; 218 DriverStr(expected, "ldrdstrd"); 219} 220 221TEST_F(AssemblerThumb2Test, eor) { 222 __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0)); 223 __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1)); 224 __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0)); 225 __ eor(arm::R8, arm::R1, arm::ShifterOperand(arm::R0)); 226 __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R8)); 227 228 const char* expected = 229 "eors r1, r0\n" 230 "eor r1, r0, r1\n" 231 "eor r1, r8, r0\n" 232 "eor r8, r1, r0\n" 233 "eor r1, r0, r8\n"; 234 DriverStr(expected, "abs"); 235} 236 237TEST_F(AssemblerThumb2Test, sub) { 238 __ subs(arm::R1, arm::R0, arm::ShifterOperand(42)); 239 __ sub(arm::R1, arm::R0, arm::ShifterOperand(42)); 240 __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); 241 __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); 242 243 const char* expected = 244 "subs r1, r0, #42\n" 245 "subw r1, r0, #42\n" 246 "subs r1, r0, r2, asr #31\n" 247 "sub r1, r0, r2, asr #31\n"; 248 DriverStr(expected, "sub"); 249} 250 251TEST_F(AssemblerThumb2Test, add) { 252 __ adds(arm::R1, arm::R0, arm::ShifterOperand(42)); 253 __ add(arm::R1, arm::R0, arm::ShifterOperand(42)); 254 __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); 255 __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); 256 257 const char* expected = 258 "adds r1, r0, #42\n" 259 "addw r1, r0, #42\n" 260 "adds r1, r0, r2, asr #31\n" 261 "add r1, r0, r2, asr #31\n"; 262 DriverStr(expected, "add"); 263} 264 265TEST_F(AssemblerThumb2Test, umull) { 266 __ umull(arm::R0, arm::R1, arm::R2, arm::R3); 267 268 const char* expected = 269 "umull r0, r1, r2, r3\n"; 270 DriverStr(expected, "umull"); 271} 272 273TEST_F(AssemblerThumb2Test, smull) { 274 __ smull(arm::R0, arm::R1, arm::R2, arm::R3); 275 276 const char* expected = 277 "smull r0, r1, r2, r3\n"; 278 DriverStr(expected, "smull"); 279} 280 281TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) { 282 arm::StoreOperandType type = arm::kStoreWord; 283 int32_t offset = 4092; 284 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset)); 285 286 __ StoreToOffset(type, arm::R0, arm::SP, offset); 287 __ StoreToOffset(type, arm::IP, arm::SP, offset); 288 __ StoreToOffset(type, arm::IP, arm::R5, offset); 289 290 const char* expected = 291 "str r0, [sp, #4092]\n" 292 "str ip, [sp, #4092]\n" 293 "str ip, [r5, #4092]\n"; 294 DriverStr(expected, "StoreWordToThumbOffset"); 295} 296 297TEST_F(AssemblerThumb2Test, StoreWordToNonThumbOffset) { 298 arm::StoreOperandType type = arm::kStoreWord; 299 int32_t offset = 4096; 300 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset)); 301 302 __ StoreToOffset(type, arm::R0, arm::SP, offset); 303 __ StoreToOffset(type, arm::IP, arm::SP, offset); 304 __ StoreToOffset(type, arm::IP, arm::R5, offset); 305 306 const char* expected = 307 "mov ip, #4096\n" // LoadImmediate(ip, 4096) 308 "add ip, ip, sp\n" 309 "str r0, [ip, #0]\n" 310 311 "str r5, [sp, #-4]!\n" // Push(r5) 312 "movw r5, #4100\n" // LoadImmediate(r5, 4096 + kRegisterSize) 313 "add r5, r5, sp\n" 314 "str ip, [r5, #0]\n" 315 "ldr r5, [sp], #4\n" // Pop(r5) 316 317 "str r6, [sp, #-4]!\n" // Push(r6) 318 "mov r6, #4096\n" // LoadImmediate(r6, 4096) 319 "add r6, r6, r5\n" 320 "str ip, [r6, #0]\n" 321 "ldr r6, [sp], #4\n"; // Pop(r6) 322 DriverStr(expected, "StoreWordToNonThumbOffset"); 323} 324 325TEST_F(AssemblerThumb2Test, StoreWordPairToThumbOffset) { 326 arm::StoreOperandType type = arm::kStoreWordPair; 327 int32_t offset = 1020; 328 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset)); 329 330 __ StoreToOffset(type, arm::R0, arm::SP, offset); 331 // We cannot use IP (i.e. R12) as first source register, as it would 332 // force us to use SP (i.e. R13) as second source register, which 333 // would have an "unpredictable" effect according to the ARMv7 334 // specification (the T1 encoding describes the result as 335 // UNPREDICTABLE when of the source registers is R13). 336 // 337 // So we use (R11, IP) (e.g. (R11, R12)) as source registers in the 338 // following instructions. 339 __ StoreToOffset(type, arm::R11, arm::SP, offset); 340 __ StoreToOffset(type, arm::R11, arm::R5, offset); 341 342 const char* expected = 343 "strd r0, r1, [sp, #1020]\n" 344 "strd r11, ip, [sp, #1020]\n" 345 "strd r11, ip, [r5, #1020]\n"; 346 DriverStr(expected, "StoreWordPairToThumbOffset"); 347} 348 349TEST_F(AssemblerThumb2Test, StoreWordPairToNonThumbOffset) { 350 arm::StoreOperandType type = arm::kStoreWordPair; 351 int32_t offset = 1024; 352 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset)); 353 354 __ StoreToOffset(type, arm::R0, arm::SP, offset); 355 // Same comment as in AssemblerThumb2Test.StoreWordPairToThumbOffset 356 // regarding the use of (R11, IP) (e.g. (R11, R12)) as source 357 // registers in the following instructions. 358 __ StoreToOffset(type, arm::R11, arm::SP, offset); 359 __ StoreToOffset(type, arm::R11, arm::R5, offset); 360 361 const char* expected = 362 "mov ip, #1024\n" // LoadImmediate(ip, 1024) 363 "add ip, ip, sp\n" 364 "strd r0, r1, [ip, #0]\n" 365 366 "str r5, [sp, #-4]!\n" // Push(r5) 367 "movw r5, #1028\n" // LoadImmediate(r5, 1024 + kRegisterSize) 368 "add r5, r5, sp\n" 369 "strd r11, ip, [r5, #0]\n" 370 "ldr r5, [sp], #4\n" // Pop(r5) 371 372 "str r6, [sp, #-4]!\n" // Push(r6) 373 "mov r6, #1024\n" // LoadImmediate(r6, 1024) 374 "add r6, r6, r5\n" 375 "strd r11, ip, [r6, #0]\n" 376 "ldr r6, [sp], #4\n"; // Pop(r6) 377 DriverStr(expected, "StoreWordPairToNonThumbOffset"); 378} 379 380TEST_F(AssemblerThumb2Test, TwoCbzMaxOffset) { 381 Label label0, label1, label2; 382 __ cbz(arm::R0, &label1); 383 constexpr size_t kLdrR0R0Count1 = 63; 384 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 385 __ ldr(arm::R0, arm::Address(arm::R0)); 386 } 387 __ Bind(&label0); 388 __ cbz(arm::R0, &label2); 389 __ Bind(&label1); 390 constexpr size_t kLdrR0R0Count2 = 64; 391 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 392 __ ldr(arm::R0, arm::Address(arm::R0)); 393 } 394 __ Bind(&label2); 395 396 std::string expected = 397 "cbz r0, 1f\n" + // cbz r0, label1 398 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 399 "0:\n" 400 "cbz r0, 2f\n" // cbz r0, label2 401 "1:\n" + 402 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 403 "2:\n"; 404 DriverStr(expected, "TwoCbzMaxOffset"); 405 406 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u, 407 __ GetAdjustedPosition(label0.Position())); 408 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 0u, 409 __ GetAdjustedPosition(label1.Position())); 410 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 0u, 411 __ GetAdjustedPosition(label2.Position())); 412} 413 414TEST_F(AssemblerThumb2Test, TwoCbzBeyondMaxOffset) { 415 Label label0, label1, label2; 416 __ cbz(arm::R0, &label1); 417 constexpr size_t kLdrR0R0Count1 = 63; 418 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 419 __ ldr(arm::R0, arm::Address(arm::R0)); 420 } 421 __ Bind(&label0); 422 __ cbz(arm::R0, &label2); 423 __ Bind(&label1); 424 constexpr size_t kLdrR0R0Count2 = 65; 425 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 426 __ ldr(arm::R0, arm::Address(arm::R0)); 427 } 428 __ Bind(&label2); 429 430 std::string expected = 431 "cmp r0, #0\n" // cbz r0, label1 432 "beq.n 1f\n" + 433 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 434 "0:\n" 435 "cmp r0, #0\n" // cbz r0, label2 436 "beq.n 2f\n" 437 "1:\n" + 438 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 439 "2:\n"; 440 DriverStr(expected, "TwoCbzBeyondMaxOffset"); 441 442 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u, 443 __ GetAdjustedPosition(label0.Position())); 444 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 4u, 445 __ GetAdjustedPosition(label1.Position())); 446 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 4u, 447 __ GetAdjustedPosition(label2.Position())); 448} 449 450TEST_F(AssemblerThumb2Test, TwoCbzSecondAtMaxB16Offset) { 451 Label label0, label1, label2; 452 __ cbz(arm::R0, &label1); 453 constexpr size_t kLdrR0R0Count1 = 62; 454 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 455 __ ldr(arm::R0, arm::Address(arm::R0)); 456 } 457 __ Bind(&label0); 458 __ cbz(arm::R0, &label2); 459 __ Bind(&label1); 460 constexpr size_t kLdrR0R0Count2 = 128; 461 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 462 __ ldr(arm::R0, arm::Address(arm::R0)); 463 } 464 __ Bind(&label2); 465 466 std::string expected = 467 "cbz r0, 1f\n" + // cbz r0, label1 468 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 469 "0:\n" 470 "cmp r0, #0\n" // cbz r0, label2 471 "beq.n 2f\n" 472 "1:\n" + 473 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 474 "2:\n"; 475 DriverStr(expected, "TwoCbzSecondAtMaxB16Offset"); 476 477 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u, 478 __ GetAdjustedPosition(label0.Position())); 479 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u, 480 __ GetAdjustedPosition(label1.Position())); 481 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u, 482 __ GetAdjustedPosition(label2.Position())); 483} 484 485TEST_F(AssemblerThumb2Test, TwoCbzSecondBeyondMaxB16Offset) { 486 Label label0, label1, label2; 487 __ cbz(arm::R0, &label1); 488 constexpr size_t kLdrR0R0Count1 = 62; 489 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 490 __ ldr(arm::R0, arm::Address(arm::R0)); 491 } 492 __ Bind(&label0); 493 __ cbz(arm::R0, &label2); 494 __ Bind(&label1); 495 constexpr size_t kLdrR0R0Count2 = 129; 496 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 497 __ ldr(arm::R0, arm::Address(arm::R0)); 498 } 499 __ Bind(&label2); 500 501 std::string expected = 502 "cmp r0, #0\n" // cbz r0, label1 503 "beq.n 1f\n" + 504 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 505 "0:\n" 506 "cmp r0, #0\n" // cbz r0, label2 507 "beq.w 2f\n" 508 "1:\n" + 509 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 510 "2:\n"; 511 DriverStr(expected, "TwoCbzSecondBeyondMaxB16Offset"); 512 513 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u, 514 __ GetAdjustedPosition(label0.Position())); 515 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u, 516 __ GetAdjustedPosition(label1.Position())); 517 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u, 518 __ GetAdjustedPosition(label2.Position())); 519} 520 521TEST_F(AssemblerThumb2Test, TwoCbzFirstAtMaxB16Offset) { 522 Label label0, label1, label2; 523 __ cbz(arm::R0, &label1); 524 constexpr size_t kLdrR0R0Count1 = 127; 525 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 526 __ ldr(arm::R0, arm::Address(arm::R0)); 527 } 528 __ Bind(&label0); 529 __ cbz(arm::R0, &label2); 530 __ Bind(&label1); 531 constexpr size_t kLdrR0R0Count2 = 64; 532 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 533 __ ldr(arm::R0, arm::Address(arm::R0)); 534 } 535 __ Bind(&label2); 536 537 std::string expected = 538 "cmp r0, #0\n" // cbz r0, label1 539 "beq.n 1f\n" + 540 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 541 "0:\n" 542 "cbz r0, 2f\n" // cbz r0, label2 543 "1:\n" + 544 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 545 "2:\n"; 546 DriverStr(expected, "TwoCbzFirstAtMaxB16Offset"); 547 548 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u, 549 __ GetAdjustedPosition(label0.Position())); 550 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u, 551 __ GetAdjustedPosition(label1.Position())); 552 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u, 553 __ GetAdjustedPosition(label2.Position())); 554} 555 556TEST_F(AssemblerThumb2Test, TwoCbzFirstBeyondMaxB16Offset) { 557 Label label0, label1, label2; 558 __ cbz(arm::R0, &label1); 559 constexpr size_t kLdrR0R0Count1 = 127; 560 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 561 __ ldr(arm::R0, arm::Address(arm::R0)); 562 } 563 __ Bind(&label0); 564 __ cbz(arm::R0, &label2); 565 __ Bind(&label1); 566 constexpr size_t kLdrR0R0Count2 = 65; 567 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 568 __ ldr(arm::R0, arm::Address(arm::R0)); 569 } 570 __ Bind(&label2); 571 572 std::string expected = 573 "cmp r0, #0\n" // cbz r0, label1 574 "beq.w 1f\n" + 575 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 576 "0:\n" 577 "cmp r0, #0\n" // cbz r0, label2 578 "beq.n 2f\n" 579 "1:\n" + 580 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 581 "2:\n"; 582 DriverStr(expected, "TwoCbzFirstBeyondMaxB16Offset"); 583 584 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 4u, 585 __ GetAdjustedPosition(label0.Position())); 586 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u, 587 __ GetAdjustedPosition(label1.Position())); 588 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u, 589 __ GetAdjustedPosition(label2.Position())); 590} 591 592TEST_F(AssemblerThumb2Test, LoadLiteralMax1KiB) { 593 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 594 __ LoadLiteral(arm::R0, literal); 595 Label label; 596 __ Bind(&label); 597 constexpr size_t kLdrR0R0Count = 511; 598 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 599 __ ldr(arm::R0, arm::Address(arm::R0)); 600 } 601 602 std::string expected = 603 "1:\n" 604 "ldr.n r0, [pc, #((2f - 1b - 2) & ~2)]\n" + 605 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 606 ".align 2, 0\n" 607 "2:\n" 608 ".word 0x12345678\n"; 609 DriverStr(expected, "LoadLiteralMax1KiB"); 610 611 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u, 612 __ GetAdjustedPosition(label.Position())); 613} 614 615TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiB) { 616 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 617 __ LoadLiteral(arm::R0, literal); 618 Label label; 619 __ Bind(&label); 620 constexpr size_t kLdrR0R0Count = 512; 621 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 622 __ ldr(arm::R0, arm::Address(arm::R0)); 623 } 624 625 std::string expected = 626 "1:\n" 627 "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" + 628 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 629 ".align 2, 0\n" 630 "2:\n" 631 ".word 0x12345678\n"; 632 DriverStr(expected, "LoadLiteralBeyondMax1KiB"); 633 634 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u, 635 __ GetAdjustedPosition(label.Position())); 636} 637 638TEST_F(AssemblerThumb2Test, LoadLiteralMax4KiB) { 639 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 640 __ LoadLiteral(arm::R1, literal); 641 Label label; 642 __ Bind(&label); 643 constexpr size_t kLdrR0R0Count = 2046; 644 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 645 __ ldr(arm::R0, arm::Address(arm::R0)); 646 } 647 648 std::string expected = 649 "1:\n" 650 "ldr.w r1, [pc, #((2f - 1b - 2) & ~2)]\n" + 651 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 652 ".align 2, 0\n" 653 "2:\n" 654 ".word 0x12345678\n"; 655 DriverStr(expected, "LoadLiteralMax4KiB"); 656 657 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u, 658 __ GetAdjustedPosition(label.Position())); 659} 660 661TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax4KiB) { 662 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 663 __ LoadLiteral(arm::R1, literal); 664 Label label; 665 __ Bind(&label); 666 constexpr size_t kLdrR0R0Count = 2047; 667 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 668 __ ldr(arm::R0, arm::Address(arm::R0)); 669 } 670 671 std::string expected = 672 "movw r1, #4096\n" // "as" does not consider (2f - 1f - 4) a constant expression for movw. 673 "1:\n" 674 "add r1, pc\n" 675 "ldr r1, [r1, #0]\n" + 676 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 677 ".align 2, 0\n" 678 "2:\n" 679 ".word 0x12345678\n"; 680 DriverStr(expected, "LoadLiteralBeyondMax4KiB"); 681 682 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u, 683 __ GetAdjustedPosition(label.Position())); 684} 685 686TEST_F(AssemblerThumb2Test, LoadLiteralMax64KiB) { 687 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 688 __ LoadLiteral(arm::R1, literal); 689 Label label; 690 __ Bind(&label); 691 constexpr size_t kLdrR0R0Count = (1u << 15) - 2u; 692 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 693 __ ldr(arm::R0, arm::Address(arm::R0)); 694 } 695 696 std::string expected = 697 "movw r1, #0xfffc\n" // "as" does not consider (2f - 1f - 4) a constant expression for movw. 698 "1:\n" 699 "add r1, pc\n" 700 "ldr r1, [r1, #0]\n" + 701 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 702 ".align 2, 0\n" 703 "2:\n" 704 ".word 0x12345678\n"; 705 DriverStr(expected, "LoadLiteralMax64KiB"); 706 707 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u, 708 __ GetAdjustedPosition(label.Position())); 709} 710 711TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax64KiB) { 712 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 713 __ LoadLiteral(arm::R1, literal); 714 Label label; 715 __ Bind(&label); 716 constexpr size_t kLdrR0R0Count = (1u << 15) - 1u; 717 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 718 __ ldr(arm::R0, arm::Address(arm::R0)); 719 } 720 721 std::string expected = 722 "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n" 723 "1:\n" 724 "add r1, pc\n" 725 "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" + 726 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 727 ".align 2, 0\n" 728 "2:\n" 729 ".word 0x12345678\n"; 730 DriverStr(expected, "LoadLiteralBeyondMax64KiB"); 731 732 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u, 733 __ GetAdjustedPosition(label.Position())); 734} 735 736TEST_F(AssemblerThumb2Test, LoadLiteralMax1MiB) { 737 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 738 __ LoadLiteral(arm::R1, literal); 739 Label label; 740 __ Bind(&label); 741 constexpr size_t kLdrR0R0Count = (1u << 19) - 3u; 742 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 743 __ ldr(arm::R0, arm::Address(arm::R0)); 744 } 745 746 std::string expected = 747 "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n" 748 "1:\n" 749 "add r1, pc\n" 750 "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" + 751 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 752 ".align 2, 0\n" 753 "2:\n" 754 ".word 0x12345678\n"; 755 DriverStr(expected, "LoadLiteralMax1MiB"); 756 757 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u, 758 __ GetAdjustedPosition(label.Position())); 759} 760 761TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1MiB) { 762 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 763 __ LoadLiteral(arm::R1, literal); 764 Label label; 765 __ Bind(&label); 766 constexpr size_t kLdrR0R0Count = (1u << 19) - 2u; 767 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 768 __ ldr(arm::R0, arm::Address(arm::R0)); 769 } 770 771 std::string expected = 772 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw. 773 "movw r1, #(0x100000 & 0xffff)\n" 774 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt. 775 "movt r1, #(0x100000 >> 16)\n" 776 "1:\n" 777 "add r1, pc\n" 778 "ldr.w r1, [r1, #0]\n" + 779 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 780 ".align 2, 0\n" 781 "2:\n" 782 ".word 0x12345678\n"; 783 DriverStr(expected, "LoadLiteralBeyondMax1MiB"); 784 785 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u, 786 __ GetAdjustedPosition(label.Position())); 787} 788 789TEST_F(AssemblerThumb2Test, LoadLiteralFar) { 790 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 791 __ LoadLiteral(arm::R1, literal); 792 Label label; 793 __ Bind(&label); 794 constexpr size_t kLdrR0R0Count = (1u << 19) - 2u + 0x1234; 795 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 796 __ ldr(arm::R0, arm::Address(arm::R0)); 797 } 798 799 std::string expected = 800 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw. 801 "movw r1, #((0x100000 + 2 * 0x1234) & 0xffff)\n" 802 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt. 803 "movt r1, #((0x100000 + 2 * 0x1234) >> 16)\n" 804 "1:\n" 805 "add r1, pc\n" 806 "ldr.w r1, [r1, #0]\n" + 807 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 808 ".align 2, 0\n" 809 "2:\n" 810 ".word 0x12345678\n"; 811 DriverStr(expected, "LoadLiteralFar"); 812 813 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u, 814 __ GetAdjustedPosition(label.Position())); 815} 816 817TEST_F(AssemblerThumb2Test, LoadLiteralWideMax1KiB) { 818 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321)); 819 __ LoadLiteral(arm::R1, arm::R3, literal); 820 Label label; 821 __ Bind(&label); 822 constexpr size_t kLdrR0R0Count = 510; 823 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 824 __ ldr(arm::R0, arm::Address(arm::R0)); 825 } 826 827 std::string expected = 828 "1:\n" 829 "ldrd r1, r3, [pc, #((2f - 1b - 2) & ~2)]\n" + 830 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 831 ".align 2, 0\n" 832 "2:\n" 833 ".word 0x87654321\n" 834 ".word 0x12345678\n"; 835 DriverStr(expected, "LoadLiteralWideMax1KiB"); 836 837 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u, 838 __ GetAdjustedPosition(label.Position())); 839} 840 841TEST_F(AssemblerThumb2Test, LoadLiteralWideBeyondMax1KiB) { 842 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321)); 843 __ LoadLiteral(arm::R1, arm::R3, literal); 844 Label label; 845 __ Bind(&label); 846 constexpr size_t kLdrR0R0Count = 511; 847 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 848 __ ldr(arm::R0, arm::Address(arm::R0)); 849 } 850 851 std::string expected = 852 "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n" 853 "1:\n" 854 "add ip, pc\n" 855 "ldrd r1, r3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" + 856 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 857 ".align 2, 0\n" 858 "2:\n" 859 ".word 0x87654321\n" 860 ".word 0x12345678\n"; 861 DriverStr(expected, "LoadLiteralWideBeyondMax1KiB"); 862 863 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u, 864 __ GetAdjustedPosition(label.Position())); 865} 866 867TEST_F(AssemblerThumb2Test, LoadLiteralSingleMax256KiB) { 868 // The literal size must match but the type doesn't, so use an int32_t rather than float. 869 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 870 __ LoadLiteral(arm::S3, literal); 871 Label label; 872 __ Bind(&label); 873 constexpr size_t kLdrR0R0Count = (1 << 17) - 3u; 874 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 875 __ ldr(arm::R0, arm::Address(arm::R0)); 876 } 877 878 std::string expected = 879 "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n" 880 "1:\n" 881 "add ip, pc\n" 882 "vldr s3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" + 883 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 884 ".align 2, 0\n" 885 "2:\n" 886 ".word 0x12345678\n"; 887 DriverStr(expected, "LoadLiteralSingleMax256KiB"); 888 889 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u, 890 __ GetAdjustedPosition(label.Position())); 891} 892 893TEST_F(AssemblerThumb2Test, LoadLiteralDoubleBeyondMax256KiB) { 894 // The literal size must match but the type doesn't, so use an int64_t rather than double. 895 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321)); 896 __ LoadLiteral(arm::D3, literal); 897 Label label; 898 __ Bind(&label); 899 constexpr size_t kLdrR0R0Count = (1 << 17) - 2u; 900 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 901 __ ldr(arm::R0, arm::Address(arm::R0)); 902 } 903 904 std::string expected = 905 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw. 906 "movw ip, #(0x40000 & 0xffff)\n" 907 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt. 908 "movt ip, #(0x40000 >> 16)\n" 909 "1:\n" 910 "add ip, pc\n" 911 "vldr d3, [ip, #0]\n" + 912 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 913 ".align 2, 0\n" 914 "2:\n" 915 ".word 0x87654321\n" 916 ".word 0x12345678\n"; 917 DriverStr(expected, "LoadLiteralDoubleBeyondMax256KiB"); 918 919 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u, 920 __ GetAdjustedPosition(label.Position())); 921} 922 923TEST_F(AssemblerThumb2Test, LoadLiteralDoubleFar) { 924 // The literal size must match but the type doesn't, so use an int64_t rather than double. 925 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321)); 926 __ LoadLiteral(arm::D3, literal); 927 Label label; 928 __ Bind(&label); 929 constexpr size_t kLdrR0R0Count = (1 << 17) - 2u + 0x1234; 930 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 931 __ ldr(arm::R0, arm::Address(arm::R0)); 932 } 933 934 std::string expected = 935 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw. 936 "movw ip, #((0x40000 + 2 * 0x1234) & 0xffff)\n" 937 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt. 938 "movt ip, #((0x40000 + 2 * 0x1234) >> 16)\n" 939 "1:\n" 940 "add ip, pc\n" 941 "vldr d3, [ip, #0]\n" + 942 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 943 ".align 2, 0\n" 944 "2:\n" 945 ".word 0x87654321\n" 946 ".word 0x12345678\n"; 947 DriverStr(expected, "LoadLiteralDoubleFar"); 948 949 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u, 950 __ GetAdjustedPosition(label.Position())); 951} 952 953TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiBDueToAlignmentOnSecondPass) { 954 // First part: as TwoCbzBeyondMaxOffset but add one 16-bit instruction to the end, 955 // so that the size is not Aligned<4>(.). On the first pass, the assembler resizes 956 // the second CBZ because it's out of range, then it will resize the first CBZ 957 // which has been pushed out of range. Thus, after the first pass, the code size 958 // will appear Aligned<4>(.) but the final size will not be. 959 Label label0, label1, label2; 960 __ cbz(arm::R0, &label1); 961 constexpr size_t kLdrR0R0Count1 = 63; 962 for (size_t i = 0; i != kLdrR0R0Count1; ++i) { 963 __ ldr(arm::R0, arm::Address(arm::R0)); 964 } 965 __ Bind(&label0); 966 __ cbz(arm::R0, &label2); 967 __ Bind(&label1); 968 constexpr size_t kLdrR0R0Count2 = 65; 969 for (size_t i = 0; i != kLdrR0R0Count2; ++i) { 970 __ ldr(arm::R0, arm::Address(arm::R0)); 971 } 972 __ Bind(&label2); 973 __ ldr(arm::R0, arm::Address(arm::R0)); 974 975 std::string expected_part1 = 976 "cmp r0, #0\n" // cbz r0, label1 977 "beq.n 1f\n" + 978 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") + 979 "0:\n" 980 "cmp r0, #0\n" // cbz r0, label2 981 "beq.n 2f\n" 982 "1:\n" + 983 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") + 984 "2:\n" // Here the offset is Aligned<4>(.). 985 "ldr r0, [r0]\n"; // Make the first part 986 987 // Second part: as LoadLiteralMax1KiB with the caveat that the offset of the load 988 // literal will not be Aligned<4>(.) but it will appear to be when we process the 989 // instruction during the first pass, so the literal will need a padding and it 990 // will push the literal out of range, so we shall end up with "ldr.w". 991 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678); 992 __ LoadLiteral(arm::R0, literal); 993 Label label; 994 __ Bind(&label); 995 constexpr size_t kLdrR0R0Count = 511; 996 for (size_t i = 0; i != kLdrR0R0Count; ++i) { 997 __ ldr(arm::R0, arm::Address(arm::R0)); 998 } 999 1000 std::string expected = 1001 expected_part1 + 1002 "1:\n" 1003 "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" + 1004 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") + 1005 ".align 2, 0\n" 1006 "2:\n" 1007 ".word 0x12345678\n"; 1008 DriverStr(expected, "LoadLiteralMax1KiB"); 1009 1010 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u, 1011 __ GetAdjustedPosition(label.Position())); 1012} 1013 1014TEST_F(AssemblerThumb2Test, Clz) { 1015 __ clz(arm::R0, arm::R1); 1016 1017 const char* expected = "clz r0, r1\n"; 1018 1019 DriverStr(expected, "clz"); 1020} 1021 1022TEST_F(AssemblerThumb2Test, rbit) { 1023 __ rbit(arm::R1, arm::R0); 1024 1025 const char* expected = "rbit r1, r0\n"; 1026 1027 DriverStr(expected, "rbit"); 1028} 1029 1030} // namespace art 1031