Home | History | Annotate | Download | only in arm
      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 "base/stringprintf.h"
     21 #include "utils/assembler_test.h"
     22 
     23 namespace art {
     24 
     25 class AssemblerThumb2Test : public AssemblerTest<arm::Thumb2Assembler,
     26                                                  arm::Register, arm::SRegister,
     27                                                  uint32_t> {
     28  protected:
     29   std::string GetArchitectureString() OVERRIDE {
     30     return "arm";
     31   }
     32 
     33   std::string GetAssemblerParameters() OVERRIDE {
     34     return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon -mthumb";
     35   }
     36 
     37   const char* GetAssemblyHeader() OVERRIDE {
     38     return kThumb2AssemblyHeader;
     39   }
     40 
     41   std::string GetDisassembleParameters() OVERRIDE {
     42     return " -D -bbinary -marm --disassembler-options=force-thumb --no-show-raw-insn";
     43   }
     44 
     45   void SetUpHelpers() OVERRIDE {
     46     if (registers_.size() == 0) {
     47       registers_.insert(end(registers_),
     48                         {  // NOLINT(whitespace/braces)
     49                           new arm::Register(arm::R0),
     50                           new arm::Register(arm::R1),
     51                           new arm::Register(arm::R2),
     52                           new arm::Register(arm::R3),
     53                           new arm::Register(arm::R4),
     54                           new arm::Register(arm::R5),
     55                           new arm::Register(arm::R6),
     56                           new arm::Register(arm::R7),
     57                           new arm::Register(arm::R8),
     58                           new arm::Register(arm::R9),
     59                           new arm::Register(arm::R10),
     60                           new arm::Register(arm::R11),
     61                           new arm::Register(arm::R12),
     62                           new arm::Register(arm::R13),
     63                           new arm::Register(arm::R14),
     64                           new arm::Register(arm::R15)
     65                         });
     66     }
     67   }
     68 
     69   void TearDown() OVERRIDE {
     70     AssemblerTest::TearDown();
     71     STLDeleteElements(&registers_);
     72   }
     73 
     74   std::vector<arm::Register*> GetRegisters() OVERRIDE {
     75     return registers_;
     76   }
     77 
     78   uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
     79     return imm_value;
     80   }
     81 
     82   std::string RepeatInsn(size_t count, const std::string& insn) {
     83     std::string result;
     84     for (; count != 0u; --count) {
     85       result += insn;
     86     }
     87     return result;
     88   }
     89 
     90  private:
     91   std::vector<arm::Register*> registers_;
     92 
     93   static constexpr const char* kThumb2AssemblyHeader = ".syntax unified\n.thumb\n";
     94 };
     95 
     96 TEST_F(AssemblerThumb2Test, Toolchain) {
     97   EXPECT_TRUE(CheckTools());
     98 }
     99 
    100 #define __ GetAssembler()->
    101 
    102 TEST_F(AssemblerThumb2Test, Sbfx) {
    103   __ sbfx(arm::R0, arm::R1, 0, 1);
    104   __ sbfx(arm::R0, arm::R1, 0, 8);
    105   __ sbfx(arm::R0, arm::R1, 0, 16);
    106   __ sbfx(arm::R0, arm::R1, 0, 32);
    107 
    108   __ sbfx(arm::R0, arm::R1, 8, 1);
    109   __ sbfx(arm::R0, arm::R1, 8, 8);
    110   __ sbfx(arm::R0, arm::R1, 8, 16);
    111   __ sbfx(arm::R0, arm::R1, 8, 24);
    112 
    113   __ sbfx(arm::R0, arm::R1, 16, 1);
    114   __ sbfx(arm::R0, arm::R1, 16, 8);
    115   __ sbfx(arm::R0, arm::R1, 16, 16);
    116 
    117   __ sbfx(arm::R0, arm::R1, 31, 1);
    118 
    119   const char* expected =
    120       "sbfx r0, r1, #0, #1\n"
    121       "sbfx r0, r1, #0, #8\n"
    122       "sbfx r0, r1, #0, #16\n"
    123       "sbfx r0, r1, #0, #32\n"
    124 
    125       "sbfx r0, r1, #8, #1\n"
    126       "sbfx r0, r1, #8, #8\n"
    127       "sbfx r0, r1, #8, #16\n"
    128       "sbfx r0, r1, #8, #24\n"
    129 
    130       "sbfx r0, r1, #16, #1\n"
    131       "sbfx r0, r1, #16, #8\n"
    132       "sbfx r0, r1, #16, #16\n"
    133 
    134       "sbfx r0, r1, #31, #1\n";
    135   DriverStr(expected, "sbfx");
    136 }
    137 
    138 TEST_F(AssemblerThumb2Test, Ubfx) {
    139   __ ubfx(arm::R0, arm::R1, 0, 1);
    140   __ ubfx(arm::R0, arm::R1, 0, 8);
    141   __ ubfx(arm::R0, arm::R1, 0, 16);
    142   __ ubfx(arm::R0, arm::R1, 0, 32);
    143 
    144   __ ubfx(arm::R0, arm::R1, 8, 1);
    145   __ ubfx(arm::R0, arm::R1, 8, 8);
    146   __ ubfx(arm::R0, arm::R1, 8, 16);
    147   __ ubfx(arm::R0, arm::R1, 8, 24);
    148 
    149   __ ubfx(arm::R0, arm::R1, 16, 1);
    150   __ ubfx(arm::R0, arm::R1, 16, 8);
    151   __ ubfx(arm::R0, arm::R1, 16, 16);
    152 
    153   __ ubfx(arm::R0, arm::R1, 31, 1);
    154 
    155   const char* expected =
    156       "ubfx r0, r1, #0, #1\n"
    157       "ubfx r0, r1, #0, #8\n"
    158       "ubfx r0, r1, #0, #16\n"
    159       "ubfx r0, r1, #0, #32\n"
    160 
    161       "ubfx r0, r1, #8, #1\n"
    162       "ubfx r0, r1, #8, #8\n"
    163       "ubfx r0, r1, #8, #16\n"
    164       "ubfx r0, r1, #8, #24\n"
    165 
    166       "ubfx r0, r1, #16, #1\n"
    167       "ubfx r0, r1, #16, #8\n"
    168       "ubfx r0, r1, #16, #16\n"
    169 
    170       "ubfx r0, r1, #31, #1\n";
    171   DriverStr(expected, "ubfx");
    172 }
    173 
    174 TEST_F(AssemblerThumb2Test, Vmstat) {
    175   __ vmstat();
    176 
    177   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
    178 
    179   DriverStr(expected, "vmrs");
    180 }
    181 
    182 TEST_F(AssemblerThumb2Test, ldrexd) {
    183   __ ldrexd(arm::R0, arm::R1, arm::R0);
    184   __ ldrexd(arm::R0, arm::R1, arm::R1);
    185   __ ldrexd(arm::R0, arm::R1, arm::R2);
    186   __ ldrexd(arm::R5, arm::R3, arm::R7);
    187 
    188   const char* expected =
    189       "ldrexd r0, r1, [r0]\n"
    190       "ldrexd r0, r1, [r1]\n"
    191       "ldrexd r0, r1, [r2]\n"
    192       "ldrexd r5, r3, [r7]\n";
    193   DriverStr(expected, "ldrexd");
    194 }
    195 
    196 TEST_F(AssemblerThumb2Test, strexd) {
    197   __ strexd(arm::R9, arm::R0, arm::R1, arm::R0);
    198   __ strexd(arm::R9, arm::R0, arm::R1, arm::R1);
    199   __ strexd(arm::R9, arm::R0, arm::R1, arm::R2);
    200   __ strexd(arm::R9, arm::R5, arm::R3, arm::R7);
    201 
    202   const char* expected =
    203       "strexd r9, r0, r1, [r0]\n"
    204       "strexd r9, r0, r1, [r1]\n"
    205       "strexd r9, r0, r1, [r2]\n"
    206       "strexd r9, r5, r3, [r7]\n";
    207   DriverStr(expected, "strexd");
    208 }
    209 
    210 TEST_F(AssemblerThumb2Test, LdrdStrd) {
    211   __ ldrd(arm::R0, arm::Address(arm::R2, 8));
    212   __ ldrd(arm::R0, arm::Address(arm::R12));
    213   __ strd(arm::R0, arm::Address(arm::R2, 8));
    214 
    215   const char* expected =
    216       "ldrd r0, r1, [r2, #8]\n"
    217       "ldrd r0, r1, [r12]\n"
    218       "strd r0, r1, [r2, #8]\n";
    219   DriverStr(expected, "ldrdstrd");
    220 }
    221 
    222 TEST_F(AssemblerThumb2Test, eor) {
    223   __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0));
    224   __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1));
    225   __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0));
    226   __ eor(arm::R8, arm::R1, arm::ShifterOperand(arm::R0));
    227   __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R8));
    228 
    229   const char* expected =
    230       "eors r1, r0\n"
    231       "eor r1, r0, r1\n"
    232       "eor r1, r8, r0\n"
    233       "eor r8, r1, r0\n"
    234       "eor r1, r0, r8\n";
    235   DriverStr(expected, "abs");
    236 }
    237 
    238 TEST_F(AssemblerThumb2Test, sub) {
    239   __ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
    240   __ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
    241   __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
    242   __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
    243 
    244   const char* expected =
    245       "subs r1, r0, #42\n"
    246       "sub.w r1, r0, #42\n"
    247       "subs r1, r0, r2, asr #31\n"
    248       "sub r1, r0, r2, asr #31\n";
    249   DriverStr(expected, "sub");
    250 }
    251 
    252 TEST_F(AssemblerThumb2Test, add) {
    253   __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
    254   __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
    255   __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
    256   __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
    257 
    258   const char* expected =
    259       "adds r1, r0, #42\n"
    260       "add.w r1, r0, #42\n"
    261       "adds r1, r0, r2, asr #31\n"
    262       "add r1, r0, r2, asr #31\n";
    263   DriverStr(expected, "add");
    264 }
    265 
    266 TEST_F(AssemblerThumb2Test, umull) {
    267   __ umull(arm::R0, arm::R1, arm::R2, arm::R3);
    268 
    269   const char* expected =
    270       "umull r0, r1, r2, r3\n";
    271   DriverStr(expected, "umull");
    272 }
    273 
    274 TEST_F(AssemblerThumb2Test, smull) {
    275   __ smull(arm::R0, arm::R1, arm::R2, arm::R3);
    276 
    277   const char* expected =
    278       "smull r0, r1, r2, r3\n";
    279   DriverStr(expected, "smull");
    280 }
    281 
    282 TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
    283   arm::StoreOperandType type = arm::kStoreWord;
    284   int32_t offset = 4092;
    285   ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
    286 
    287   __ StoreToOffset(type, arm::R0, arm::SP, offset);
    288   __ StoreToOffset(type, arm::IP, arm::SP, offset);
    289   __ StoreToOffset(type, arm::IP, arm::R5, offset);
    290 
    291   const char* expected =
    292       "str r0, [sp, #4092]\n"
    293       "str ip, [sp, #4092]\n"
    294       "str ip, [r5, #4092]\n";
    295   DriverStr(expected, "StoreWordToThumbOffset");
    296 }
    297 
    298 TEST_F(AssemblerThumb2Test, StoreWordToNonThumbOffset) {
    299   arm::StoreOperandType type = arm::kStoreWord;
    300   int32_t offset = 4096;
    301   ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
    302 
    303   __ StoreToOffset(type, arm::R0, arm::SP, offset);
    304   __ StoreToOffset(type, arm::IP, arm::SP, offset);
    305   __ StoreToOffset(type, arm::IP, arm::R5, offset);
    306 
    307   const char* expected =
    308       "add.w ip, sp, #4096\n"   // AddConstant(ip, sp, 4096)
    309       "str r0, [ip, #0]\n"
    310 
    311       "str r5, [sp, #-4]!\n"    // Push(r5)
    312       "add.w r5, sp, #4096\n"   // AddConstant(r5, 4100 & ~0xfff)
    313       "str ip, [r5, #4]\n"      // StoreToOffset(type, ip, r5, 4100 & 0xfff)
    314       "ldr r5, [sp], #4\n"      // Pop(r5)
    315 
    316       "str r6, [sp, #-4]!\n"    // Push(r6)
    317       "add.w r6, r5, #4096\n"   // AddConstant(r6, r5, 4096 & ~0xfff)
    318       "str ip, [r6, #0]\n"      // StoreToOffset(type, ip, r6, 4096 & 0xfff)
    319       "ldr r6, [sp], #4\n";     // Pop(r6)
    320   DriverStr(expected, "StoreWordToNonThumbOffset");
    321 }
    322 
    323 TEST_F(AssemblerThumb2Test, StoreWordPairToThumbOffset) {
    324   arm::StoreOperandType type = arm::kStoreWordPair;
    325   int32_t offset = 1020;
    326   ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
    327 
    328   __ StoreToOffset(type, arm::R0, arm::SP, offset);
    329   // We cannot use IP (i.e. R12) as first source register, as it would
    330   // force us to use SP (i.e. R13) as second source register, which
    331   // would have an "unpredictable" effect according to the ARMv7
    332   // specification (the T1 encoding describes the result as
    333   // UNPREDICTABLE when of the source registers is R13).
    334   //
    335   // So we use (R11, IP) (e.g. (R11, R12)) as source registers in the
    336   // following instructions.
    337   __ StoreToOffset(type, arm::R11, arm::SP, offset);
    338   __ StoreToOffset(type, arm::R11, arm::R5, offset);
    339 
    340   const char* expected =
    341       "strd r0, r1, [sp, #1020]\n"
    342       "strd r11, ip, [sp, #1020]\n"
    343       "strd r11, ip, [r5, #1020]\n";
    344   DriverStr(expected, "StoreWordPairToThumbOffset");
    345 }
    346 
    347 TEST_F(AssemblerThumb2Test, StoreWordPairToNonThumbOffset) {
    348   arm::StoreOperandType type = arm::kStoreWordPair;
    349   int32_t offset = 1024;
    350   ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
    351 
    352   __ StoreToOffset(type, arm::R0, arm::SP, offset);
    353   // Same comment as in AssemblerThumb2Test.StoreWordPairToThumbOffset
    354   // regarding the use of (R11, IP) (e.g. (R11, R12)) as source
    355   // registers in the following instructions.
    356   __ StoreToOffset(type, arm::R11, arm::SP, offset);
    357   __ StoreToOffset(type, arm::R11, arm::R5, offset);
    358 
    359   const char* expected =
    360       "add.w ip, sp, #1024\n"     // AddConstant(ip, sp, 1024)
    361       "strd r0, r1, [ip, #0]\n"
    362 
    363       "str r5, [sp, #-4]!\n"      // Push(r5)
    364       "add.w r5, sp, #1024\n"     // AddConstant(r5, sp, (1024 + kRegisterSize) & ~0x3fc)
    365       "strd r11, ip, [r5, #4]\n"  // StoreToOffset(type, r11, sp, (1024 + kRegisterSize) & 0x3fc)
    366       "ldr r5, [sp], #4\n"        // Pop(r5)
    367 
    368       "str r6, [sp, #-4]!\n"      // Push(r6)
    369       "add.w r6, r5, #1024\n"     // AddConstant(r6, r5, 1024 & ~0x3fc)
    370       "strd r11, ip, [r6, #0]\n"  // StoreToOffset(type, r11, r6, 1024 & 0x3fc)
    371       "ldr r6, [sp], #4\n";       // Pop(r6)
    372   DriverStr(expected, "StoreWordPairToNonThumbOffset");
    373 }
    374 
    375 TEST_F(AssemblerThumb2Test, DistantBackBranch) {
    376   Label start, end;
    377   __ Bind(&start);
    378   constexpr size_t kLdrR0R0Count1 = 256;
    379   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    380     __ ldr(arm::R0, arm::Address(arm::R0));
    381   }
    382   __ b(&end, arm::EQ);
    383   __ b(&start, arm::LT);
    384   constexpr size_t kLdrR0R0Count2 = 256;
    385   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    386     __ ldr(arm::R0, arm::Address(arm::R0));
    387   }
    388   __ Bind(&end);
    389 
    390   std::string expected =
    391       "0:\n" +
    392       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    393       "beq 1f\n"
    394       "blt 0b\n" +
    395       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    396       "1:\n";
    397   DriverStr(expected, "DistantBackBranch");
    398 }
    399 
    400 TEST_F(AssemblerThumb2Test, TwoCbzMaxOffset) {
    401   Label label0, label1, label2;
    402   __ cbz(arm::R0, &label1);
    403   constexpr size_t kLdrR0R0Count1 = 63;
    404   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    405     __ ldr(arm::R0, arm::Address(arm::R0));
    406   }
    407   __ Bind(&label0);
    408   __ cbz(arm::R0, &label2);
    409   __ Bind(&label1);
    410   constexpr size_t kLdrR0R0Count2 = 64;
    411   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    412     __ ldr(arm::R0, arm::Address(arm::R0));
    413   }
    414   __ Bind(&label2);
    415 
    416   std::string expected =
    417       "cbz r0, 1f\n" +            // cbz r0, label1
    418       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    419       "0:\n"
    420       "cbz r0, 2f\n"              // cbz r0, label2
    421       "1:\n" +
    422       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    423       "2:\n";
    424   DriverStr(expected, "TwoCbzMaxOffset");
    425 
    426   EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u,
    427             __ GetAdjustedPosition(label0.Position()));
    428   EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 0u,
    429             __ GetAdjustedPosition(label1.Position()));
    430   EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 0u,
    431             __ GetAdjustedPosition(label2.Position()));
    432 }
    433 
    434 TEST_F(AssemblerThumb2Test, TwoCbzBeyondMaxOffset) {
    435   Label label0, label1, label2;
    436   __ cbz(arm::R0, &label1);
    437   constexpr size_t kLdrR0R0Count1 = 63;
    438   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    439     __ ldr(arm::R0, arm::Address(arm::R0));
    440   }
    441   __ Bind(&label0);
    442   __ cbz(arm::R0, &label2);
    443   __ Bind(&label1);
    444   constexpr size_t kLdrR0R0Count2 = 65;
    445   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    446     __ ldr(arm::R0, arm::Address(arm::R0));
    447   }
    448   __ Bind(&label2);
    449 
    450   std::string expected =
    451       "cmp r0, #0\n"              // cbz r0, label1
    452       "beq.n 1f\n" +
    453       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    454       "0:\n"
    455       "cmp r0, #0\n"              // cbz r0, label2
    456       "beq.n 2f\n"
    457       "1:\n" +
    458       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    459       "2:\n";
    460   DriverStr(expected, "TwoCbzBeyondMaxOffset");
    461 
    462   EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
    463             __ GetAdjustedPosition(label0.Position()));
    464   EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 4u,
    465             __ GetAdjustedPosition(label1.Position()));
    466   EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 4u,
    467             __ GetAdjustedPosition(label2.Position()));
    468 }
    469 
    470 TEST_F(AssemblerThumb2Test, TwoCbzSecondAtMaxB16Offset) {
    471   Label label0, label1, label2;
    472   __ cbz(arm::R0, &label1);
    473   constexpr size_t kLdrR0R0Count1 = 62;
    474   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    475     __ ldr(arm::R0, arm::Address(arm::R0));
    476   }
    477   __ Bind(&label0);
    478   __ cbz(arm::R0, &label2);
    479   __ Bind(&label1);
    480   constexpr size_t kLdrR0R0Count2 = 128;
    481   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    482     __ ldr(arm::R0, arm::Address(arm::R0));
    483   }
    484   __ Bind(&label2);
    485 
    486   std::string expected =
    487       "cbz r0, 1f\n" +            // cbz r0, label1
    488       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    489       "0:\n"
    490       "cmp r0, #0\n"              // cbz r0, label2
    491       "beq.n 2f\n"
    492       "1:\n" +
    493       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    494       "2:\n";
    495   DriverStr(expected, "TwoCbzSecondAtMaxB16Offset");
    496 
    497   EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u,
    498             __ GetAdjustedPosition(label0.Position()));
    499   EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u,
    500             __ GetAdjustedPosition(label1.Position()));
    501   EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u,
    502             __ GetAdjustedPosition(label2.Position()));
    503 }
    504 
    505 TEST_F(AssemblerThumb2Test, TwoCbzSecondBeyondMaxB16Offset) {
    506   Label label0, label1, label2;
    507   __ cbz(arm::R0, &label1);
    508   constexpr size_t kLdrR0R0Count1 = 62;
    509   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    510     __ ldr(arm::R0, arm::Address(arm::R0));
    511   }
    512   __ Bind(&label0);
    513   __ cbz(arm::R0, &label2);
    514   __ Bind(&label1);
    515   constexpr size_t kLdrR0R0Count2 = 129;
    516   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    517     __ ldr(arm::R0, arm::Address(arm::R0));
    518   }
    519   __ Bind(&label2);
    520 
    521   std::string expected =
    522       "cmp r0, #0\n"              // cbz r0, label1
    523       "beq.n 1f\n" +
    524       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    525       "0:\n"
    526       "cmp r0, #0\n"              // cbz r0, label2
    527       "beq.w 2f\n"
    528       "1:\n" +
    529       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    530       "2:\n";
    531   DriverStr(expected, "TwoCbzSecondBeyondMaxB16Offset");
    532 
    533   EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
    534             __ GetAdjustedPosition(label0.Position()));
    535   EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u,
    536             __ GetAdjustedPosition(label1.Position()));
    537   EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u,
    538             __ GetAdjustedPosition(label2.Position()));
    539 }
    540 
    541 TEST_F(AssemblerThumb2Test, TwoCbzFirstAtMaxB16Offset) {
    542   Label label0, label1, label2;
    543   __ cbz(arm::R0, &label1);
    544   constexpr size_t kLdrR0R0Count1 = 127;
    545   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    546     __ ldr(arm::R0, arm::Address(arm::R0));
    547   }
    548   __ Bind(&label0);
    549   __ cbz(arm::R0, &label2);
    550   __ Bind(&label1);
    551   constexpr size_t kLdrR0R0Count2 = 64;
    552   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    553     __ ldr(arm::R0, arm::Address(arm::R0));
    554   }
    555   __ Bind(&label2);
    556 
    557   std::string expected =
    558       "cmp r0, #0\n"              // cbz r0, label1
    559       "beq.n 1f\n" +
    560       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    561       "0:\n"
    562       "cbz r0, 2f\n"              // cbz r0, label2
    563       "1:\n" +
    564       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    565       "2:\n";
    566   DriverStr(expected, "TwoCbzFirstAtMaxB16Offset");
    567 
    568   EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
    569             __ GetAdjustedPosition(label0.Position()));
    570   EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u,
    571             __ GetAdjustedPosition(label1.Position()));
    572   EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u,
    573             __ GetAdjustedPosition(label2.Position()));
    574 }
    575 
    576 TEST_F(AssemblerThumb2Test, TwoCbzFirstBeyondMaxB16Offset) {
    577   Label label0, label1, label2;
    578   __ cbz(arm::R0, &label1);
    579   constexpr size_t kLdrR0R0Count1 = 127;
    580   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    581     __ ldr(arm::R0, arm::Address(arm::R0));
    582   }
    583   __ Bind(&label0);
    584   __ cbz(arm::R0, &label2);
    585   __ Bind(&label1);
    586   constexpr size_t kLdrR0R0Count2 = 65;
    587   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    588     __ ldr(arm::R0, arm::Address(arm::R0));
    589   }
    590   __ Bind(&label2);
    591 
    592   std::string expected =
    593       "cmp r0, #0\n"              // cbz r0, label1
    594       "beq.w 1f\n" +
    595       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    596       "0:\n"
    597       "cmp r0, #0\n"              // cbz r0, label2
    598       "beq.n 2f\n"
    599       "1:\n" +
    600       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
    601       "2:\n";
    602   DriverStr(expected, "TwoCbzFirstBeyondMaxB16Offset");
    603 
    604   EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 4u,
    605             __ GetAdjustedPosition(label0.Position()));
    606   EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u,
    607             __ GetAdjustedPosition(label1.Position()));
    608   EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u,
    609             __ GetAdjustedPosition(label2.Position()));
    610 }
    611 
    612 TEST_F(AssemblerThumb2Test, LoadLiteralMax1KiB) {
    613   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    614   __ LoadLiteral(arm::R0, literal);
    615   Label label;
    616   __ Bind(&label);
    617   constexpr size_t kLdrR0R0Count = 511;
    618   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    619     __ ldr(arm::R0, arm::Address(arm::R0));
    620   }
    621 
    622   std::string expected =
    623       "1:\n"
    624       "ldr.n r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
    625       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    626       ".align 2, 0\n"
    627       "2:\n"
    628       ".word 0x12345678\n";
    629   DriverStr(expected, "LoadLiteralMax1KiB");
    630 
    631   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u,
    632             __ GetAdjustedPosition(label.Position()));
    633 }
    634 
    635 TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiB) {
    636   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    637   __ LoadLiteral(arm::R0, literal);
    638   Label label;
    639   __ Bind(&label);
    640   constexpr size_t kLdrR0R0Count = 512;
    641   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    642     __ ldr(arm::R0, arm::Address(arm::R0));
    643   }
    644 
    645   std::string expected =
    646       "1:\n"
    647       "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
    648       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    649       ".align 2, 0\n"
    650       "2:\n"
    651       ".word 0x12345678\n";
    652   DriverStr(expected, "LoadLiteralBeyondMax1KiB");
    653 
    654   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u,
    655             __ GetAdjustedPosition(label.Position()));
    656 }
    657 
    658 TEST_F(AssemblerThumb2Test, LoadLiteralMax4KiB) {
    659   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    660   __ LoadLiteral(arm::R1, literal);
    661   Label label;
    662   __ Bind(&label);
    663   constexpr size_t kLdrR0R0Count = 2046;
    664   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    665     __ ldr(arm::R0, arm::Address(arm::R0));
    666   }
    667 
    668   std::string expected =
    669       "1:\n"
    670       "ldr.w r1, [pc, #((2f - 1b - 2) & ~2)]\n" +
    671       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    672       ".align 2, 0\n"
    673       "2:\n"
    674       ".word 0x12345678\n";
    675   DriverStr(expected, "LoadLiteralMax4KiB");
    676 
    677   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u,
    678             __ GetAdjustedPosition(label.Position()));
    679 }
    680 
    681 TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax4KiB) {
    682   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    683   __ LoadLiteral(arm::R1, literal);
    684   Label label;
    685   __ Bind(&label);
    686   constexpr size_t kLdrR0R0Count = 2047;
    687   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    688     __ ldr(arm::R0, arm::Address(arm::R0));
    689   }
    690 
    691   std::string expected =
    692       "movw r1, #4096\n"  // "as" does not consider (2f - 1f - 4) a constant expression for movw.
    693       "1:\n"
    694       "add r1, pc\n"
    695       "ldr r1, [r1, #0]\n" +
    696       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    697       ".align 2, 0\n"
    698       "2:\n"
    699       ".word 0x12345678\n";
    700   DriverStr(expected, "LoadLiteralBeyondMax4KiB");
    701 
    702   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
    703             __ GetAdjustedPosition(label.Position()));
    704 }
    705 
    706 TEST_F(AssemblerThumb2Test, LoadLiteralMax64KiB) {
    707   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    708   __ LoadLiteral(arm::R1, literal);
    709   Label label;
    710   __ Bind(&label);
    711   constexpr size_t kLdrR0R0Count = (1u << 15) - 2u;
    712   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    713     __ ldr(arm::R0, arm::Address(arm::R0));
    714   }
    715 
    716   std::string expected =
    717       "movw r1, #0xfffc\n"  // "as" does not consider (2f - 1f - 4) a constant expression for movw.
    718       "1:\n"
    719       "add r1, pc\n"
    720       "ldr r1, [r1, #0]\n" +
    721       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    722       ".align 2, 0\n"
    723       "2:\n"
    724       ".word 0x12345678\n";
    725   DriverStr(expected, "LoadLiteralMax64KiB");
    726 
    727   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
    728             __ GetAdjustedPosition(label.Position()));
    729 }
    730 
    731 TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax64KiB) {
    732   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    733   __ LoadLiteral(arm::R1, literal);
    734   Label label;
    735   __ Bind(&label);
    736   constexpr size_t kLdrR0R0Count = (1u << 15) - 1u;
    737   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    738     __ ldr(arm::R0, arm::Address(arm::R0));
    739   }
    740 
    741   std::string expected =
    742       "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n"
    743       "1:\n"
    744       "add r1, pc\n"
    745       "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" +
    746       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    747       ".align 2, 0\n"
    748       "2:\n"
    749       ".word 0x12345678\n";
    750   DriverStr(expected, "LoadLiteralBeyondMax64KiB");
    751 
    752   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u,
    753             __ GetAdjustedPosition(label.Position()));
    754 }
    755 
    756 TEST_F(AssemblerThumb2Test, LoadLiteralMax1MiB) {
    757   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    758   __ LoadLiteral(arm::R1, literal);
    759   Label label;
    760   __ Bind(&label);
    761   constexpr size_t kLdrR0R0Count = (1u << 19) - 3u;
    762   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    763     __ ldr(arm::R0, arm::Address(arm::R0));
    764   }
    765 
    766   std::string expected =
    767       "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n"
    768       "1:\n"
    769       "add r1, pc\n"
    770       "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" +
    771       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    772       ".align 2, 0\n"
    773       "2:\n"
    774       ".word 0x12345678\n";
    775   DriverStr(expected, "LoadLiteralMax1MiB");
    776 
    777   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u,
    778             __ GetAdjustedPosition(label.Position()));
    779 }
    780 
    781 TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1MiB) {
    782   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    783   __ LoadLiteral(arm::R1, literal);
    784   Label label;
    785   __ Bind(&label);
    786   constexpr size_t kLdrR0R0Count = (1u << 19) - 2u;
    787   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    788     __ ldr(arm::R0, arm::Address(arm::R0));
    789   }
    790 
    791   std::string expected =
    792       // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
    793       "movw r1, #(0x100000 & 0xffff)\n"
    794       // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
    795       "movt r1, #(0x100000 >> 16)\n"
    796       "1:\n"
    797       "add r1, pc\n"
    798       "ldr.w r1, [r1, #0]\n" +
    799       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    800       ".align 2, 0\n"
    801       "2:\n"
    802       ".word 0x12345678\n";
    803   DriverStr(expected, "LoadLiteralBeyondMax1MiB");
    804 
    805   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u,
    806             __ GetAdjustedPosition(label.Position()));
    807 }
    808 
    809 TEST_F(AssemblerThumb2Test, LoadLiteralFar) {
    810   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    811   __ LoadLiteral(arm::R1, literal);
    812   Label label;
    813   __ Bind(&label);
    814   constexpr size_t kLdrR0R0Count = (1u << 19) - 2u + 0x1234;
    815   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    816     __ ldr(arm::R0, arm::Address(arm::R0));
    817   }
    818 
    819   std::string expected =
    820       // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
    821       "movw r1, #((0x100000 + 2 * 0x1234) & 0xffff)\n"
    822       // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
    823       "movt r1, #((0x100000 + 2 * 0x1234) >> 16)\n"
    824       "1:\n"
    825       "add r1, pc\n"
    826       "ldr.w r1, [r1, #0]\n" +
    827       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    828       ".align 2, 0\n"
    829       "2:\n"
    830       ".word 0x12345678\n";
    831   DriverStr(expected, "LoadLiteralFar");
    832 
    833   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u,
    834             __ GetAdjustedPosition(label.Position()));
    835 }
    836 
    837 TEST_F(AssemblerThumb2Test, LoadLiteralWideMax1KiB) {
    838   arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
    839   __ LoadLiteral(arm::R1, arm::R3, literal);
    840   Label label;
    841   __ Bind(&label);
    842   constexpr size_t kLdrR0R0Count = 510;
    843   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    844     __ ldr(arm::R0, arm::Address(arm::R0));
    845   }
    846 
    847   std::string expected =
    848       "1:\n"
    849       "ldrd r1, r3, [pc, #((2f - 1b - 2) & ~2)]\n" +
    850       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    851       ".align 2, 0\n"
    852       "2:\n"
    853       ".word 0x87654321\n"
    854       ".word 0x12345678\n";
    855   DriverStr(expected, "LoadLiteralWideMax1KiB");
    856 
    857   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u,
    858             __ GetAdjustedPosition(label.Position()));
    859 }
    860 
    861 TEST_F(AssemblerThumb2Test, LoadLiteralWideBeyondMax1KiB) {
    862   arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
    863   __ LoadLiteral(arm::R1, arm::R3, literal);
    864   Label label;
    865   __ Bind(&label);
    866   constexpr size_t kLdrR0R0Count = 511;
    867   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    868     __ ldr(arm::R0, arm::Address(arm::R0));
    869   }
    870 
    871   std::string expected =
    872       "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n"
    873       "1:\n"
    874       "add ip, pc\n"
    875       "ldrd r1, r3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" +
    876       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    877       ".align 2, 0\n"
    878       "2:\n"
    879       ".word 0x87654321\n"
    880       ".word 0x12345678\n";
    881   DriverStr(expected, "LoadLiteralWideBeyondMax1KiB");
    882 
    883   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
    884             __ GetAdjustedPosition(label.Position()));
    885 }
    886 
    887 TEST_F(AssemblerThumb2Test, LoadLiteralSingleMax256KiB) {
    888   // The literal size must match but the type doesn't, so use an int32_t rather than float.
    889   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
    890   __ LoadLiteral(arm::S3, literal);
    891   Label label;
    892   __ Bind(&label);
    893   constexpr size_t kLdrR0R0Count = (1 << 17) - 3u;
    894   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    895     __ ldr(arm::R0, arm::Address(arm::R0));
    896   }
    897 
    898   std::string expected =
    899       "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n"
    900       "1:\n"
    901       "add ip, pc\n"
    902       "vldr s3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" +
    903       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    904       ".align 2, 0\n"
    905       "2:\n"
    906       ".word 0x12345678\n";
    907   DriverStr(expected, "LoadLiteralSingleMax256KiB");
    908 
    909   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
    910             __ GetAdjustedPosition(label.Position()));
    911 }
    912 
    913 TEST_F(AssemblerThumb2Test, LoadLiteralDoubleBeyondMax256KiB) {
    914   // The literal size must match but the type doesn't, so use an int64_t rather than double.
    915   arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
    916   __ LoadLiteral(arm::D3, literal);
    917   Label label;
    918   __ Bind(&label);
    919   constexpr size_t kLdrR0R0Count = (1 << 17) - 2u;
    920   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    921     __ ldr(arm::R0, arm::Address(arm::R0));
    922   }
    923 
    924   std::string expected =
    925       // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
    926       "movw ip, #(0x40000 & 0xffff)\n"
    927       // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
    928       "movt ip, #(0x40000 >> 16)\n"
    929       "1:\n"
    930       "add ip, pc\n"
    931       "vldr d3, [ip, #0]\n" +
    932       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    933       ".align 2, 0\n"
    934       "2:\n"
    935       ".word 0x87654321\n"
    936       ".word 0x12345678\n";
    937   DriverStr(expected, "LoadLiteralDoubleBeyondMax256KiB");
    938 
    939   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u,
    940             __ GetAdjustedPosition(label.Position()));
    941 }
    942 
    943 TEST_F(AssemblerThumb2Test, LoadLiteralDoubleFar) {
    944   // The literal size must match but the type doesn't, so use an int64_t rather than double.
    945   arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
    946   __ LoadLiteral(arm::D3, literal);
    947   Label label;
    948   __ Bind(&label);
    949   constexpr size_t kLdrR0R0Count = (1 << 17) - 2u + 0x1234;
    950   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
    951     __ ldr(arm::R0, arm::Address(arm::R0));
    952   }
    953 
    954   std::string expected =
    955       // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
    956       "movw ip, #((0x40000 + 2 * 0x1234) & 0xffff)\n"
    957       // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
    958       "movt ip, #((0x40000 + 2 * 0x1234) >> 16)\n"
    959       "1:\n"
    960       "add ip, pc\n"
    961       "vldr d3, [ip, #0]\n" +
    962       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
    963       ".align 2, 0\n"
    964       "2:\n"
    965       ".word 0x87654321\n"
    966       ".word 0x12345678\n";
    967   DriverStr(expected, "LoadLiteralDoubleFar");
    968 
    969   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u,
    970             __ GetAdjustedPosition(label.Position()));
    971 }
    972 
    973 TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiBDueToAlignmentOnSecondPass) {
    974   // First part: as TwoCbzBeyondMaxOffset but add one 16-bit instruction to the end,
    975   // so that the size is not Aligned<4>(.). On the first pass, the assembler resizes
    976   // the second CBZ because it's out of range, then it will resize the first CBZ
    977   // which has been pushed out of range. Thus, after the first pass, the code size
    978   // will appear Aligned<4>(.) but the final size will not be.
    979   Label label0, label1, label2;
    980   __ cbz(arm::R0, &label1);
    981   constexpr size_t kLdrR0R0Count1 = 63;
    982   for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
    983     __ ldr(arm::R0, arm::Address(arm::R0));
    984   }
    985   __ Bind(&label0);
    986   __ cbz(arm::R0, &label2);
    987   __ Bind(&label1);
    988   constexpr size_t kLdrR0R0Count2 = 65;
    989   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
    990     __ ldr(arm::R0, arm::Address(arm::R0));
    991   }
    992   __ Bind(&label2);
    993   __ ldr(arm::R0, arm::Address(arm::R0));
    994 
    995   std::string expected_part1 =
    996       "cmp r0, #0\n"              // cbz r0, label1
    997       "beq.n 1f\n" +
    998       RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
    999       "0:\n"
   1000       "cmp r0, #0\n"              // cbz r0, label2
   1001       "beq.n 2f\n"
   1002       "1:\n" +
   1003       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
   1004       "2:\n"                      // Here the offset is Aligned<4>(.).
   1005       "ldr r0, [r0]\n";           // Make the first part
   1006 
   1007   // Second part: as LoadLiteralMax1KiB with the caveat that the offset of the load
   1008   // literal will not be Aligned<4>(.) but it will appear to be when we process the
   1009   // instruction during the first pass, so the literal will need a padding and it
   1010   // will push the literal out of range, so we shall end up with "ldr.w".
   1011   arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
   1012   __ LoadLiteral(arm::R0, literal);
   1013   Label label;
   1014   __ Bind(&label);
   1015   constexpr size_t kLdrR0R0Count = 511;
   1016   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1017     __ ldr(arm::R0, arm::Address(arm::R0));
   1018   }
   1019 
   1020   std::string expected =
   1021       expected_part1 +
   1022       "1:\n"
   1023       "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
   1024       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1025       ".align 2, 0\n"
   1026       "2:\n"
   1027       ".word 0x12345678\n";
   1028   DriverStr(expected, "LoadLiteralMax1KiB");
   1029 
   1030   EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
   1031             __ GetAdjustedPosition(label.Position()));
   1032 }
   1033 
   1034 TEST_F(AssemblerThumb2Test, BindTrackedLabel) {
   1035   Label non_tracked, tracked, branch_target;
   1036 
   1037   // A few dummy loads on entry.
   1038   constexpr size_t kLdrR0R0Count = 5;
   1039   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1040     __ ldr(arm::R0, arm::Address(arm::R0));
   1041   }
   1042 
   1043   // A branch that will need to be fixed up.
   1044   __ cbz(arm::R0, &branch_target);
   1045 
   1046   // Some more dummy loads.
   1047   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1048     __ ldr(arm::R0, arm::Address(arm::R0));
   1049   }
   1050 
   1051   // Now insert tracked and untracked label.
   1052   __ Bind(&non_tracked);
   1053   __ BindTrackedLabel(&tracked);
   1054 
   1055   // A lot of dummy loads, to ensure the branch needs resizing.
   1056   constexpr size_t kLdrR0R0CountLong = 60;
   1057   for (size_t i = 0; i != kLdrR0R0CountLong; ++i) {
   1058     __ ldr(arm::R0, arm::Address(arm::R0));
   1059   }
   1060 
   1061   // Bind the branch target.
   1062   __ Bind(&branch_target);
   1063 
   1064   // One more load.
   1065   __ ldr(arm::R0, arm::Address(arm::R0));
   1066 
   1067   std::string expected =
   1068       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1069       "cmp r0, #0\n"                                                       // cbz r0, 1f
   1070       "beq.n 1f\n" +
   1071       RepeatInsn(kLdrR0R0Count + kLdrR0R0CountLong, "ldr r0, [r0]\n") +
   1072       "1:\n"
   1073       "ldr r0, [r0]\n";
   1074   DriverStr(expected, "BindTrackedLabel");
   1075 
   1076   // Expectation is that the tracked label should have moved.
   1077   EXPECT_LT(non_tracked.Position(), tracked.Position());
   1078 }
   1079 
   1080 TEST_F(AssemblerThumb2Test, JumpTable) {
   1081   // The jump table. Use three labels.
   1082   Label label1, label2, label3;
   1083   std::vector<Label*> labels({ &label1, &label2, &label3 });
   1084 
   1085   // A few dummy loads on entry, interspersed with 2 labels.
   1086   constexpr size_t kLdrR0R0Count = 5;
   1087   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1088     __ ldr(arm::R0, arm::Address(arm::R0));
   1089   }
   1090   __ BindTrackedLabel(&label1);
   1091   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1092     __ ldr(arm::R0, arm::Address(arm::R0));
   1093   }
   1094   __ BindTrackedLabel(&label2);
   1095   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1096     __ ldr(arm::R0, arm::Address(arm::R0));
   1097   }
   1098 
   1099   // Create the jump table, emit the base load.
   1100   arm::JumpTable* jump_table = __ CreateJumpTable(std::move(labels), arm::R1);
   1101 
   1102   // Dummy computation, stand-in for the address. We're only testing the jump table here, not how
   1103   // it's being used.
   1104   __ ldr(arm::R0, arm::Address(arm::R0));
   1105 
   1106   // Emit the jump
   1107   __ EmitJumpTableDispatch(jump_table, arm::R1);
   1108 
   1109   // Some more dummy instructions.
   1110   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1111     __ ldr(arm::R0, arm::Address(arm::R0));
   1112   }
   1113   __ BindTrackedLabel(&label3);
   1114   for (size_t i = 0; i != kLdrR0R0Count; ++i) {          // Note: odd so there's no alignment
   1115     __ ldr(arm::R0, arm::Address(arm::R0));              //       necessary, as gcc as emits nops,
   1116   }                                                      //       whereas we emit 0 != nop.
   1117 
   1118   static_assert((kLdrR0R0Count + 3) * 2 < 1 * KB, "Too much offset");
   1119 
   1120   std::string expected =
   1121       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1122       ".L1:\n" +
   1123       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1124       ".L2:\n" +
   1125       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1126       "adr r1, .Ljump_table\n"
   1127       "ldr r0, [r0]\n"
   1128       ".Lbase:\n"
   1129       "add pc, r1\n" +
   1130       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1131       ".L3:\n" +
   1132       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1133       ".align 2\n"
   1134       ".Ljump_table:\n"
   1135       ".4byte (.L1 - .Lbase - 4)\n"
   1136       ".4byte (.L2 - .Lbase - 4)\n"
   1137       ".4byte (.L3 - .Lbase - 4)\n";
   1138   DriverStr(expected, "JumpTable");
   1139 }
   1140 
   1141 // Test for >1K fixup.
   1142 TEST_F(AssemblerThumb2Test, JumpTable4K) {
   1143   // The jump table. Use three labels.
   1144   Label label1, label2, label3;
   1145   std::vector<Label*> labels({ &label1, &label2, &label3 });
   1146 
   1147   // A few dummy loads on entry, interspersed with 2 labels.
   1148   constexpr size_t kLdrR0R0Count = 5;
   1149   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1150     __ ldr(arm::R0, arm::Address(arm::R0));
   1151   }
   1152   __ BindTrackedLabel(&label1);
   1153   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1154     __ ldr(arm::R0, arm::Address(arm::R0));
   1155   }
   1156   __ BindTrackedLabel(&label2);
   1157   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1158     __ ldr(arm::R0, arm::Address(arm::R0));
   1159   }
   1160 
   1161   // Create the jump table, emit the base load.
   1162   arm::JumpTable* jump_table = __ CreateJumpTable(std::move(labels), arm::R1);
   1163 
   1164   // Dummy computation, stand-in for the address. We're only testing the jump table here, not how
   1165   // it's being used.
   1166   __ ldr(arm::R0, arm::Address(arm::R0));
   1167 
   1168   // Emit the jump
   1169   __ EmitJumpTableDispatch(jump_table, arm::R1);
   1170 
   1171   // Some more dummy instructions.
   1172   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1173     __ ldr(arm::R0, arm::Address(arm::R0));
   1174   }
   1175   __ BindTrackedLabel(&label3);
   1176   constexpr size_t kLdrR0R0Count2 = 600;               // Note: even so there's no alignment
   1177   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {       //       necessary, as gcc as emits nops,
   1178     __ ldr(arm::R0, arm::Address(arm::R0));            //       whereas we emit 0 != nop.
   1179   }
   1180 
   1181   static_assert((kLdrR0R0Count + kLdrR0R0Count2 + 3) * 2 > 1 * KB, "Not enough offset");
   1182   static_assert((kLdrR0R0Count + kLdrR0R0Count2 + 3) * 2 < 4 * KB, "Too much offset");
   1183 
   1184   std::string expected =
   1185       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1186       ".L1:\n" +
   1187       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1188       ".L2:\n" +
   1189       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1190       "adr r1, .Ljump_table\n"
   1191       "ldr r0, [r0]\n"
   1192       ".Lbase:\n"
   1193       "add pc, r1\n" +
   1194       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1195       ".L3:\n" +
   1196       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
   1197       ".align 2\n"
   1198       ".Ljump_table:\n"
   1199       ".4byte (.L1 - .Lbase - 4)\n"
   1200       ".4byte (.L2 - .Lbase - 4)\n"
   1201       ".4byte (.L3 - .Lbase - 4)\n";
   1202   DriverStr(expected, "JumpTable4K");
   1203 }
   1204 
   1205 // Test for >4K fixup.
   1206 TEST_F(AssemblerThumb2Test, JumpTable64K) {
   1207   // The jump table. Use three labels.
   1208   Label label1, label2, label3;
   1209   std::vector<Label*> labels({ &label1, &label2, &label3 });
   1210 
   1211   // A few dummy loads on entry, interspersed with 2 labels.
   1212   constexpr size_t kLdrR0R0Count = 5;
   1213   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1214     __ ldr(arm::R0, arm::Address(arm::R0));
   1215   }
   1216   __ BindTrackedLabel(&label1);
   1217   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1218     __ ldr(arm::R0, arm::Address(arm::R0));
   1219   }
   1220   __ BindTrackedLabel(&label2);
   1221   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1222     __ ldr(arm::R0, arm::Address(arm::R0));
   1223   }
   1224 
   1225   // Create the jump table, emit the base load.
   1226   arm::JumpTable* jump_table = __ CreateJumpTable(std::move(labels), arm::R1);
   1227 
   1228   // Dummy computation, stand-in for the address. We're only testing the jump table here, not how
   1229   // it's being used.
   1230   __ ldr(arm::R0, arm::Address(arm::R0));
   1231 
   1232   // Emit the jump
   1233   __ EmitJumpTableDispatch(jump_table, arm::R1);
   1234 
   1235   // Some more dummy instructions.
   1236   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1237     __ ldr(arm::R0, arm::Address(arm::R0));
   1238   }
   1239   __ BindTrackedLabel(&label3);
   1240   constexpr size_t kLdrR0R0Count2 = 2601;              // Note: odd so there's no alignment
   1241   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {       //       necessary, as gcc as emits nops,
   1242     __ ldr(arm::R0, arm::Address(arm::R0));            //       whereas we emit 0 != nop.
   1243   }
   1244 
   1245   static_assert((kLdrR0R0Count + kLdrR0R0Count2 + 3) * 2 > 4 * KB, "Not enough offset");
   1246   static_assert((kLdrR0R0Count + kLdrR0R0Count2 + 3) * 2 < 64 * KB, "Too much offset");
   1247 
   1248   std::string expected =
   1249       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1250       ".L1:\n" +
   1251       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1252       ".L2:\n" +
   1253       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1254       // ~ adr r1, .Ljump_table, gcc as can't seem to fix up a large offset itself.
   1255       // (Note: have to use constants, as labels aren't accepted.
   1256       "movw r1, #(((3 + " + StringPrintf("%zu", kLdrR0R0Count + kLdrR0R0Count2) +
   1257           ") * 2 - 4) & 0xFFFF)\n"
   1258       "add r1, pc\n"
   1259       "ldr r0, [r0]\n"
   1260       ".Lbase:\n"
   1261       "add pc, r1\n" +
   1262       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1263       ".L3:\n" +
   1264       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
   1265       ".align 2\n"
   1266       ".Ljump_table:\n"
   1267       ".4byte (.L1 - .Lbase - 4)\n"
   1268       ".4byte (.L2 - .Lbase - 4)\n"
   1269       ".4byte (.L3 - .Lbase - 4)\n";
   1270   DriverStr(expected, "JumpTable64K");
   1271 }
   1272 
   1273 // Test for >64K fixup.
   1274 TEST_F(AssemblerThumb2Test, JumpTableFar) {
   1275   // The jump table. Use three labels.
   1276   Label label1, label2, label3;
   1277   std::vector<Label*> labels({ &label1, &label2, &label3 });
   1278 
   1279   // A few dummy loads on entry, interspersed with 2 labels.
   1280   constexpr size_t kLdrR0R0Count = 5;
   1281   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1282     __ ldr(arm::R0, arm::Address(arm::R0));
   1283   }
   1284   __ BindTrackedLabel(&label1);
   1285   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1286     __ ldr(arm::R0, arm::Address(arm::R0));
   1287   }
   1288   __ BindTrackedLabel(&label2);
   1289   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1290     __ ldr(arm::R0, arm::Address(arm::R0));
   1291   }
   1292 
   1293   // Create the jump table, emit the base load.
   1294   arm::JumpTable* jump_table = __ CreateJumpTable(std::move(labels), arm::R1);
   1295 
   1296   // Dummy computation, stand-in for the address. We're only testing the jump table here, not how
   1297   // it's being used.
   1298   __ ldr(arm::R0, arm::Address(arm::R0));
   1299 
   1300   // Emit the jump
   1301   __ EmitJumpTableDispatch(jump_table, arm::R1);
   1302 
   1303   // Some more dummy instructions.
   1304   for (size_t i = 0; i != kLdrR0R0Count; ++i) {
   1305     __ ldr(arm::R0, arm::Address(arm::R0));
   1306   }
   1307   __ BindTrackedLabel(&label3);
   1308   constexpr size_t kLdrR0R0Count2 = 70001;             // Note: odd so there's no alignment
   1309   for (size_t i = 0; i != kLdrR0R0Count2; ++i) {       //       necessary, as gcc as emits nops,
   1310     __ ldr(arm::R0, arm::Address(arm::R0));            //       whereas we emit 0 != nop.
   1311   }
   1312 
   1313   static_assert((kLdrR0R0Count + kLdrR0R0Count2 + 3) * 2 > 64 * KB, "Not enough offset");
   1314 
   1315   std::string expected =
   1316       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1317       ".L1:\n" +
   1318       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1319       ".L2:\n" +
   1320       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1321       // ~ adr r1, .Ljump_table, gcc as can't seem to fix up a large offset itself.
   1322       // (Note: have to use constants, as labels aren't accepted.
   1323       "movw r1, #(((3 + " + StringPrintf("%zu", kLdrR0R0Count + kLdrR0R0Count2) +
   1324           ") * 2 - 4) & 0xFFFF)\n"
   1325       "movt r1, #(((3 + " + StringPrintf("%zu", kLdrR0R0Count + kLdrR0R0Count2) +
   1326           ") * 2 - 4) >> 16)\n"
   1327       ".Lhelp:"
   1328       "add r1, pc\n"
   1329       "ldr r0, [r0]\n"
   1330       ".Lbase:\n"
   1331       "add pc, r1\n" +
   1332       RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
   1333       ".L3:\n" +
   1334       RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
   1335       ".align 2\n"
   1336       ".Ljump_table:\n"
   1337       ".4byte (.L1 - .Lbase - 4)\n"
   1338       ".4byte (.L2 - .Lbase - 4)\n"
   1339       ".4byte (.L3 - .Lbase - 4)\n";
   1340   DriverStr(expected, "JumpTableFar");
   1341 }
   1342 
   1343 TEST_F(AssemblerThumb2Test, Clz) {
   1344   __ clz(arm::R0, arm::R1);
   1345 
   1346   const char* expected = "clz r0, r1\n";
   1347 
   1348   DriverStr(expected, "clz");
   1349 }
   1350 
   1351 TEST_F(AssemblerThumb2Test, rbit) {
   1352   __ rbit(arm::R1, arm::R0);
   1353 
   1354   const char* expected = "rbit r1, r0\n";
   1355 
   1356   DriverStr(expected, "rbit");
   1357 }
   1358 
   1359 TEST_F(AssemblerThumb2Test, rev) {
   1360   __ rev(arm::R1, arm::R0);
   1361 
   1362   const char* expected = "rev r1, r0\n";
   1363 
   1364   DriverStr(expected, "rev");
   1365 }
   1366 
   1367 TEST_F(AssemblerThumb2Test, rev16) {
   1368   __ rev16(arm::R1, arm::R0);
   1369 
   1370   const char* expected = "rev16 r1, r0\n";
   1371 
   1372   DriverStr(expected, "rev16");
   1373 }
   1374 
   1375 TEST_F(AssemblerThumb2Test, revsh) {
   1376   __ revsh(arm::R1, arm::R0);
   1377 
   1378   const char* expected = "revsh r1, r0\n";
   1379 
   1380   DriverStr(expected, "revsh");
   1381 }
   1382 
   1383 }  // namespace art
   1384