blob: 733441b889482f4686c59da8a43f59f2d9052738 [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
81 private:
82 std::vector<arm::Register*> registers_;
Andreas Gampe513ea0c2015-02-02 13:17:52 -080083
84 static constexpr const char* kThumb2AssemblyHeader = ".syntax unified\n.thumb\n";
Roland Levillain1a28fc42014-11-13 18:03:06 +000085};
86
87
88TEST_F(AssemblerThumb2Test, Toolchain) {
89 EXPECT_TRUE(CheckTools());
90}
91
Zheng Xuc6667102015-05-15 16:08:45 +080092#define __ GetAssembler()->
Roland Levillain1a28fc42014-11-13 18:03:06 +000093
94TEST_F(AssemblerThumb2Test, Sbfx) {
Zheng Xuc6667102015-05-15 16:08:45 +080095 __ sbfx(arm::R0, arm::R1, 0, 1);
96 __ sbfx(arm::R0, arm::R1, 0, 8);
97 __ sbfx(arm::R0, arm::R1, 0, 16);
98 __ sbfx(arm::R0, arm::R1, 0, 32);
Roland Levillain1a28fc42014-11-13 18:03:06 +000099
Zheng Xuc6667102015-05-15 16:08:45 +0800100 __ sbfx(arm::R0, arm::R1, 8, 1);
101 __ sbfx(arm::R0, arm::R1, 8, 8);
102 __ sbfx(arm::R0, arm::R1, 8, 16);
103 __ sbfx(arm::R0, arm::R1, 8, 24);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000104
Zheng Xuc6667102015-05-15 16:08:45 +0800105 __ sbfx(arm::R0, arm::R1, 16, 1);
106 __ sbfx(arm::R0, arm::R1, 16, 8);
107 __ sbfx(arm::R0, arm::R1, 16, 16);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000108
Zheng Xuc6667102015-05-15 16:08:45 +0800109 __ sbfx(arm::R0, arm::R1, 31, 1);
Roland Levillain1a28fc42014-11-13 18:03:06 +0000110
111 const char* expected =
112 "sbfx r0, r1, #0, #1\n"
113 "sbfx r0, r1, #0, #8\n"
114 "sbfx r0, r1, #0, #16\n"
115 "sbfx r0, r1, #0, #32\n"
116
117 "sbfx r0, r1, #8, #1\n"
118 "sbfx r0, r1, #8, #8\n"
119 "sbfx r0, r1, #8, #16\n"
120 "sbfx r0, r1, #8, #24\n"
121
122 "sbfx r0, r1, #16, #1\n"
123 "sbfx r0, r1, #16, #8\n"
124 "sbfx r0, r1, #16, #16\n"
125
126 "sbfx r0, r1, #31, #1\n";
127 DriverStr(expected, "sbfx");
128}
129
Roland Levillain981e4542014-11-14 11:47:14 +0000130TEST_F(AssemblerThumb2Test, Ubfx) {
Zheng Xuc6667102015-05-15 16:08:45 +0800131 __ ubfx(arm::R0, arm::R1, 0, 1);
132 __ ubfx(arm::R0, arm::R1, 0, 8);
133 __ ubfx(arm::R0, arm::R1, 0, 16);
134 __ ubfx(arm::R0, arm::R1, 0, 32);
Roland Levillain981e4542014-11-14 11:47:14 +0000135
Zheng Xuc6667102015-05-15 16:08:45 +0800136 __ ubfx(arm::R0, arm::R1, 8, 1);
137 __ ubfx(arm::R0, arm::R1, 8, 8);
138 __ ubfx(arm::R0, arm::R1, 8, 16);
139 __ ubfx(arm::R0, arm::R1, 8, 24);
Roland Levillain981e4542014-11-14 11:47:14 +0000140
Zheng Xuc6667102015-05-15 16:08:45 +0800141 __ ubfx(arm::R0, arm::R1, 16, 1);
142 __ ubfx(arm::R0, arm::R1, 16, 8);
143 __ ubfx(arm::R0, arm::R1, 16, 16);
Roland Levillain981e4542014-11-14 11:47:14 +0000144
Zheng Xuc6667102015-05-15 16:08:45 +0800145 __ ubfx(arm::R0, arm::R1, 31, 1);
Roland Levillain981e4542014-11-14 11:47:14 +0000146
147 const char* expected =
148 "ubfx r0, r1, #0, #1\n"
149 "ubfx r0, r1, #0, #8\n"
150 "ubfx r0, r1, #0, #16\n"
151 "ubfx r0, r1, #0, #32\n"
152
153 "ubfx r0, r1, #8, #1\n"
154 "ubfx r0, r1, #8, #8\n"
155 "ubfx r0, r1, #8, #16\n"
156 "ubfx r0, r1, #8, #24\n"
157
158 "ubfx r0, r1, #16, #1\n"
159 "ubfx r0, r1, #16, #8\n"
160 "ubfx r0, r1, #16, #16\n"
161
162 "ubfx r0, r1, #31, #1\n";
163 DriverStr(expected, "ubfx");
164}
165
Calin Juravleddb7df22014-11-25 20:56:51 +0000166TEST_F(AssemblerThumb2Test, Vmstat) {
Zheng Xuc6667102015-05-15 16:08:45 +0800167 __ vmstat();
Calin Juravleddb7df22014-11-25 20:56:51 +0000168
169 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
170
171 DriverStr(expected, "vmrs");
172}
173
Calin Juravle52c48962014-12-16 17:02:57 +0000174TEST_F(AssemblerThumb2Test, ldrexd) {
Zheng Xuc6667102015-05-15 16:08:45 +0800175 __ ldrexd(arm::R0, arm::R1, arm::R0);
176 __ ldrexd(arm::R0, arm::R1, arm::R1);
177 __ ldrexd(arm::R0, arm::R1, arm::R2);
178 __ ldrexd(arm::R5, arm::R3, arm::R7);
Calin Juravle52c48962014-12-16 17:02:57 +0000179
180 const char* expected =
181 "ldrexd r0, r1, [r0]\n"
182 "ldrexd r0, r1, [r1]\n"
183 "ldrexd r0, r1, [r2]\n"
184 "ldrexd r5, r3, [r7]\n";
185 DriverStr(expected, "ldrexd");
186}
187
188TEST_F(AssemblerThumb2Test, strexd) {
Zheng Xuc6667102015-05-15 16:08:45 +0800189 __ strexd(arm::R9, arm::R0, arm::R1, arm::R0);
190 __ strexd(arm::R9, arm::R0, arm::R1, arm::R1);
191 __ strexd(arm::R9, arm::R0, arm::R1, arm::R2);
192 __ strexd(arm::R9, arm::R5, arm::R3, arm::R7);
Calin Juravle52c48962014-12-16 17:02:57 +0000193
194 const char* expected =
195 "strexd r9, r0, r1, [r0]\n"
196 "strexd r9, r0, r1, [r1]\n"
197 "strexd r9, r0, r1, [r2]\n"
198 "strexd r9, r5, r3, [r7]\n";
199 DriverStr(expected, "strexd");
200}
201
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -0800202TEST_F(AssemblerThumb2Test, LdrdStrd) {
Zheng Xuc6667102015-05-15 16:08:45 +0800203 __ ldrd(arm::R0, arm::Address(arm::R2, 8));
204 __ ldrd(arm::R0, arm::Address(arm::R12));
205 __ strd(arm::R0, arm::Address(arm::R2, 8));
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -0800206
207 const char* expected =
208 "ldrd r0, r1, [r2, #8]\n"
209 "ldrd r0, r1, [r12]\n"
210 "strd r0, r1, [r2, #8]\n";
211 DriverStr(expected, "ldrdstrd");
212}
213
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800214TEST_F(AssemblerThumb2Test, eor) {
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800215 __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0));
216 __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1));
217 __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0));
218 __ eor(arm::R8, arm::R1, arm::ShifterOperand(arm::R0));
219 __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R8));
220
221 const char* expected =
222 "eors r1, r0\n"
223 "eor r1, r0, r1\n"
224 "eor r1, r8, r0\n"
225 "eor r8, r1, r0\n"
226 "eor r1, r0, r8\n";
227 DriverStr(expected, "abs");
228}
229
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000230TEST_F(AssemblerThumb2Test, sub) {
231 __ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
232 __ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
Zheng Xuc6667102015-05-15 16:08:45 +0800233 __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
234 __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000235
236 const char* expected =
237 "subs r1, r0, #42\n"
Zheng Xuc6667102015-05-15 16:08:45 +0800238 "subw r1, r0, #42\n"
239 "subs r1, r0, r2, asr #31\n"
240 "sub r1, r0, r2, asr #31\n";
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000241 DriverStr(expected, "sub");
242}
243
244TEST_F(AssemblerThumb2Test, add) {
245 __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
246 __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
Zheng Xuc6667102015-05-15 16:08:45 +0800247 __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
248 __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000249
250 const char* expected =
251 "adds r1, r0, #42\n"
Zheng Xuc6667102015-05-15 16:08:45 +0800252 "addw r1, r0, #42\n"
253 "adds r1, r0, r2, asr #31\n"
254 "add r1, r0, r2, asr #31\n";
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000255 DriverStr(expected, "add");
256}
257
Zheng Xuc6667102015-05-15 16:08:45 +0800258TEST_F(AssemblerThumb2Test, umull) {
259 __ umull(arm::R0, arm::R1, arm::R2, arm::R3);
260
261 const char* expected =
262 "umull r0, r1, r2, r3\n";
263 DriverStr(expected, "umull");
264}
265
266TEST_F(AssemblerThumb2Test, smull) {
267 __ smull(arm::R0, arm::R1, arm::R2, arm::R3);
268
269 const char* expected =
270 "smull r0, r1, r2, r3\n";
271 DriverStr(expected, "smull");
272}
273
Roland Levillainc5a5ac62015-04-02 15:49:24 +0100274TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
275 arm::StoreOperandType type = arm::kStoreWord;
276 int32_t offset = 4092;
277 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
278
279 __ StoreToOffset(type, arm::R0, arm::SP, offset);
280 __ StoreToOffset(type, arm::IP, arm::SP, offset);
281 __ StoreToOffset(type, arm::IP, arm::R5, offset);
282
283 const char* expected =
284 "str r0, [sp, #4092]\n"
285 "str ip, [sp, #4092]\n"
286 "str ip, [r5, #4092]\n";
287 DriverStr(expected, "StoreWordToThumbOffset");
288}
289
290TEST_F(AssemblerThumb2Test, StoreWordToNonThumbOffset) {
291 arm::StoreOperandType type = arm::kStoreWord;
292 int32_t offset = 4096;
293 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
294
295 __ StoreToOffset(type, arm::R0, arm::SP, offset);
296 __ StoreToOffset(type, arm::IP, arm::SP, offset);
297 __ StoreToOffset(type, arm::IP, arm::R5, offset);
298
299 const char* expected =
300 "mov ip, #4096\n" // LoadImmediate(ip, 4096)
301 "add ip, ip, sp\n"
302 "str r0, [ip, #0]\n"
303
304 "str r5, [sp, #-4]!\n" // Push(r5)
305 "movw r5, #4100\n" // LoadImmediate(r5, 4096 + kRegisterSize)
306 "add r5, r5, sp\n"
307 "str ip, [r5, #0]\n"
308 "ldr r5, [sp], #4\n" // Pop(r5)
309
310 "str r6, [sp, #-4]!\n" // Push(r6)
311 "mov r6, #4096\n" // LoadImmediate(r6, 4096)
312 "add r6, r6, r5\n"
313 "str ip, [r6, #0]\n"
314 "ldr r6, [sp], #4\n"; // Pop(r6)
315 DriverStr(expected, "StoreWordToNonThumbOffset");
316}
317
Roland Levillain4af147e2015-04-07 13:54:49 +0100318TEST_F(AssemblerThumb2Test, StoreWordPairToThumbOffset) {
319 arm::StoreOperandType type = arm::kStoreWordPair;
320 int32_t offset = 1020;
321 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
322
323 __ StoreToOffset(type, arm::R0, arm::SP, offset);
324 // We cannot use IP (i.e. R12) as first source register, as it would
325 // force us to use SP (i.e. R13) as second source register, which
326 // would have an "unpredictable" effect according to the ARMv7
327 // specification (the T1 encoding describes the result as
328 // UNPREDICTABLE when of the source registers is R13).
329 //
330 // So we use (R11, IP) (e.g. (R11, R12)) as source registers in the
331 // following instructions.
332 __ StoreToOffset(type, arm::R11, arm::SP, offset);
333 __ StoreToOffset(type, arm::R11, arm::R5, offset);
334
335 const char* expected =
336 "strd r0, r1, [sp, #1020]\n"
337 "strd r11, ip, [sp, #1020]\n"
338 "strd r11, ip, [r5, #1020]\n";
339 DriverStr(expected, "StoreWordPairToThumbOffset");
340}
341
342TEST_F(AssemblerThumb2Test, StoreWordPairToNonThumbOffset) {
343 arm::StoreOperandType type = arm::kStoreWordPair;
344 int32_t offset = 1024;
345 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
346
347 __ StoreToOffset(type, arm::R0, arm::SP, offset);
348 // Same comment as in AssemblerThumb2Test.StoreWordPairToThumbOffset
349 // regarding the use of (R11, IP) (e.g. (R11, R12)) as source
350 // registers in the following instructions.
351 __ StoreToOffset(type, arm::R11, arm::SP, offset);
352 __ StoreToOffset(type, arm::R11, arm::R5, offset);
353
354 const char* expected =
355 "mov ip, #1024\n" // LoadImmediate(ip, 1024)
356 "add ip, ip, sp\n"
357 "strd r0, r1, [ip, #0]\n"
358
359 "str r5, [sp, #-4]!\n" // Push(r5)
360 "movw r5, #1028\n" // LoadImmediate(r5, 1024 + kRegisterSize)
361 "add r5, r5, sp\n"
362 "strd r11, ip, [r5, #0]\n"
363 "ldr r5, [sp], #4\n" // Pop(r5)
364
365 "str r6, [sp, #-4]!\n" // Push(r6)
366 "mov r6, #1024\n" // LoadImmediate(r6, 1024)
367 "add r6, r6, r5\n"
368 "strd r11, ip, [r6, #0]\n"
369 "ldr r6, [sp], #4\n"; // Pop(r6)
370 DriverStr(expected, "StoreWordPairToNonThumbOffset");
371}
372
Roland Levillain1a28fc42014-11-13 18:03:06 +0000373} // namespace art