blob: efd517b83aa8b4f9f0b0cd7d31b1fa63ea5b48ec [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_arm32.h"
18
Andreas Gampe849cc5e2014-11-18 13:46:46 -080019#include <functional>
20#include <type_traits>
21
22#include "base/macros.h"
Roland Levillain1a28fc42014-11-13 18:03:06 +000023#include "base/stl_util.h"
Andreas Gampe849cc5e2014-11-18 13:46:46 -080024#include "utils/arm/assembler_arm_test.h"
Roland Levillain1a28fc42014-11-13 18:03:06 +000025
26namespace art {
27
Andreas Gampe849cc5e2014-11-18 13:46:46 -080028using std::placeholders::_1;
29using std::placeholders::_2;
30using std::placeholders::_3;
31using std::placeholders::_4;
32using std::placeholders::_5;
33
34// To speed up tests, don't use all register combinations.
35static constexpr bool kUseSparseRegisterList = true;
36
37// To speed up tests, don't use all condition codes.
38static constexpr bool kUseSparseConditionList = true;
39
40// To speed up tests, don't use all shift immediates.
41static constexpr bool kUseSparseShiftImmediates = true;
42
43class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler,
44 arm::Register, arm::SRegister,
45 uint32_t, arm::ShifterOperand, arm::Condition> {
Roland Levillain1a28fc42014-11-13 18:03:06 +000046 protected:
47 std::string GetArchitectureString() OVERRIDE {
48 return "arm";
49 }
50
Andreas Gampe849cc5e2014-11-18 13:46:46 -080051 std::string GetAssemblerParameters() OVERRIDE {
Calin Juravleddb7df22014-11-25 20:56:51 +000052 // Arm-v7a, cortex-a15 (means we have sdiv).
53 return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
Andreas Gampe849cc5e2014-11-18 13:46:46 -080054 }
55
56 const char* GetAssemblyHeader() OVERRIDE {
57 return kArm32AssemblyHeader;
58 }
59
Roland Levillain1a28fc42014-11-13 18:03:06 +000060 std::string GetDisassembleParameters() OVERRIDE {
61 return " -D -bbinary -marm --no-show-raw-insn";
62 }
63
64 void SetUpHelpers() OVERRIDE {
65 if (registers_.size() == 0) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -080066 if (kUseSparseRegisterList) {
67 registers_.insert(end(registers_),
68 { // NOLINT(whitespace/braces)
69 new arm::Register(arm::R0),
70 new arm::Register(arm::R1),
71 new arm::Register(arm::R4),
72 new arm::Register(arm::R8),
73 new arm::Register(arm::R11),
74 new arm::Register(arm::R12),
75 new arm::Register(arm::R13),
76 new arm::Register(arm::R14),
77 new arm::Register(arm::R15)
78 });
79 } else {
80 registers_.insert(end(registers_),
81 { // NOLINT(whitespace/braces)
82 new arm::Register(arm::R0),
83 new arm::Register(arm::R1),
84 new arm::Register(arm::R2),
85 new arm::Register(arm::R3),
86 new arm::Register(arm::R4),
87 new arm::Register(arm::R5),
88 new arm::Register(arm::R6),
89 new arm::Register(arm::R7),
90 new arm::Register(arm::R8),
91 new arm::Register(arm::R9),
92 new arm::Register(arm::R10),
93 new arm::Register(arm::R11),
94 new arm::Register(arm::R12),
95 new arm::Register(arm::R13),
96 new arm::Register(arm::R14),
97 new arm::Register(arm::R15)
98 });
99 }
100 }
101
102 if (!kUseSparseConditionList) {
103 conditions_.push_back(arm::Condition::EQ);
104 conditions_.push_back(arm::Condition::NE);
105 conditions_.push_back(arm::Condition::CS);
106 conditions_.push_back(arm::Condition::CC);
107 conditions_.push_back(arm::Condition::MI);
108 conditions_.push_back(arm::Condition::PL);
109 conditions_.push_back(arm::Condition::VS);
110 conditions_.push_back(arm::Condition::VC);
111 conditions_.push_back(arm::Condition::HI);
112 conditions_.push_back(arm::Condition::LS);
113 conditions_.push_back(arm::Condition::GE);
114 conditions_.push_back(arm::Condition::LT);
115 conditions_.push_back(arm::Condition::GT);
116 conditions_.push_back(arm::Condition::LE);
117 conditions_.push_back(arm::Condition::AL);
118 } else {
119 conditions_.push_back(arm::Condition::EQ);
120 conditions_.push_back(arm::Condition::NE);
121 conditions_.push_back(arm::Condition::CC);
122 conditions_.push_back(arm::Condition::VC);
123 conditions_.push_back(arm::Condition::HI);
124 conditions_.push_back(arm::Condition::LT);
125 conditions_.push_back(arm::Condition::AL);
126 }
127
128 shifter_operands_.push_back(arm::ShifterOperand(0));
129 shifter_operands_.push_back(arm::ShifterOperand(1));
130 shifter_operands_.push_back(arm::ShifterOperand(2));
131 shifter_operands_.push_back(arm::ShifterOperand(3));
132 shifter_operands_.push_back(arm::ShifterOperand(4));
133 shifter_operands_.push_back(arm::ShifterOperand(5));
134 shifter_operands_.push_back(arm::ShifterOperand(127));
135 shifter_operands_.push_back(arm::ShifterOperand(128));
136 shifter_operands_.push_back(arm::ShifterOperand(254));
137 shifter_operands_.push_back(arm::ShifterOperand(255));
138
139 if (!kUseSparseRegisterList) {
140 shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
141 shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
142 shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
143 shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
144 shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
145 shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
146 shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
147 shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
148 shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
149 shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
150 shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
151 shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
152 shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
153 shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
154 } else {
155 shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
156 shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
157 shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
158 shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
159 shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
160 shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
161 shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
162 }
163
164 std::vector<arm::Shift> shifts {
165 arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
166 };
167
168 // ShifterOperands of form "reg shift-type imm."
169 for (arm::Shift shift : shifts) {
170 for (arm::Register* reg : registers_) { // Note: this will pick up the sparse set.
171 if (*reg == arm::R15) { // Skip PC.
172 continue;
173 }
174 if (shift != arm::Shift::RRX) {
175 if (!kUseSparseShiftImmediates) {
176 for (uint32_t imm = 1; imm < 32; ++imm) {
177 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
178 }
179 } else {
180 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
181 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
182 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
183 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
184 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
185 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
186 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
187 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
188 }
189 } else {
190 // RRX doesn't have an immediate.
191 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
192 }
193 }
Roland Levillain1a28fc42014-11-13 18:03:06 +0000194 }
195 }
196
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800197 std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
198 int32_t shift_min, int32_t shift_max) {
199 std::vector<arm::ShifterOperand> res;
200 static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
201 arm::Shift::ROR };
202
203 for (arm::Shift shift : kShifts) {
204 for (arm::Register* reg : base_regs) {
205 // Take the min, the max, and three values in between.
206 res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
207 if (shift_min != shift_max) {
208 res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
209 int32_t middle = (shift_min + shift_max) / 2;
210 res.push_back(arm::ShifterOperand(*reg, shift, middle));
211 res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
212 res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
213 }
214 }
215 }
216
217 return res;
218 }
219
Roland Levillain1a28fc42014-11-13 18:03:06 +0000220 void TearDown() OVERRIDE {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800221 AssemblerArmTest::TearDown();
Roland Levillain1a28fc42014-11-13 18:03:06 +0000222 STLDeleteElements(&registers_);
223 }
224
225 std::vector<arm::Register*> GetRegisters() OVERRIDE {
226 return registers_;
227 }
228
229 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
230 return imm_value;
231 }
232
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800233 std::vector<arm::Condition>& GetConditions() OVERRIDE {
234 return conditions_;
235 }
236
237 std::string GetConditionString(arm::Condition c) OVERRIDE {
238 std::ostringstream oss;
239 oss << c;
240 return oss.str();
241 }
242
243 arm::Register GetPCRegister() OVERRIDE {
244 return arm::R15;
245 }
246
247 std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
248 return shifter_operands_;
249 }
250
251 std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
252 std::ostringstream oss;
253 if (sop.IsShift()) {
254 // Not a rotate...
255 if (sop.GetShift() == arm::Shift::RRX) {
256 oss << sop.GetRegister() << ", " << sop.GetShift();
257 } else {
258 oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
259 }
260 } else if (sop.IsRegister()) {
261 oss << sop.GetRegister();
262 } else {
263 CHECK(sop.IsImmediate());
264 oss << "#" << sop.GetImmediate();
265 }
266 return oss.str();
267 }
268
269 static const char* GetRegTokenFromDepth(int depth) {
270 switch (depth) {
271 case 0:
272 return Base::REG1_TOKEN;
273 case 1:
274 return Base::REG2_TOKEN;
275 case 2:
276 return REG3_TOKEN;
277 case 3:
278 return REG4_TOKEN;
279 default:
280 LOG(FATAL) << "Depth problem.";
281 UNREACHABLE();
282 }
283 }
284
285 void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
286 if (first_) {
287 first_ = false;
288 } else {
289 oss << "\n";
290 }
291 oss << fmt;
292
293 f();
294 }
295
Zheng Xuc6667102015-05-15 16:08:45 +0800296 // NOTE: Only support simple test like "aaa=bbb"
297 bool EvalFilterString(std::string filter) {
298 if (filter.compare("") == 0) {
299 return false;
300 }
301
302 size_t equal_sign_index = filter.find('=');
303 if (equal_sign_index == std::string::npos) {
304 EXPECT_TRUE(false) << "Unsupported filter string.";
305 }
306
307 std::string lhs = filter.substr(0, equal_sign_index);
308 std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
309 return lhs.compare(rhs) == 0;
310 }
311
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800312 void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
Zheng Xuc6667102015-05-15 16:08:45 +0800313 bool without_pc, std::string fmt, std::string filter,
314 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800315 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
316 for (auto reg : registers) {
317 std::string after_reg = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800318 std::string after_reg_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800319
320 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
321 size_t reg_index;
322 const char* reg_token = GetRegTokenFromDepth(depth);
323
324 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
325 after_reg.replace(reg_index, strlen(reg_token), reg_string);
326 }
327
Zheng Xuc6667102015-05-15 16:08:45 +0800328 while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
329 after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
330 }
331 if (EvalFilterString(after_reg_filter)) {
332 continue;
333 }
334
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800335 ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
336 }
337 }
338
339 void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
Zheng Xuc6667102015-05-15 16:08:45 +0800340 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
341 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800342 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
343 std::string after_shift = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800344 std::string after_shift_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800345
346 std::string shift_string = GetShiftString(shift);
347 size_t shift_index;
348 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
349 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
350 }
351
Zheng Xuc6667102015-05-15 16:08:45 +0800352 while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
353 after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
354 }
355 if (EvalFilterString(after_shift_filter)) {
356 continue;
357 }
358
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800359 ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
360 }
361 }
362
363 void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
Zheng Xuc6667102015-05-15 16:08:45 +0800364 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
365 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800366 for (arm::Condition c : GetConditions()) {
367 std::string after_cond = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800368 std::string after_cond_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800369
370 size_t cond_index = after_cond.find(COND_TOKEN);
371 if (cond_index != std::string::npos) {
372 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
373 }
374
Zheng Xuc6667102015-05-15 16:08:45 +0800375 cond_index = after_cond_filter.find(COND_TOKEN);
376 if (cond_index != std::string::npos) {
377 after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
378 }
379 if (EvalFilterString(after_cond_filter)) {
380 continue;
381 }
382
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800383 ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
384 }
385 }
386
387 template <typename... Args>
388 void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800389 std::string fmt, std::string filter, std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800390 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
391 for (auto reg : registers) {
392 std::string after_reg = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800393 std::string after_reg_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800394
395 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
396 size_t reg_index;
397 const char* reg_token = GetRegTokenFromDepth(depth);
398
399 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
400 after_reg.replace(reg_index, strlen(reg_token), reg_string);
401 }
402
Zheng Xuc6667102015-05-15 16:08:45 +0800403 while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
404 after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
405 }
406 if (EvalFilterString(after_reg_filter)) {
407 continue;
408 }
409
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800410 auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
411 TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800412 after_reg, after_reg_filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800413 }
414 }
415
416 template <typename... Args>
417 void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
Zheng Xuc6667102015-05-15 16:08:45 +0800418 bool without_pc, std::string fmt, std::string filter,
419 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800420 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
421 std::string after_shift = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800422 std::string after_shift_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800423
424 std::string shift_string = GetShiftString(shift);
425 size_t shift_index;
426 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
427 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
428 }
429
Zheng Xuc6667102015-05-15 16:08:45 +0800430 while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
431 after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
432 }
433 if (EvalFilterString(after_shift_filter)) {
434 continue;
435 }
436
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800437 auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
438 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800439 after_shift, after_shift_filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800440 }
441 }
442
443 template <typename... Args>
444 void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800445 std::string fmt, std::string filter, std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800446 for (arm::Condition c : GetConditions()) {
447 std::string after_cond = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800448 std::string after_cond_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800449
450 size_t cond_index = after_cond.find(COND_TOKEN);
451 if (cond_index != std::string::npos) {
452 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
453 }
454
Zheng Xuc6667102015-05-15 16:08:45 +0800455 cond_index = after_cond_filter.find(COND_TOKEN);
456 if (cond_index != std::string::npos) {
457 after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
458 }
459 if (EvalFilterString(after_cond_filter)) {
460 continue;
461 }
462
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800463 auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
464 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800465 after_cond, after_cond_filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800466 }
467 }
468
469 template <typename T1, typename T2>
470 std::function<void(T1, T2)> GetBoundFunction2(void (arm::Arm32Assembler::*f)(T1, T2)) {
471 return std::bind(f, GetAssembler(), _1, _2);
472 }
473
474 template <typename T1, typename T2, typename T3>
475 std::function<void(T1, T2, T3)> GetBoundFunction3(void (arm::Arm32Assembler::*f)(T1, T2, T3)) {
476 return std::bind(f, GetAssembler(), _1, _2, _3);
477 }
478
479 template <typename T1, typename T2, typename T3, typename T4>
480 std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
481 void (arm::Arm32Assembler::*f)(T1, T2, T3, T4)) {
482 return std::bind(f, GetAssembler(), _1, _2, _3, _4);
483 }
484
485 template <typename T1, typename T2, typename T3, typename T4, typename T5>
486 std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
487 void (arm::Arm32Assembler::*f)(T1, T2, T3, T4, T5)) {
488 return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
489 }
490
491 template <typename... Args>
492 void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800493 std::string fmt, std::string test_name, std::string filter) {
Andreas Gampeab65c672014-11-20 20:22:31 -0800494 first_ = false;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800495 WarnOnCombinations(CountHelper<Args...>(without_pc));
496
497 std::ostringstream oss;
498
Zheng Xuc6667102015-05-15 16:08:45 +0800499 TemplateHelper(f, 0, without_pc, fmt, filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800500
501 oss << "\n"; // Trailing newline.
502
503 DriverStr(oss.str(), test_name);
504 }
505
506 template <typename... Args>
507 void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800508 std::string test_name, std::string filter = "") {
509 GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800510 }
511
512 template <typename... Args>
513 void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800514 std::string test_name, std::string filter = "") {
515 GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800516 }
517
518 template <typename... Args>
519 void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800520 std::string test_name, std::string filter = "") {
521 GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800522 }
523
524 template <typename... Args>
525 void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800526 std::string test_name, std::string filter = "") {
527 GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800528 }
529
Roland Levillain1a28fc42014-11-13 18:03:06 +0000530 private:
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800531 template <typename T>
532 size_t CountHelper(bool without_pc) {
533 size_t tmp;
534 if (std::is_same<T, arm::Register>::value) {
535 tmp = GetRegisters().size();
536 if (without_pc) {
537 tmp--;; // Approximation...
538 }
539 return tmp;
540 } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
541 return GetShiftOperands().size();
542 } else if (std::is_same<T, arm::Condition>::value) {
543 return GetConditions().size();
544 } else {
545 LOG(WARNING) << "Unknown type while counting.";
546 return 1;
547 }
548 }
549
550 template <typename T1, typename T2, typename... Args>
551 size_t CountHelper(bool without_pc) {
552 size_t tmp;
553 if (std::is_same<T1, arm::Register>::value) {
554 tmp = GetRegisters().size();
555 if (without_pc) {
556 tmp--;; // Approximation...
557 }
558 } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
559 tmp = GetShiftOperands().size();
560 } else if (std::is_same<T1, arm::Condition>::value) {
561 tmp = GetConditions().size();
562 } else {
563 LOG(WARNING) << "Unknown type while counting.";
564 tmp = 1;
565 }
566 size_t rec = CountHelper<T2, Args...>(without_pc);
567 return rec * tmp;
568 }
569
570 bool first_;
571
572 static constexpr const char* kArm32AssemblyHeader = ".arm\n";
573
Roland Levillain1a28fc42014-11-13 18:03:06 +0000574 std::vector<arm::Register*> registers_;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800575 std::vector<arm::Condition> conditions_;
576 std::vector<arm::ShifterOperand> shifter_operands_;
Roland Levillain1a28fc42014-11-13 18:03:06 +0000577};
578
579
580TEST_F(AssemblerArm32Test, Toolchain) {
581 EXPECT_TRUE(CheckTools());
582}
583
Roland Levillain1a28fc42014-11-13 18:03:06 +0000584TEST_F(AssemblerArm32Test, Sbfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800585 std::vector<std::pair<uint32_t, uint32_t>> immediates;
586 immediates.push_back({0, 1});
587 immediates.push_back({0, 8});
588 immediates.push_back({0, 15});
589 immediates.push_back({0, 16});
590 immediates.push_back({0, 31});
591 immediates.push_back({0, 32});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000592
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800593 immediates.push_back({1, 1});
594 immediates.push_back({1, 15});
595 immediates.push_back({1, 31});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000596
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800597 immediates.push_back({8, 1});
598 immediates.push_back({8, 15});
599 immediates.push_back({8, 16});
600 immediates.push_back({8, 24});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000601
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800602 immediates.push_back({31, 1});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000603
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800604 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
605 "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
Roland Levillain1a28fc42014-11-13 18:03:06 +0000606}
607
Roland Levillain981e4542014-11-14 11:47:14 +0000608TEST_F(AssemblerArm32Test, Ubfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800609 std::vector<std::pair<uint32_t, uint32_t>> immediates;
610 immediates.push_back({0, 1});
611 immediates.push_back({0, 8});
612 immediates.push_back({0, 15});
613 immediates.push_back({0, 16});
614 immediates.push_back({0, 31});
615 immediates.push_back({0, 32});
Roland Levillain981e4542014-11-14 11:47:14 +0000616
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800617 immediates.push_back({1, 1});
618 immediates.push_back({1, 15});
619 immediates.push_back({1, 31});
Roland Levillain981e4542014-11-14 11:47:14 +0000620
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800621 immediates.push_back({8, 1});
622 immediates.push_back({8, 15});
623 immediates.push_back({8, 16});
624 immediates.push_back({8, 24});
Roland Levillain981e4542014-11-14 11:47:14 +0000625
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800626 immediates.push_back({31, 1});
Roland Levillain981e4542014-11-14 11:47:14 +0000627
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800628 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
629 "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
630}
Roland Levillain981e4542014-11-14 11:47:14 +0000631
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800632TEST_F(AssemblerArm32Test, Mul) {
633 T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
634}
Roland Levillain981e4542014-11-14 11:47:14 +0000635
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800636TEST_F(AssemblerArm32Test, Mla) {
Zheng Xuc6667102015-05-15 16:08:45 +0800637 T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800638}
Roland Levillain981e4542014-11-14 11:47:14 +0000639
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800640TEST_F(AssemblerArm32Test, Umull) {
641 T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
Zheng Xuc6667102015-05-15 16:08:45 +0800642 "umull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800643}
Zheng Xuc6667102015-05-15 16:08:45 +0800644
645TEST_F(AssemblerArm32Test, Smull) {
646 T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
647 "smull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
648}
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800649
650TEST_F(AssemblerArm32Test, Sdiv) {
651 T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
652}
653
654TEST_F(AssemblerArm32Test, Udiv) {
655 T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
656}
657
658TEST_F(AssemblerArm32Test, And) {
659 T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and");
660}
661
662TEST_F(AssemblerArm32Test, Eor) {
663 T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor");
664}
665
666TEST_F(AssemblerArm32Test, Orr) {
667 T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr");
668}
669
670TEST_F(AssemblerArm32Test, Orrs) {
671 T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
672}
673
674TEST_F(AssemblerArm32Test, Bic) {
675 T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic");
676}
677
678TEST_F(AssemblerArm32Test, Mov) {
679 T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov");
680}
681
682TEST_F(AssemblerArm32Test, Movs) {
683 T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
684}
685
686TEST_F(AssemblerArm32Test, Mvn) {
687 T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn");
688}
689
690TEST_F(AssemblerArm32Test, Mvns) {
691 T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
692}
693
694TEST_F(AssemblerArm32Test, Add) {
695 T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add");
696}
697
698TEST_F(AssemblerArm32Test, Adds) {
699 T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
700}
701
702TEST_F(AssemblerArm32Test, Adc) {
703 T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc");
704}
705
706TEST_F(AssemblerArm32Test, Sub) {
707 T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub");
708}
709
710TEST_F(AssemblerArm32Test, Subs) {
711 T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
712}
713
714TEST_F(AssemblerArm32Test, Sbc) {
715 T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc");
716}
717
718TEST_F(AssemblerArm32Test, Rsb) {
719 T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb");
720}
721
722TEST_F(AssemblerArm32Test, Rsbs) {
723 T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
724}
725
726TEST_F(AssemblerArm32Test, Rsc) {
727 T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
728}
729
Zheng Xuc6667102015-05-15 16:08:45 +0800730/* TODO: Need better filter support.
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800731TEST_F(AssemblerArm32Test, Strex) {
Zheng Xuc6667102015-05-15 16:08:45 +0800732 T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
733 "{reg1}={reg2}||{reg1}={reg3}"); // Skip the cases where reg1 == reg2 || reg1 == reg3.
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800734}
735*/
736
737TEST_F(AssemblerArm32Test, Clz) {
738 T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
739}
740
741TEST_F(AssemblerArm32Test, Tst) {
742 T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
743}
744
745TEST_F(AssemblerArm32Test, Teq) {
746 T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
747}
748
749TEST_F(AssemblerArm32Test, Cmp) {
750 T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
751}
752
753TEST_F(AssemblerArm32Test, Cmn) {
754 T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
755}
756
757TEST_F(AssemblerArm32Test, Blx) {
758 T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
759}
760
761TEST_F(AssemblerArm32Test, Bx) {
762 T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
Roland Levillain981e4542014-11-14 11:47:14 +0000763}
764
Calin Juravleddb7df22014-11-25 20:56:51 +0000765TEST_F(AssemblerArm32Test, Vmstat) {
766 GetAssembler()->vmstat();
767
768 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
769
770 DriverStr(expected, "vmrs");
771}
772
Calin Juravle52c48962014-12-16 17:02:57 +0000773TEST_F(AssemblerArm32Test, ldrexd) {
774 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
775 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
776 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
777
778 const char* expected =
779 "ldrexd r0, r1, [r0]\n"
780 "ldrexd r0, r1, [r1]\n"
781 "ldrexd r0, r1, [r2]\n";
782 DriverStr(expected, "ldrexd");
783}
784
785TEST_F(AssemblerArm32Test, strexd) {
786 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
787 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
788 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
789
790 const char* expected =
791 "strexd r9, r0, r1, [r0]\n"
792 "strexd r9, r0, r1, [r1]\n"
793 "strexd r9, r0, r1, [r2]\n";
794 DriverStr(expected, "strexd");
795}
796
Roland Levillain1a28fc42014-11-13 18:03:06 +0000797} // namespace art