blob: 68b7931a0c8cd6e9d484aef061c313f0cb3e932a [file] [log] [blame]
Roland Levillain1a28fc42014-11-13 18:03:06 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_thumb2.h"
18
19#include "base/stl_util.h"
20#include "utils/assembler_test.h"
21
22namespace art {
23
24class AssemblerThumb2Test : public AssemblerTest<arm::Thumb2Assembler,
Andreas Gampe851df202014-11-12 14:05:46 -080025 arm::Register, arm::SRegister,
26 uint32_t> {
Roland Levillain1a28fc42014-11-13 18:03:06 +000027 protected:
28 std::string GetArchitectureString() OVERRIDE {
29 return "arm";
30 }
31
32 std::string GetAssemblerParameters() OVERRIDE {
Andreas Gampe513ea0c2015-02-02 13:17:52 -080033 return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon -mthumb";
34 }
35
36 const char* GetAssemblyHeader() OVERRIDE {
37 return kThumb2AssemblyHeader;
Roland Levillain1a28fc42014-11-13 18:03:06 +000038 }
39
40 std::string GetDisassembleParameters() OVERRIDE {
Andreas Gampe513ea0c2015-02-02 13:17:52 -080041 return " -D -bbinary -marm --disassembler-options=force-thumb --no-show-raw-insn";
Roland Levillain1a28fc42014-11-13 18:03:06 +000042 }
43
44 void SetUpHelpers() OVERRIDE {
45 if (registers_.size() == 0) {
46 registers_.insert(end(registers_),
47 { // NOLINT(whitespace/braces)
48 new arm::Register(arm::R0),
49 new arm::Register(arm::R1),
50 new arm::Register(arm::R2),
51 new arm::Register(arm::R3),
52 new arm::Register(arm::R4),
53 new arm::Register(arm::R5),
54 new arm::Register(arm::R6),
55 new arm::Register(arm::R7),
56 new arm::Register(arm::R8),
57 new arm::Register(arm::R9),
58 new arm::Register(arm::R10),
59 new arm::Register(arm::R11),
60 new arm::Register(arm::R12),
61 new arm::Register(arm::R13),
62 new arm::Register(arm::R14),
63 new arm::Register(arm::R15)
64 });
65 }
66 }
67
68 void TearDown() OVERRIDE {
69 AssemblerTest::TearDown();
70 STLDeleteElements(&registers_);
71 }
72
73 std::vector<arm::Register*> GetRegisters() OVERRIDE {
74 return registers_;
75 }
76
77 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
78 return imm_value;
79 }
80
Vladimir Markocf93a5c2015-06-16 11:33:24 +000081 std::string RepeatInsn(size_t count, const std::string& insn) {
82 std::string result;
83 for (; count != 0u; --count) {
84 result += insn;
85 }
86 return result;
87 }
88
Roland Levillain1a28fc42014-11-13 18:03:06 +000089 private:
90 std::vector<arm::Register*> registers_;
Andreas Gampe513ea0c2015-02-02 13:17:52 -080091
92 static constexpr const char* kThumb2AssemblyHeader = ".syntax unified\n.thumb\n";
Roland Levillain1a28fc42014-11-13 18:03:06 +000093};
94
Roland Levillain1a28fc42014-11-13 18:03:06 +000095TEST_F(AssemblerThumb2Test, Toolchain) {
96 EXPECT_TRUE(CheckTools());
97}
98
Zheng Xuc6667102015-05-15 16:08:45 +080099#define __ GetAssembler()->
Roland Levillain1a28fc42014-11-13 18:03:06 +0000100
101TEST_F(AssemblerThumb2Test, Sbfx) {
Zheng Xuc6667102015-05-15 16:08:45 +0800102 __ sbfx(arm::R0, arm::R1, 0, 1);
103 __ sbfx(arm::R0, arm::R1, 0, 8);
104 __ sbfx(arm::R0, arm::R1, 0, 16);
105 __ sbfx(arm::R0, arm::R1, 0, 32);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000106
Zheng Xuc6667102015-05-15 16:08:45 +0800107 __ sbfx(arm::R0, arm::R1, 8, 1);
108 __ sbfx(arm::R0, arm::R1, 8, 8);
109 __ sbfx(arm::R0, arm::R1, 8, 16);
110 __ sbfx(arm::R0, arm::R1, 8, 24);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000111
Zheng Xuc6667102015-05-15 16:08:45 +0800112 __ sbfx(arm::R0, arm::R1, 16, 1);
113 __ sbfx(arm::R0, arm::R1, 16, 8);
114 __ sbfx(arm::R0, arm::R1, 16, 16);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000115
Zheng Xuc6667102015-05-15 16:08:45 +0800116 __ sbfx(arm::R0, arm::R1, 31, 1);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000117
118 const char* expected =
119 "sbfx r0, r1, #0, #1\n"
120 "sbfx r0, r1, #0, #8\n"
121 "sbfx r0, r1, #0, #16\n"
122 "sbfx r0, r1, #0, #32\n"
123
124 "sbfx r0, r1, #8, #1\n"
125 "sbfx r0, r1, #8, #8\n"
126 "sbfx r0, r1, #8, #16\n"
127 "sbfx r0, r1, #8, #24\n"
128
129 "sbfx r0, r1, #16, #1\n"
130 "sbfx r0, r1, #16, #8\n"
131 "sbfx r0, r1, #16, #16\n"
132
133 "sbfx r0, r1, #31, #1\n";
134 DriverStr(expected, "sbfx");
135}
136
Roland Levillain981e4542014-11-14 11:47:14 +0000137TEST_F(AssemblerThumb2Test, Ubfx) {
Zheng Xuc6667102015-05-15 16:08:45 +0800138 __ ubfx(arm::R0, arm::R1, 0, 1);
139 __ ubfx(arm::R0, arm::R1, 0, 8);
140 __ ubfx(arm::R0, arm::R1, 0, 16);
141 __ ubfx(arm::R0, arm::R1, 0, 32);
Roland Levillain981e4542014-11-14 11:47:14 +0000142
Zheng Xuc6667102015-05-15 16:08:45 +0800143 __ ubfx(arm::R0, arm::R1, 8, 1);
144 __ ubfx(arm::R0, arm::R1, 8, 8);
145 __ ubfx(arm::R0, arm::R1, 8, 16);
146 __ ubfx(arm::R0, arm::R1, 8, 24);
Roland Levillain981e4542014-11-14 11:47:14 +0000147
Zheng Xuc6667102015-05-15 16:08:45 +0800148 __ ubfx(arm::R0, arm::R1, 16, 1);
149 __ ubfx(arm::R0, arm::R1, 16, 8);
150 __ ubfx(arm::R0, arm::R1, 16, 16);
Roland Levillain981e4542014-11-14 11:47:14 +0000151
Zheng Xuc6667102015-05-15 16:08:45 +0800152 __ ubfx(arm::R0, arm::R1, 31, 1);
Roland Levillain981e4542014-11-14 11:47:14 +0000153
154 const char* expected =
155 "ubfx r0, r1, #0, #1\n"
156 "ubfx r0, r1, #0, #8\n"
157 "ubfx r0, r1, #0, #16\n"
158 "ubfx r0, r1, #0, #32\n"
159
160 "ubfx r0, r1, #8, #1\n"
161 "ubfx r0, r1, #8, #8\n"
162 "ubfx r0, r1, #8, #16\n"
163 "ubfx r0, r1, #8, #24\n"
164
165 "ubfx r0, r1, #16, #1\n"
166 "ubfx r0, r1, #16, #8\n"
167 "ubfx r0, r1, #16, #16\n"
168
169 "ubfx r0, r1, #31, #1\n";
170 DriverStr(expected, "ubfx");
171}
172
Calin Juravleddb7df22014-11-25 20:56:51 +0000173TEST_F(AssemblerThumb2Test, Vmstat) {
Zheng Xuc6667102015-05-15 16:08:45 +0800174 __ vmstat();
Calin Juravleddb7df22014-11-25 20:56:51 +0000175
176 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
177
178 DriverStr(expected, "vmrs");
179}
180
Calin Juravle52c48962014-12-16 17:02:57 +0000181TEST_F(AssemblerThumb2Test, ldrexd) {
Zheng Xuc6667102015-05-15 16:08:45 +0800182 __ ldrexd(arm::R0, arm::R1, arm::R0);
183 __ ldrexd(arm::R0, arm::R1, arm::R1);
184 __ ldrexd(arm::R0, arm::R1, arm::R2);
185 __ ldrexd(arm::R5, arm::R3, arm::R7);
Calin Juravle52c48962014-12-16 17:02:57 +0000186
187 const char* expected =
188 "ldrexd r0, r1, [r0]\n"
189 "ldrexd r0, r1, [r1]\n"
190 "ldrexd r0, r1, [r2]\n"
191 "ldrexd r5, r3, [r7]\n";
192 DriverStr(expected, "ldrexd");
193}
194
195TEST_F(AssemblerThumb2Test, strexd) {
Zheng Xuc6667102015-05-15 16:08:45 +0800196 __ strexd(arm::R9, arm::R0, arm::R1, arm::R0);
197 __ strexd(arm::R9, arm::R0, arm::R1, arm::R1);
198 __ strexd(arm::R9, arm::R0, arm::R1, arm::R2);
199 __ strexd(arm::R9, arm::R5, arm::R3, arm::R7);
Calin Juravle52c48962014-12-16 17:02:57 +0000200
201 const char* expected =
202 "strexd r9, r0, r1, [r0]\n"
203 "strexd r9, r0, r1, [r1]\n"
204 "strexd r9, r0, r1, [r2]\n"
205 "strexd r9, r5, r3, [r7]\n";
206 DriverStr(expected, "strexd");
207}
208
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -0800209TEST_F(AssemblerThumb2Test, LdrdStrd) {
Zheng Xuc6667102015-05-15 16:08:45 +0800210 __ ldrd(arm::R0, arm::Address(arm::R2, 8));
211 __ ldrd(arm::R0, arm::Address(arm::R12));
212 __ strd(arm::R0, arm::Address(arm::R2, 8));
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -0800213
214 const char* expected =
215 "ldrd r0, r1, [r2, #8]\n"
216 "ldrd r0, r1, [r12]\n"
217 "strd r0, r1, [r2, #8]\n";
218 DriverStr(expected, "ldrdstrd");
219}
220
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800221TEST_F(AssemblerThumb2Test, eor) {
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800222 __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0));
223 __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1));
224 __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0));
225 __ eor(arm::R8, arm::R1, arm::ShifterOperand(arm::R0));
226 __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R8));
227
228 const char* expected =
229 "eors r1, r0\n"
230 "eor r1, r0, r1\n"
231 "eor r1, r8, r0\n"
232 "eor r8, r1, r0\n"
233 "eor r1, r0, r8\n";
234 DriverStr(expected, "abs");
235}
236
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000237TEST_F(AssemblerThumb2Test, sub) {
238 __ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
239 __ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
Zheng Xuc6667102015-05-15 16:08:45 +0800240 __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
241 __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000242
243 const char* expected =
244 "subs r1, r0, #42\n"
Zheng Xuc6667102015-05-15 16:08:45 +0800245 "subw r1, r0, #42\n"
246 "subs r1, r0, r2, asr #31\n"
247 "sub r1, r0, r2, asr #31\n";
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000248 DriverStr(expected, "sub");
249}
250
251TEST_F(AssemblerThumb2Test, add) {
252 __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
253 __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
Zheng Xuc6667102015-05-15 16:08:45 +0800254 __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
255 __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000256
257 const char* expected =
258 "adds r1, r0, #42\n"
Zheng Xuc6667102015-05-15 16:08:45 +0800259 "addw r1, r0, #42\n"
260 "adds r1, r0, r2, asr #31\n"
261 "add r1, r0, r2, asr #31\n";
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000262 DriverStr(expected, "add");
263}
264
Zheng Xuc6667102015-05-15 16:08:45 +0800265TEST_F(AssemblerThumb2Test, umull) {
266 __ umull(arm::R0, arm::R1, arm::R2, arm::R3);
267
268 const char* expected =
269 "umull r0, r1, r2, r3\n";
270 DriverStr(expected, "umull");
271}
272
273TEST_F(AssemblerThumb2Test, smull) {
274 __ smull(arm::R0, arm::R1, arm::R2, arm::R3);
275
276 const char* expected =
277 "smull r0, r1, r2, r3\n";
278 DriverStr(expected, "smull");
279}
280
Roland Levillainc5a5ac62015-04-02 15:49:24 +0100281TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
282 arm::StoreOperandType type = arm::kStoreWord;
283 int32_t offset = 4092;
284 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
285
286 __ StoreToOffset(type, arm::R0, arm::SP, offset);
287 __ StoreToOffset(type, arm::IP, arm::SP, offset);
288 __ StoreToOffset(type, arm::IP, arm::R5, offset);
289
290 const char* expected =
291 "str r0, [sp, #4092]\n"
292 "str ip, [sp, #4092]\n"
293 "str ip, [r5, #4092]\n";
294 DriverStr(expected, "StoreWordToThumbOffset");
295}
296
297TEST_F(AssemblerThumb2Test, StoreWordToNonThumbOffset) {
298 arm::StoreOperandType type = arm::kStoreWord;
299 int32_t offset = 4096;
300 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
301
302 __ StoreToOffset(type, arm::R0, arm::SP, offset);
303 __ StoreToOffset(type, arm::IP, arm::SP, offset);
304 __ StoreToOffset(type, arm::IP, arm::R5, offset);
305
306 const char* expected =
307 "mov ip, #4096\n" // LoadImmediate(ip, 4096)
308 "add ip, ip, sp\n"
309 "str r0, [ip, #0]\n"
310
311 "str r5, [sp, #-4]!\n" // Push(r5)
312 "movw r5, #4100\n" // LoadImmediate(r5, 4096 + kRegisterSize)
313 "add r5, r5, sp\n"
314 "str ip, [r5, #0]\n"
315 "ldr r5, [sp], #4\n" // Pop(r5)
316
317 "str r6, [sp, #-4]!\n" // Push(r6)
318 "mov r6, #4096\n" // LoadImmediate(r6, 4096)
319 "add r6, r6, r5\n"
320 "str ip, [r6, #0]\n"
321 "ldr r6, [sp], #4\n"; // Pop(r6)
322 DriverStr(expected, "StoreWordToNonThumbOffset");
323}
324
Roland Levillain4af147e2015-04-07 13:54:49 +0100325TEST_F(AssemblerThumb2Test, StoreWordPairToThumbOffset) {
326 arm::StoreOperandType type = arm::kStoreWordPair;
327 int32_t offset = 1020;
328 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
329
330 __ StoreToOffset(type, arm::R0, arm::SP, offset);
331 // We cannot use IP (i.e. R12) as first source register, as it would
332 // force us to use SP (i.e. R13) as second source register, which
333 // would have an "unpredictable" effect according to the ARMv7
334 // specification (the T1 encoding describes the result as
335 // UNPREDICTABLE when of the source registers is R13).
336 //
337 // So we use (R11, IP) (e.g. (R11, R12)) as source registers in the
338 // following instructions.
339 __ StoreToOffset(type, arm::R11, arm::SP, offset);
340 __ StoreToOffset(type, arm::R11, arm::R5, offset);
341
342 const char* expected =
343 "strd r0, r1, [sp, #1020]\n"
344 "strd r11, ip, [sp, #1020]\n"
345 "strd r11, ip, [r5, #1020]\n";
346 DriverStr(expected, "StoreWordPairToThumbOffset");
347}
348
349TEST_F(AssemblerThumb2Test, StoreWordPairToNonThumbOffset) {
350 arm::StoreOperandType type = arm::kStoreWordPair;
351 int32_t offset = 1024;
352 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
353
354 __ StoreToOffset(type, arm::R0, arm::SP, offset);
355 // Same comment as in AssemblerThumb2Test.StoreWordPairToThumbOffset
356 // regarding the use of (R11, IP) (e.g. (R11, R12)) as source
357 // registers in the following instructions.
358 __ StoreToOffset(type, arm::R11, arm::SP, offset);
359 __ StoreToOffset(type, arm::R11, arm::R5, offset);
360
361 const char* expected =
362 "mov ip, #1024\n" // LoadImmediate(ip, 1024)
363 "add ip, ip, sp\n"
364 "strd r0, r1, [ip, #0]\n"
365
366 "str r5, [sp, #-4]!\n" // Push(r5)
367 "movw r5, #1028\n" // LoadImmediate(r5, 1024 + kRegisterSize)
368 "add r5, r5, sp\n"
369 "strd r11, ip, [r5, #0]\n"
370 "ldr r5, [sp], #4\n" // Pop(r5)
371
372 "str r6, [sp, #-4]!\n" // Push(r6)
373 "mov r6, #1024\n" // LoadImmediate(r6, 1024)
374 "add r6, r6, r5\n"
375 "strd r11, ip, [r6, #0]\n"
376 "ldr r6, [sp], #4\n"; // Pop(r6)
377 DriverStr(expected, "StoreWordPairToNonThumbOffset");
378}
379
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000380TEST_F(AssemblerThumb2Test, TwoCbzMaxOffset) {
381 Label label0, label1, label2;
382 __ cbz(arm::R0, &label1);
383 constexpr size_t kLdrR0R0Count1 = 63;
384 for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
385 __ ldr(arm::R0, arm::Address(arm::R0));
386 }
387 __ Bind(&label0);
388 __ cbz(arm::R0, &label2);
389 __ Bind(&label1);
390 constexpr size_t kLdrR0R0Count2 = 64;
391 for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
392 __ ldr(arm::R0, arm::Address(arm::R0));
393 }
394 __ Bind(&label2);
395
396 std::string expected =
397 "cbz r0, 1f\n" + // cbz r0, label1
398 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
399 "0:\n"
400 "cbz r0, 2f\n" // cbz r0, label2
401 "1:\n" +
402 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
403 "2:\n";
404 DriverStr(expected, "TwoCbzMaxOffset");
405
406 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u,
407 __ GetAdjustedPosition(label0.Position()));
408 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 0u,
409 __ GetAdjustedPosition(label1.Position()));
410 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 0u,
411 __ GetAdjustedPosition(label2.Position()));
412}
413
414TEST_F(AssemblerThumb2Test, TwoCbzBeyondMaxOffset) {
415 Label label0, label1, label2;
416 __ cbz(arm::R0, &label1);
417 constexpr size_t kLdrR0R0Count1 = 63;
418 for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
419 __ ldr(arm::R0, arm::Address(arm::R0));
420 }
421 __ Bind(&label0);
422 __ cbz(arm::R0, &label2);
423 __ Bind(&label1);
424 constexpr size_t kLdrR0R0Count2 = 65;
425 for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
426 __ ldr(arm::R0, arm::Address(arm::R0));
427 }
428 __ Bind(&label2);
429
430 std::string expected =
431 "cmp r0, #0\n" // cbz r0, label1
432 "beq.n 1f\n" +
433 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
434 "0:\n"
435 "cmp r0, #0\n" // cbz r0, label2
436 "beq.n 2f\n"
437 "1:\n" +
438 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
439 "2:\n";
440 DriverStr(expected, "TwoCbzBeyondMaxOffset");
441
442 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
443 __ GetAdjustedPosition(label0.Position()));
444 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 4u,
445 __ GetAdjustedPosition(label1.Position()));
446 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 4u,
447 __ GetAdjustedPosition(label2.Position()));
448}
449
450TEST_F(AssemblerThumb2Test, TwoCbzSecondAtMaxB16Offset) {
451 Label label0, label1, label2;
452 __ cbz(arm::R0, &label1);
453 constexpr size_t kLdrR0R0Count1 = 62;
454 for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
455 __ ldr(arm::R0, arm::Address(arm::R0));
456 }
457 __ Bind(&label0);
458 __ cbz(arm::R0, &label2);
459 __ Bind(&label1);
460 constexpr size_t kLdrR0R0Count2 = 128;
461 for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
462 __ ldr(arm::R0, arm::Address(arm::R0));
463 }
464 __ Bind(&label2);
465
466 std::string expected =
467 "cbz r0, 1f\n" + // cbz r0, label1
468 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
469 "0:\n"
470 "cmp r0, #0\n" // cbz r0, label2
471 "beq.n 2f\n"
472 "1:\n" +
473 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
474 "2:\n";
475 DriverStr(expected, "TwoCbzSecondAtMaxB16Offset");
476
477 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u,
478 __ GetAdjustedPosition(label0.Position()));
479 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u,
480 __ GetAdjustedPosition(label1.Position()));
481 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u,
482 __ GetAdjustedPosition(label2.Position()));
483}
484
485TEST_F(AssemblerThumb2Test, TwoCbzSecondBeyondMaxB16Offset) {
486 Label label0, label1, label2;
487 __ cbz(arm::R0, &label1);
488 constexpr size_t kLdrR0R0Count1 = 62;
489 for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
490 __ ldr(arm::R0, arm::Address(arm::R0));
491 }
492 __ Bind(&label0);
493 __ cbz(arm::R0, &label2);
494 __ Bind(&label1);
495 constexpr size_t kLdrR0R0Count2 = 129;
496 for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
497 __ ldr(arm::R0, arm::Address(arm::R0));
498 }
499 __ Bind(&label2);
500
501 std::string expected =
502 "cmp r0, #0\n" // cbz r0, label1
503 "beq.n 1f\n" +
504 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
505 "0:\n"
506 "cmp r0, #0\n" // cbz r0, label2
507 "beq.w 2f\n"
508 "1:\n" +
509 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
510 "2:\n";
511 DriverStr(expected, "TwoCbzSecondBeyondMaxB16Offset");
512
513 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
514 __ GetAdjustedPosition(label0.Position()));
515 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u,
516 __ GetAdjustedPosition(label1.Position()));
517 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u,
518 __ GetAdjustedPosition(label2.Position()));
519}
520
521TEST_F(AssemblerThumb2Test, TwoCbzFirstAtMaxB16Offset) {
522 Label label0, label1, label2;
523 __ cbz(arm::R0, &label1);
524 constexpr size_t kLdrR0R0Count1 = 127;
525 for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
526 __ ldr(arm::R0, arm::Address(arm::R0));
527 }
528 __ Bind(&label0);
529 __ cbz(arm::R0, &label2);
530 __ Bind(&label1);
531 constexpr size_t kLdrR0R0Count2 = 64;
532 for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
533 __ ldr(arm::R0, arm::Address(arm::R0));
534 }
535 __ Bind(&label2);
536
537 std::string expected =
538 "cmp r0, #0\n" // cbz r0, label1
539 "beq.n 1f\n" +
540 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
541 "0:\n"
542 "cbz r0, 2f\n" // cbz r0, label2
543 "1:\n" +
544 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
545 "2:\n";
546 DriverStr(expected, "TwoCbzFirstAtMaxB16Offset");
547
548 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
549 __ GetAdjustedPosition(label0.Position()));
550 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u,
551 __ GetAdjustedPosition(label1.Position()));
552 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u,
553 __ GetAdjustedPosition(label2.Position()));
554}
555
556TEST_F(AssemblerThumb2Test, TwoCbzFirstBeyondMaxB16Offset) {
557 Label label0, label1, label2;
558 __ cbz(arm::R0, &label1);
559 constexpr size_t kLdrR0R0Count1 = 127;
560 for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
561 __ ldr(arm::R0, arm::Address(arm::R0));
562 }
563 __ Bind(&label0);
564 __ cbz(arm::R0, &label2);
565 __ Bind(&label1);
566 constexpr size_t kLdrR0R0Count2 = 65;
567 for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
568 __ ldr(arm::R0, arm::Address(arm::R0));
569 }
570 __ Bind(&label2);
571
572 std::string expected =
573 "cmp r0, #0\n" // cbz r0, label1
574 "beq.w 1f\n" +
575 RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
576 "0:\n"
577 "cmp r0, #0\n" // cbz r0, label2
578 "beq.n 2f\n"
579 "1:\n" +
580 RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
581 "2:\n";
582 DriverStr(expected, "TwoCbzFirstBeyondMaxB16Offset");
583
584 EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 4u,
585 __ GetAdjustedPosition(label0.Position()));
586 EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u,
587 __ GetAdjustedPosition(label1.Position()));
588 EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u,
589 __ GetAdjustedPosition(label2.Position()));
590}
591
592TEST_F(AssemblerThumb2Test, LoadLiteralMax1KiB) {
593 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
594 __ LoadLiteral(arm::R0, literal);
595 Label label;
596 __ Bind(&label);
597 constexpr size_t kLdrR0R0Count = 511;
598 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
599 __ ldr(arm::R0, arm::Address(arm::R0));
600 }
601
602 std::string expected =
603 "1:\n"
604 "ldr.n r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
605 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
606 ".align 2, 0\n"
607 "2:\n"
608 ".word 0x12345678\n";
609 DriverStr(expected, "LoadLiteralMax1KiB");
610
611 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u,
612 __ GetAdjustedPosition(label.Position()));
613}
614
615TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiB) {
616 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
617 __ LoadLiteral(arm::R0, literal);
618 Label label;
619 __ Bind(&label);
620 constexpr size_t kLdrR0R0Count = 512;
621 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
622 __ ldr(arm::R0, arm::Address(arm::R0));
623 }
624
625 std::string expected =
626 "1:\n"
627 "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
628 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
629 ".align 2, 0\n"
630 "2:\n"
631 ".word 0x12345678\n";
632 DriverStr(expected, "LoadLiteralBeyondMax1KiB");
633
634 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u,
635 __ GetAdjustedPosition(label.Position()));
636}
637
638TEST_F(AssemblerThumb2Test, LoadLiteralMax4KiB) {
639 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
640 __ LoadLiteral(arm::R1, literal);
641 Label label;
642 __ Bind(&label);
643 constexpr size_t kLdrR0R0Count = 2046;
644 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
645 __ ldr(arm::R0, arm::Address(arm::R0));
646 }
647
648 std::string expected =
649 "1:\n"
650 "ldr.w r1, [pc, #((2f - 1b - 2) & ~2)]\n" +
651 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
652 ".align 2, 0\n"
653 "2:\n"
654 ".word 0x12345678\n";
655 DriverStr(expected, "LoadLiteralMax4KiB");
656
657 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u,
658 __ GetAdjustedPosition(label.Position()));
659}
660
661TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax4KiB) {
662 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
663 __ LoadLiteral(arm::R1, literal);
664 Label label;
665 __ Bind(&label);
666 constexpr size_t kLdrR0R0Count = 2047;
667 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
668 __ ldr(arm::R0, arm::Address(arm::R0));
669 }
670
671 std::string expected =
672 "movw r1, #4096\n" // "as" does not consider (2f - 1f - 4) a constant expression for movw.
673 "1:\n"
674 "add r1, pc\n"
675 "ldr r1, [r1, #0]\n" +
676 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
677 ".align 2, 0\n"
678 "2:\n"
679 ".word 0x12345678\n";
680 DriverStr(expected, "LoadLiteralBeyondMax4KiB");
681
682 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
683 __ GetAdjustedPosition(label.Position()));
684}
685
686TEST_F(AssemblerThumb2Test, LoadLiteralMax64KiB) {
687 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
688 __ LoadLiteral(arm::R1, literal);
689 Label label;
690 __ Bind(&label);
691 constexpr size_t kLdrR0R0Count = (1u << 15) - 2u;
692 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
693 __ ldr(arm::R0, arm::Address(arm::R0));
694 }
695
696 std::string expected =
697 "movw r1, #0xfffc\n" // "as" does not consider (2f - 1f - 4) a constant expression for movw.
698 "1:\n"
699 "add r1, pc\n"
700 "ldr r1, [r1, #0]\n" +
701 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
702 ".align 2, 0\n"
703 "2:\n"
704 ".word 0x12345678\n";
705 DriverStr(expected, "LoadLiteralMax64KiB");
706
707 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
708 __ GetAdjustedPosition(label.Position()));
709}
710
711TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax64KiB) {
712 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
713 __ LoadLiteral(arm::R1, literal);
714 Label label;
715 __ Bind(&label);
716 constexpr size_t kLdrR0R0Count = (1u << 15) - 1u;
717 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
718 __ ldr(arm::R0, arm::Address(arm::R0));
719 }
720
721 std::string expected =
722 "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n"
723 "1:\n"
724 "add r1, pc\n"
725 "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" +
726 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
727 ".align 2, 0\n"
728 "2:\n"
729 ".word 0x12345678\n";
730 DriverStr(expected, "LoadLiteralBeyondMax64KiB");
731
732 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u,
733 __ GetAdjustedPosition(label.Position()));
734}
735
736TEST_F(AssemblerThumb2Test, LoadLiteralMax1MiB) {
737 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
738 __ LoadLiteral(arm::R1, literal);
739 Label label;
740 __ Bind(&label);
741 constexpr size_t kLdrR0R0Count = (1u << 19) - 3u;
742 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
743 __ ldr(arm::R0, arm::Address(arm::R0));
744 }
745
746 std::string expected =
747 "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n"
748 "1:\n"
749 "add r1, pc\n"
750 "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" +
751 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
752 ".align 2, 0\n"
753 "2:\n"
754 ".word 0x12345678\n";
755 DriverStr(expected, "LoadLiteralMax1MiB");
756
757 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u,
758 __ GetAdjustedPosition(label.Position()));
759}
760
761TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1MiB) {
762 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
763 __ LoadLiteral(arm::R1, literal);
764 Label label;
765 __ Bind(&label);
766 constexpr size_t kLdrR0R0Count = (1u << 19) - 2u;
767 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
768 __ ldr(arm::R0, arm::Address(arm::R0));
769 }
770
771 std::string expected =
772 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
773 "movw r1, #(0x100000 & 0xffff)\n"
774 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
775 "movt r1, #(0x100000 >> 16)\n"
776 "1:\n"
777 "add r1, pc\n"
778 "ldr.w r1, [r1, #0]\n" +
779 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
780 ".align 2, 0\n"
781 "2:\n"
782 ".word 0x12345678\n";
783 DriverStr(expected, "LoadLiteralBeyondMax1MiB");
784
785 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u,
786 __ GetAdjustedPosition(label.Position()));
787}
788
789TEST_F(AssemblerThumb2Test, LoadLiteralFar) {
790 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
791 __ LoadLiteral(arm::R1, literal);
792 Label label;
793 __ Bind(&label);
794 constexpr size_t kLdrR0R0Count = (1u << 19) - 2u + 0x1234;
795 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
796 __ ldr(arm::R0, arm::Address(arm::R0));
797 }
798
799 std::string expected =
800 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
801 "movw r1, #((0x100000 + 2 * 0x1234) & 0xffff)\n"
802 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
803 "movt r1, #((0x100000 + 2 * 0x1234) >> 16)\n"
804 "1:\n"
805 "add r1, pc\n"
806 "ldr.w r1, [r1, #0]\n" +
807 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
808 ".align 2, 0\n"
809 "2:\n"
810 ".word 0x12345678\n";
811 DriverStr(expected, "LoadLiteralFar");
812
813 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u,
814 __ GetAdjustedPosition(label.Position()));
815}
816
817TEST_F(AssemblerThumb2Test, LoadLiteralWideMax1KiB) {
818 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
819 __ LoadLiteral(arm::R1, arm::R3, literal);
820 Label label;
821 __ Bind(&label);
822 constexpr size_t kLdrR0R0Count = 510;
823 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
824 __ ldr(arm::R0, arm::Address(arm::R0));
825 }
826
827 std::string expected =
828 "1:\n"
829 "ldrd r1, r3, [pc, #((2f - 1b - 2) & ~2)]\n" +
830 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
831 ".align 2, 0\n"
832 "2:\n"
833 ".word 0x87654321\n"
834 ".word 0x12345678\n";
835 DriverStr(expected, "LoadLiteralWideMax1KiB");
836
837 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u,
838 __ GetAdjustedPosition(label.Position()));
839}
840
841TEST_F(AssemblerThumb2Test, LoadLiteralWideBeyondMax1KiB) {
842 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
843 __ LoadLiteral(arm::R1, arm::R3, literal);
844 Label label;
845 __ Bind(&label);
846 constexpr size_t kLdrR0R0Count = 511;
847 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
848 __ ldr(arm::R0, arm::Address(arm::R0));
849 }
850
851 std::string expected =
852 "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n"
853 "1:\n"
854 "add ip, pc\n"
855 "ldrd r1, r3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" +
856 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
857 ".align 2, 0\n"
858 "2:\n"
859 ".word 0x87654321\n"
860 ".word 0x12345678\n";
861 DriverStr(expected, "LoadLiteralWideBeyondMax1KiB");
862
863 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
864 __ GetAdjustedPosition(label.Position()));
865}
866
867TEST_F(AssemblerThumb2Test, LoadLiteralSingleMax256KiB) {
868 // The literal size must match but the type doesn't, so use an int32_t rather than float.
869 arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
870 __ LoadLiteral(arm::S3, literal);
871 Label label;
872 __ Bind(&label);
873 constexpr size_t kLdrR0R0Count = (1 << 17) - 3u;
874 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
875 __ ldr(arm::R0, arm::Address(arm::R0));
876 }
877
878 std::string expected =
879 "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n"
880 "1:\n"
881 "add ip, pc\n"
882 "vldr s3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" +
883 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
884 ".align 2, 0\n"
885 "2:\n"
886 ".word 0x12345678\n";
887 DriverStr(expected, "LoadLiteralSingleMax256KiB");
888
889 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
890 __ GetAdjustedPosition(label.Position()));
891}
892
893TEST_F(AssemblerThumb2Test, LoadLiteralDoubleBeyondMax256KiB) {
894 // The literal size must match but the type doesn't, so use an int64_t rather than double.
895 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
896 __ LoadLiteral(arm::D3, literal);
897 Label label;
898 __ Bind(&label);
899 constexpr size_t kLdrR0R0Count = (1 << 17) - 2u;
900 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
901 __ ldr(arm::R0, arm::Address(arm::R0));
902 }
903
904 std::string expected =
905 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
906 "movw ip, #(0x40000 & 0xffff)\n"
907 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
908 "movt ip, #(0x40000 >> 16)\n"
909 "1:\n"
910 "add ip, pc\n"
911 "vldr d3, [ip, #0]\n" +
912 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
913 ".align 2, 0\n"
914 "2:\n"
915 ".word 0x87654321\n"
916 ".word 0x12345678\n";
917 DriverStr(expected, "LoadLiteralDoubleBeyondMax256KiB");
918
919 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u,
920 __ GetAdjustedPosition(label.Position()));
921}
922
923TEST_F(AssemblerThumb2Test, LoadLiteralDoubleFar) {
924 // The literal size must match but the type doesn't, so use an int64_t rather than double.
925 arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
926 __ LoadLiteral(arm::D3, literal);
927 Label label;
928 __ Bind(&label);
929 constexpr size_t kLdrR0R0Count = (1 << 17) - 2u + 0x1234;
930 for (size_t i = 0; i != kLdrR0R0Count; ++i) {
931 __ ldr(arm::R0, arm::Address(arm::R0));
932 }
933
934 std::string expected =
935 // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
936 "movw ip, #((0x40000 + 2 * 0x1234) & 0xffff)\n"
937 // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
938 "movt ip, #((0x40000 + 2 * 0x1234) >> 16)\n"
939 "1:\n"
940 "add ip, pc\n"
941 "vldr d3, [ip, #0]\n" +
942 RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
943 ".align 2, 0\n"
944 "2:\n"
945 ".word 0x87654321\n"
946 ".word 0x12345678\n";
947 DriverStr(expected, "LoadLiteralDoubleFar");
948
949 EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u,
950 __ GetAdjustedPosition(label.Position()));
951}
952
Roland Levillain1a28fc42014-11-13 18:03:06 +0000953} // namespace art