• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
GetArchitectureString()29   std::string GetArchitectureString() OVERRIDE {
30     return "arm";
31   }
32 
GetAssemblerParameters()33   std::string GetAssemblerParameters() OVERRIDE {
34     return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon -mthumb";
35   }
36 
GetAssemblyHeader()37   const char* GetAssemblyHeader() OVERRIDE {
38     return kThumb2AssemblyHeader;
39   }
40 
GetDisassembleParameters()41   std::string GetDisassembleParameters() OVERRIDE {
42     return " -D -bbinary -marm --disassembler-options=force-thumb --no-show-raw-insn";
43   }
44 
SetUpHelpers()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 
TearDown()69   void TearDown() OVERRIDE {
70     AssemblerTest::TearDown();
71     STLDeleteElements(&registers_);
72   }
73 
GetRegisters()74   std::vector<arm::Register*> GetRegisters() OVERRIDE {
75     return registers_;
76   }
77 
CreateImmediate(int64_t imm_value)78   uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
79     return imm_value;
80   }
81 
RepeatInsn(size_t count,const std::string & insn)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 
TEST_F(AssemblerThumb2Test,Toolchain)96 TEST_F(AssemblerThumb2Test, Toolchain) {
97   EXPECT_TRUE(CheckTools());
98 }
99 
100 #define __ GetAssembler()->
101 
TEST_F(AssemblerThumb2Test,Sbfx)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 
TEST_F(AssemblerThumb2Test,Ubfx)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 
TEST_F(AssemblerThumb2Test,Vmstat)174 TEST_F(AssemblerThumb2Test, Vmstat) {
175   __ vmstat();
176 
177   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
178 
179   DriverStr(expected, "vmrs");
180 }
181 
TEST_F(AssemblerThumb2Test,ldrexd)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 
TEST_F(AssemblerThumb2Test,strexd)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 
TEST_F(AssemblerThumb2Test,LdrdStrd)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 
TEST_F(AssemblerThumb2Test,eor)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 
TEST_F(AssemblerThumb2Test,sub)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 
TEST_F(AssemblerThumb2Test,add)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 
TEST_F(AssemblerThumb2Test,umull)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 
TEST_F(AssemblerThumb2Test,smull)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 
TEST_F(AssemblerThumb2Test,StoreWordToThumbOffset)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 
TEST_F(AssemblerThumb2Test,StoreWordToNonThumbOffset)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 
TEST_F(AssemblerThumb2Test,StoreWordPairToThumbOffset)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 
TEST_F(AssemblerThumb2Test,StoreWordPairToNonThumbOffset)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 
TEST_F(AssemblerThumb2Test,DistantBackBranch)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 
TEST_F(AssemblerThumb2Test,TwoCbzMaxOffset)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 
TEST_F(AssemblerThumb2Test,TwoCbzBeyondMaxOffset)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 
TEST_F(AssemblerThumb2Test,TwoCbzSecondAtMaxB16Offset)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 
TEST_F(AssemblerThumb2Test,TwoCbzSecondBeyondMaxB16Offset)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 
TEST_F(AssemblerThumb2Test,TwoCbzFirstAtMaxB16Offset)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 
TEST_F(AssemblerThumb2Test,TwoCbzFirstBeyondMaxB16Offset)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 
TEST_F(AssemblerThumb2Test,LoadLiteralMax1KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralBeyondMax1KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralMax4KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralBeyondMax4KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralMax64KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralBeyondMax64KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralMax1MiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralBeyondMax1MiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralFar)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 
TEST_F(AssemblerThumb2Test,LoadLiteralWideMax1KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralWideBeyondMax1KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralSingleMax256KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralDoubleBeyondMax256KiB)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 
TEST_F(AssemblerThumb2Test,LoadLiteralDoubleFar)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 
TEST_F(AssemblerThumb2Test,LoadLiteralBeyondMax1KiBDueToAlignmentOnSecondPass)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 
TEST_F(AssemblerThumb2Test,BindTrackedLabel)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 
TEST_F(AssemblerThumb2Test,JumpTable)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.
TEST_F(AssemblerThumb2Test,JumpTable4K)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.
TEST_F(AssemblerThumb2Test,JumpTable64K)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.
TEST_F(AssemblerThumb2Test,JumpTableFar)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 
TEST_F(AssemblerThumb2Test,Clz)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 
TEST_F(AssemblerThumb2Test,rbit)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 
TEST_F(AssemblerThumb2Test,rev)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 
TEST_F(AssemblerThumb2Test,rev16)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 
TEST_F(AssemblerThumb2Test,revsh)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