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