blob: 62e0b90e73f972f4d8c8e8ed59851cd892ddfab4 [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
92
93TEST_F(AssemblerThumb2Test, Sbfx) {
94 GetAssembler()->sbfx(arm::R0, arm::R1, 0, 1);
95 GetAssembler()->sbfx(arm::R0, arm::R1, 0, 8);
96 GetAssembler()->sbfx(arm::R0, arm::R1, 0, 16);
97 GetAssembler()->sbfx(arm::R0, arm::R1, 0, 32);
98
99 GetAssembler()->sbfx(arm::R0, arm::R1, 8, 1);
100 GetAssembler()->sbfx(arm::R0, arm::R1, 8, 8);
101 GetAssembler()->sbfx(arm::R0, arm::R1, 8, 16);
102 GetAssembler()->sbfx(arm::R0, arm::R1, 8, 24);
103
104 GetAssembler()->sbfx(arm::R0, arm::R1, 16, 1);
105 GetAssembler()->sbfx(arm::R0, arm::R1, 16, 8);
106 GetAssembler()->sbfx(arm::R0, arm::R1, 16, 16);
107
108 GetAssembler()->sbfx(arm::R0, arm::R1, 31, 1);
109
110 const char* expected =
111 "sbfx r0, r1, #0, #1\n"
112 "sbfx r0, r1, #0, #8\n"
113 "sbfx r0, r1, #0, #16\n"
114 "sbfx r0, r1, #0, #32\n"
115
116 "sbfx r0, r1, #8, #1\n"
117 "sbfx r0, r1, #8, #8\n"
118 "sbfx r0, r1, #8, #16\n"
119 "sbfx r0, r1, #8, #24\n"
120
121 "sbfx r0, r1, #16, #1\n"
122 "sbfx r0, r1, #16, #8\n"
123 "sbfx r0, r1, #16, #16\n"
124
125 "sbfx r0, r1, #31, #1\n";
126 DriverStr(expected, "sbfx");
127}
128
Roland Levillain981e4542014-11-14 11:47:14 +0000129TEST_F(AssemblerThumb2Test, Ubfx) {
130 GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1);
131 GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8);
132 GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16);
133 GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32);
134
135 GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1);
136 GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8);
137 GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16);
138 GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24);
139
140 GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1);
141 GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8);
142 GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16);
143
144 GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1);
145
146 const char* expected =
147 "ubfx r0, r1, #0, #1\n"
148 "ubfx r0, r1, #0, #8\n"
149 "ubfx r0, r1, #0, #16\n"
150 "ubfx r0, r1, #0, #32\n"
151
152 "ubfx r0, r1, #8, #1\n"
153 "ubfx r0, r1, #8, #8\n"
154 "ubfx r0, r1, #8, #16\n"
155 "ubfx r0, r1, #8, #24\n"
156
157 "ubfx r0, r1, #16, #1\n"
158 "ubfx r0, r1, #16, #8\n"
159 "ubfx r0, r1, #16, #16\n"
160
161 "ubfx r0, r1, #31, #1\n";
162 DriverStr(expected, "ubfx");
163}
164
Calin Juravleddb7df22014-11-25 20:56:51 +0000165TEST_F(AssemblerThumb2Test, Vmstat) {
166 GetAssembler()->vmstat();
167
168 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
169
170 DriverStr(expected, "vmrs");
171}
172
Calin Juravle52c48962014-12-16 17:02:57 +0000173TEST_F(AssemblerThumb2Test, ldrexd) {
174 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
175 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
176 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
177 GetAssembler()->ldrexd(arm::R5, arm::R3, arm::R7);
178
179 const char* expected =
180 "ldrexd r0, r1, [r0]\n"
181 "ldrexd r0, r1, [r1]\n"
182 "ldrexd r0, r1, [r2]\n"
183 "ldrexd r5, r3, [r7]\n";
184 DriverStr(expected, "ldrexd");
185}
186
187TEST_F(AssemblerThumb2Test, strexd) {
188 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
189 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
190 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
191 GetAssembler()->strexd(arm::R9, arm::R5, arm::R3, arm::R7);
192
193 const char* expected =
194 "strexd r9, r0, r1, [r0]\n"
195 "strexd r9, r0, r1, [r1]\n"
196 "strexd r9, r0, r1, [r2]\n"
197 "strexd r9, r5, r3, [r7]\n";
198 DriverStr(expected, "strexd");
199}
200
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -0800201TEST_F(AssemblerThumb2Test, LdrdStrd) {
202 GetAssembler()->ldrd(arm::R0, arm::Address(arm::R2, 8));
203 GetAssembler()->ldrd(arm::R0, arm::Address(arm::R12));
204 GetAssembler()->strd(arm::R0, arm::Address(arm::R2, 8));
205
206 const char* expected =
207 "ldrd r0, r1, [r2, #8]\n"
208 "ldrd r0, r1, [r12]\n"
209 "strd r0, r1, [r2, #8]\n";
210 DriverStr(expected, "ldrdstrd");
211}
212
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800213TEST_F(AssemblerThumb2Test, eor) {
214#define __ GetAssembler()->
215 __ 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));
233
234 const char* expected =
235 "subs r1, r0, #42\n"
236 "subw r1, r0, #42\n";
237 DriverStr(expected, "sub");
238}
239
240TEST_F(AssemblerThumb2Test, add) {
241 __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
242 __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
243
244 const char* expected =
245 "adds r1, r0, #42\n"
246 "addw r1, r0, #42\n";
247 DriverStr(expected, "add");
248}
249
Roland Levillainc5a5ac62015-04-02 15:49:24 +0100250TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
251 arm::StoreOperandType type = arm::kStoreWord;
252 int32_t offset = 4092;
253 ASSERT_TRUE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
254
255 __ StoreToOffset(type, arm::R0, arm::SP, offset);
256 __ StoreToOffset(type, arm::IP, arm::SP, offset);
257 __ StoreToOffset(type, arm::IP, arm::R5, offset);
258
259 const char* expected =
260 "str r0, [sp, #4092]\n"
261 "str ip, [sp, #4092]\n"
262 "str ip, [r5, #4092]\n";
263 DriverStr(expected, "StoreWordToThumbOffset");
264}
265
266TEST_F(AssemblerThumb2Test, StoreWordToNonThumbOffset) {
267 arm::StoreOperandType type = arm::kStoreWord;
268 int32_t offset = 4096;
269 ASSERT_FALSE(arm::Address::CanHoldStoreOffsetThumb(type, offset));
270
271 __ StoreToOffset(type, arm::R0, arm::SP, offset);
272 __ StoreToOffset(type, arm::IP, arm::SP, offset);
273 __ StoreToOffset(type, arm::IP, arm::R5, offset);
274
275 const char* expected =
276 "mov ip, #4096\n" // LoadImmediate(ip, 4096)
277 "add ip, ip, sp\n"
278 "str r0, [ip, #0]\n"
279
280 "str r5, [sp, #-4]!\n" // Push(r5)
281 "movw r5, #4100\n" // LoadImmediate(r5, 4096 + kRegisterSize)
282 "add r5, r5, sp\n"
283 "str ip, [r5, #0]\n"
284 "ldr r5, [sp], #4\n" // Pop(r5)
285
286 "str r6, [sp, #-4]!\n" // Push(r6)
287 "mov r6, #4096\n" // LoadImmediate(r6, 4096)
288 "add r6, r6, r5\n"
289 "str ip, [r6, #0]\n"
290 "ldr r6, [sp], #4\n"; // Pop(r6)
291 DriverStr(expected, "StoreWordToNonThumbOffset");
292}
293
Roland Levillain1a28fc42014-11-13 18:03:06 +0000294} // namespace art