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_arm32.h"
18
19 #include <functional>
20 #include <type_traits>
21
22 #include "base/macros.h"
23 #include "base/stl_util.h"
24 #include "utils/arm/assembler_arm_test.h"
25
26 namespace art {
27
28 using std::placeholders::_1;
29 using std::placeholders::_2;
30 using std::placeholders::_3;
31 using std::placeholders::_4;
32 using std::placeholders::_5;
33
34 // To speed up tests, don't use all register combinations.
35 static constexpr bool kUseSparseRegisterList = true;
36
37 // To speed up tests, don't use all condition codes.
38 static constexpr bool kUseSparseConditionList = true;
39
40 // To speed up tests, don't use all shift immediates.
41 static constexpr bool kUseSparseShiftImmediates = true;
42
43 class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler,
44 arm::Register, arm::SRegister,
45 uint32_t, arm::ShifterOperand, arm::Condition,
46 arm::SetCc> {
47 protected:
GetArchitectureString()48 std::string GetArchitectureString() OVERRIDE {
49 return "arm";
50 }
51
GetAssemblerParameters()52 std::string GetAssemblerParameters() OVERRIDE {
53 // Arm-v7a, cortex-a15 (means we have sdiv).
54 return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
55 }
56
GetAssemblyHeader()57 const char* GetAssemblyHeader() OVERRIDE {
58 return kArm32AssemblyHeader;
59 }
60
GetDisassembleParameters()61 std::string GetDisassembleParameters() OVERRIDE {
62 return " -D -bbinary -marm --no-show-raw-insn";
63 }
64
SetUpHelpers()65 void SetUpHelpers() OVERRIDE {
66 if (registers_.size() == 0) {
67 if (kUseSparseRegisterList) {
68 registers_.insert(end(registers_),
69 { // NOLINT(whitespace/braces)
70 new arm::Register(arm::R0),
71 new arm::Register(arm::R1),
72 new arm::Register(arm::R4),
73 new arm::Register(arm::R8),
74 new arm::Register(arm::R11),
75 new arm::Register(arm::R12),
76 new arm::Register(arm::R13),
77 new arm::Register(arm::R14),
78 new arm::Register(arm::R15)
79 });
80 } else {
81 registers_.insert(end(registers_),
82 { // NOLINT(whitespace/braces)
83 new arm::Register(arm::R0),
84 new arm::Register(arm::R1),
85 new arm::Register(arm::R2),
86 new arm::Register(arm::R3),
87 new arm::Register(arm::R4),
88 new arm::Register(arm::R5),
89 new arm::Register(arm::R6),
90 new arm::Register(arm::R7),
91 new arm::Register(arm::R8),
92 new arm::Register(arm::R9),
93 new arm::Register(arm::R10),
94 new arm::Register(arm::R11),
95 new arm::Register(arm::R12),
96 new arm::Register(arm::R13),
97 new arm::Register(arm::R14),
98 new arm::Register(arm::R15)
99 });
100 }
101 }
102
103 if (!kUseSparseConditionList) {
104 conditions_.push_back(arm::Condition::EQ);
105 conditions_.push_back(arm::Condition::NE);
106 conditions_.push_back(arm::Condition::CS);
107 conditions_.push_back(arm::Condition::CC);
108 conditions_.push_back(arm::Condition::MI);
109 conditions_.push_back(arm::Condition::PL);
110 conditions_.push_back(arm::Condition::VS);
111 conditions_.push_back(arm::Condition::VC);
112 conditions_.push_back(arm::Condition::HI);
113 conditions_.push_back(arm::Condition::LS);
114 conditions_.push_back(arm::Condition::GE);
115 conditions_.push_back(arm::Condition::LT);
116 conditions_.push_back(arm::Condition::GT);
117 conditions_.push_back(arm::Condition::LE);
118 conditions_.push_back(arm::Condition::AL);
119 } else {
120 conditions_.push_back(arm::Condition::EQ);
121 conditions_.push_back(arm::Condition::NE);
122 conditions_.push_back(arm::Condition::CC);
123 conditions_.push_back(arm::Condition::VC);
124 conditions_.push_back(arm::Condition::HI);
125 conditions_.push_back(arm::Condition::LT);
126 conditions_.push_back(arm::Condition::AL);
127 }
128
129 set_ccs_.push_back(arm::kCcDontCare);
130 set_ccs_.push_back(arm::kCcSet);
131 set_ccs_.push_back(arm::kCcKeep);
132
133 shifter_operands_.push_back(arm::ShifterOperand(0));
134 shifter_operands_.push_back(arm::ShifterOperand(1));
135 shifter_operands_.push_back(arm::ShifterOperand(2));
136 shifter_operands_.push_back(arm::ShifterOperand(3));
137 shifter_operands_.push_back(arm::ShifterOperand(4));
138 shifter_operands_.push_back(arm::ShifterOperand(5));
139 shifter_operands_.push_back(arm::ShifterOperand(127));
140 shifter_operands_.push_back(arm::ShifterOperand(128));
141 shifter_operands_.push_back(arm::ShifterOperand(254));
142 shifter_operands_.push_back(arm::ShifterOperand(255));
143
144 if (!kUseSparseRegisterList) {
145 shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
146 shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
147 shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
148 shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
149 shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
150 shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
151 shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
152 shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
153 shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
154 shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
155 shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
156 shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
157 shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
158 shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
159 } else {
160 shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
161 shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
162 shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
163 shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
164 shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
165 shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
166 shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
167 }
168
169 std::vector<arm::Shift> shifts {
170 arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
171 };
172
173 // ShifterOperands of form "reg shift-type imm."
174 for (arm::Shift shift : shifts) {
175 for (arm::Register* reg : registers_) { // Note: this will pick up the sparse set.
176 if (*reg == arm::R15) { // Skip PC.
177 continue;
178 }
179 if (shift != arm::Shift::RRX) {
180 if (!kUseSparseShiftImmediates) {
181 for (uint32_t imm = 1; imm < 32; ++imm) {
182 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
183 }
184 } else {
185 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
186 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
187 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
188 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
189 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
190 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
191 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
192 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
193 }
194 } else {
195 // RRX doesn't have an immediate.
196 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
197 }
198 }
199 }
200 }
201
CreateRegisterShifts(std::vector<arm::Register * > & base_regs,int32_t shift_min,int32_t shift_max)202 std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
203 int32_t shift_min, int32_t shift_max) {
204 std::vector<arm::ShifterOperand> res;
205 static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
206 arm::Shift::ROR };
207
208 for (arm::Shift shift : kShifts) {
209 for (arm::Register* reg : base_regs) {
210 // Take the min, the max, and three values in between.
211 res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
212 if (shift_min != shift_max) {
213 res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
214 int32_t middle = (shift_min + shift_max) / 2;
215 res.push_back(arm::ShifterOperand(*reg, shift, middle));
216 res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
217 res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
218 }
219 }
220 }
221
222 return res;
223 }
224
TearDown()225 void TearDown() OVERRIDE {
226 AssemblerArmTest::TearDown();
227 STLDeleteElements(®isters_);
228 }
229
GetRegisters()230 std::vector<arm::Register*> GetRegisters() OVERRIDE {
231 return registers_;
232 }
233
CreateImmediate(int64_t imm_value)234 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
235 return imm_value;
236 }
237
GetConditions()238 std::vector<arm::Condition>& GetConditions() OVERRIDE {
239 return conditions_;
240 }
241
GetConditionString(arm::Condition c)242 std::string GetConditionString(arm::Condition c) OVERRIDE {
243 std::ostringstream oss;
244 oss << c;
245 return oss.str();
246 }
247
GetSetCcs()248 std::vector<arm::SetCc>& GetSetCcs() OVERRIDE {
249 return set_ccs_;
250 }
251
GetSetCcString(arm::SetCc s)252 std::string GetSetCcString(arm::SetCc s) OVERRIDE {
253 // For arm32, kCcDontCare defaults to not setting condition codes.
254 return s == arm::kCcSet ? "s" : "";
255 }
256
GetPCRegister()257 arm::Register GetPCRegister() OVERRIDE {
258 return arm::R15;
259 }
260
GetShiftOperands()261 std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
262 return shifter_operands_;
263 }
264
GetShiftString(arm::ShifterOperand sop)265 std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
266 std::ostringstream oss;
267 if (sop.IsShift()) {
268 // Not a rotate...
269 if (sop.GetShift() == arm::Shift::RRX) {
270 oss << sop.GetRegister() << ", " << sop.GetShift();
271 } else {
272 oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
273 }
274 } else if (sop.IsRegister()) {
275 oss << sop.GetRegister();
276 } else {
277 CHECK(sop.IsImmediate());
278 oss << "#" << sop.GetImmediate();
279 }
280 return oss.str();
281 }
282
GetRegTokenFromDepth(int depth)283 static const char* GetRegTokenFromDepth(int depth) {
284 switch (depth) {
285 case 0:
286 return Base::REG1_TOKEN;
287 case 1:
288 return Base::REG2_TOKEN;
289 case 2:
290 return Base::REG3_TOKEN;
291 case 3:
292 return REG4_TOKEN;
293 default:
294 LOG(FATAL) << "Depth problem.";
295 UNREACHABLE();
296 }
297 }
298
ExecuteAndPrint(std::function<void ()> f,std::string fmt,std::ostringstream & oss)299 void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
300 if (first_) {
301 first_ = false;
302 } else {
303 oss << "\n";
304 }
305 oss << fmt;
306
307 f();
308 }
309
310 // NOTE: Only support simple test like "aaa=bbb"
EvalFilterString(std::string filter)311 bool EvalFilterString(std::string filter) {
312 if (filter.compare("") == 0) {
313 return false;
314 }
315
316 size_t equal_sign_index = filter.find('=');
317 if (equal_sign_index == std::string::npos) {
318 EXPECT_TRUE(false) << "Unsupported filter string.";
319 }
320
321 std::string lhs = filter.substr(0, equal_sign_index);
322 std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
323 return lhs.compare(rhs) == 0;
324 }
325
TemplateHelper(std::function<void (arm::Register)> f,int depth ATTRIBUTE_UNUSED,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)326 void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
327 bool without_pc, std::string fmt, std::string filter,
328 std::ostringstream& oss) {
329 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
330 for (auto reg : registers) {
331 std::string after_reg = fmt;
332 std::string after_reg_filter = filter;
333
334 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
335 size_t reg_index;
336 const char* reg_token = GetRegTokenFromDepth(depth);
337
338 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
339 after_reg.replace(reg_index, strlen(reg_token), reg_string);
340 }
341
342 while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
343 after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
344 }
345 if (EvalFilterString(after_reg_filter)) {
346 continue;
347 }
348
349 ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
350 }
351 }
352
TemplateHelper(std::function<void (const arm::ShifterOperand &)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::string filter,std::ostringstream & oss)353 void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
354 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
355 std::ostringstream& oss) {
356 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
357 std::string after_shift = fmt;
358 std::string after_shift_filter = filter;
359
360 std::string shift_string = GetShiftString(shift);
361 size_t shift_index;
362 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
363 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
364 }
365
366 while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
367 after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
368 }
369 if (EvalFilterString(after_shift_filter)) {
370 continue;
371 }
372
373 ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
374 }
375 }
376
TemplateHelper(std::function<void (arm::Condition)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::string filter,std::ostringstream & oss)377 void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
378 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
379 std::ostringstream& oss) {
380 for (arm::Condition c : GetConditions()) {
381 std::string after_cond = fmt;
382 std::string after_cond_filter = filter;
383
384 size_t cond_index = after_cond.find(COND_TOKEN);
385 if (cond_index != std::string::npos) {
386 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
387 }
388
389 cond_index = after_cond_filter.find(COND_TOKEN);
390 if (cond_index != std::string::npos) {
391 after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
392 }
393 if (EvalFilterString(after_cond_filter)) {
394 continue;
395 }
396
397 ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
398 }
399 }
400
TemplateHelper(std::function<void (arm::SetCc)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::string filter,std::ostringstream & oss)401 void TemplateHelper(std::function<void(arm::SetCc)> f, int depth ATTRIBUTE_UNUSED,
402 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
403 std::ostringstream& oss) {
404 for (arm::SetCc s : GetSetCcs()) {
405 std::string after_cond = fmt;
406 std::string after_cond_filter = filter;
407
408 size_t cond_index = after_cond.find(SET_CC_TOKEN);
409 if (cond_index != std::string::npos) {
410 after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
411 }
412
413 cond_index = after_cond_filter.find(SET_CC_TOKEN);
414 if (cond_index != std::string::npos) {
415 after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
416 }
417 if (EvalFilterString(after_cond_filter)) {
418 continue;
419 }
420
421 ExecuteAndPrint([&] () { f(s); }, after_cond, oss);
422 }
423 }
424
425 template <typename... Args>
TemplateHelper(std::function<void (arm::Register,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)426 void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
427 std::string fmt, std::string filter, std::ostringstream& oss) {
428 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
429 for (auto reg : registers) {
430 std::string after_reg = fmt;
431 std::string after_reg_filter = filter;
432
433 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
434 size_t reg_index;
435 const char* reg_token = GetRegTokenFromDepth(depth);
436
437 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
438 after_reg.replace(reg_index, strlen(reg_token), reg_string);
439 }
440
441 while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
442 after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
443 }
444 if (EvalFilterString(after_reg_filter)) {
445 continue;
446 }
447
448 auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
449 TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
450 after_reg, after_reg_filter, oss);
451 }
452 }
453
454 template <typename... Args>
TemplateHelper(std::function<void (const arm::ShifterOperand &,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)455 void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
456 bool without_pc, std::string fmt, std::string filter,
457 std::ostringstream& oss) {
458 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
459 std::string after_shift = fmt;
460 std::string after_shift_filter = filter;
461
462 std::string shift_string = GetShiftString(shift);
463 size_t shift_index;
464 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
465 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
466 }
467
468 while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
469 after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
470 }
471 if (EvalFilterString(after_shift_filter)) {
472 continue;
473 }
474
475 auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
476 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
477 after_shift, after_shift_filter, oss);
478 }
479 }
480
481 template <typename... Args>
TemplateHelper(std::function<void (arm::Condition,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)482 void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
483 std::string fmt, std::string filter, std::ostringstream& oss) {
484 for (arm::Condition c : GetConditions()) {
485 std::string after_cond = fmt;
486 std::string after_cond_filter = filter;
487
488 size_t cond_index = after_cond.find(COND_TOKEN);
489 if (cond_index != std::string::npos) {
490 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
491 }
492
493 cond_index = after_cond_filter.find(COND_TOKEN);
494 if (cond_index != std::string::npos) {
495 after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
496 }
497 if (EvalFilterString(after_cond_filter)) {
498 continue;
499 }
500
501 auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
502 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
503 after_cond, after_cond_filter, oss);
504 }
505 }
506
507 template <typename... Args>
TemplateHelper(std::function<void (arm::SetCc,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)508 void TemplateHelper(std::function<void(arm::SetCc, Args...)> f, int depth, bool without_pc,
509 std::string fmt, std::string filter, std::ostringstream& oss) {
510 for (arm::SetCc s : GetSetCcs()) {
511 std::string after_cond = fmt;
512 std::string after_cond_filter = filter;
513
514 size_t cond_index = after_cond.find(SET_CC_TOKEN);
515 if (cond_index != std::string::npos) {
516 after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
517 }
518
519 cond_index = after_cond_filter.find(SET_CC_TOKEN);
520 if (cond_index != std::string::npos) {
521 after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
522 }
523 if (EvalFilterString(after_cond_filter)) {
524 continue;
525 }
526
527 auto lambda = [&] (Args... args) { f(s, args...); }; // NOLINT [readability/braces] [4]
528 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
529 after_cond, after_cond_filter, oss);
530 }
531 }
532
533 template <typename Assembler, typename T1, typename T2>
GetBoundFunction2(void (Assembler::* f)(T1,T2))534 std::function<void(T1, T2)> GetBoundFunction2(void (Assembler::*f)(T1, T2)) {
535 return std::bind(f, GetAssembler(), _1, _2);
536 }
537
538 template <typename Assembler, typename T1, typename T2, typename T3>
GetBoundFunction3(void (Assembler::* f)(T1,T2,T3))539 std::function<void(T1, T2, T3)> GetBoundFunction3(void (Assembler::*f)(T1, T2, T3)) {
540 return std::bind(f, GetAssembler(), _1, _2, _3);
541 }
542
543 template <typename Assembler, typename T1, typename T2, typename T3, typename T4>
GetBoundFunction4(void (Assembler::* f)(T1,T2,T3,T4))544 std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
545 void (Assembler::*f)(T1, T2, T3, T4)) {
546 return std::bind(f, GetAssembler(), _1, _2, _3, _4);
547 }
548
549 template <typename Assembler, typename T1, typename T2, typename T3, typename T4, typename T5>
GetBoundFunction5(void (Assembler::* f)(T1,T2,T3,T4,T5))550 std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
551 void (Assembler::*f)(T1, T2, T3, T4, T5)) {
552 return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
553 }
554
555 template <typename... Args>
GenericTemplateHelper(std::function<void (Args...)> f,bool without_pc,std::string fmt,std::string test_name,std::string filter)556 void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
557 std::string fmt, std::string test_name, std::string filter) {
558 first_ = false;
559 WarnOnCombinations(CountHelper<Args...>(without_pc));
560
561 std::ostringstream oss;
562
563 TemplateHelper(f, 0, without_pc, fmt, filter, oss);
564
565 oss << "\n"; // Trailing newline.
566
567 DriverStr(oss.str(), test_name);
568 }
569
570 template <typename Assembler, typename... Args>
T2Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")571 void T2Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
572 std::string test_name, std::string filter = "") {
573 GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
574 }
575
576 template <typename Assembler, typename... Args>
T3Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")577 void T3Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
578 std::string test_name, std::string filter = "") {
579 GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
580 }
581
582 template <typename Assembler, typename... Args>
T4Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")583 void T4Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
584 std::string test_name, std::string filter = "") {
585 GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
586 }
587
588 template <typename Assembler, typename... Args>
T5Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")589 void T5Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
590 std::string test_name, std::string filter = "") {
591 GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
592 }
593
594 private:
595 template <typename T>
CountHelper(bool without_pc)596 size_t CountHelper(bool without_pc) {
597 size_t tmp;
598 if (std::is_same<T, arm::Register>::value) {
599 tmp = GetRegisters().size();
600 if (without_pc) {
601 tmp--;; // Approximation...
602 }
603 return tmp;
604 } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
605 return GetShiftOperands().size();
606 } else if (std::is_same<T, arm::Condition>::value) {
607 return GetConditions().size();
608 } else {
609 LOG(WARNING) << "Unknown type while counting.";
610 return 1;
611 }
612 }
613
614 template <typename T1, typename T2, typename... Args>
CountHelper(bool without_pc)615 size_t CountHelper(bool without_pc) {
616 size_t tmp;
617 if (std::is_same<T1, arm::Register>::value) {
618 tmp = GetRegisters().size();
619 if (without_pc) {
620 tmp--;; // Approximation...
621 }
622 } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
623 tmp = GetShiftOperands().size();
624 } else if (std::is_same<T1, arm::Condition>::value) {
625 tmp = GetConditions().size();
626 } else {
627 LOG(WARNING) << "Unknown type while counting.";
628 tmp = 1;
629 }
630 size_t rec = CountHelper<T2, Args...>(without_pc);
631 return rec * tmp;
632 }
633
634 bool first_;
635
636 static constexpr const char* kArm32AssemblyHeader = ".arm\n";
637
638 std::vector<arm::Register*> registers_;
639 std::vector<arm::Condition> conditions_;
640 std::vector<arm::SetCc> set_ccs_;
641 std::vector<arm::ShifterOperand> shifter_operands_;
642 };
643
644
TEST_F(AssemblerArm32Test,Toolchain)645 TEST_F(AssemblerArm32Test, Toolchain) {
646 EXPECT_TRUE(CheckTools());
647 }
648
TEST_F(AssemblerArm32Test,Sbfx)649 TEST_F(AssemblerArm32Test, Sbfx) {
650 std::vector<std::pair<uint32_t, uint32_t>> immediates;
651 immediates.push_back({0, 1});
652 immediates.push_back({0, 8});
653 immediates.push_back({0, 15});
654 immediates.push_back({0, 16});
655 immediates.push_back({0, 31});
656 immediates.push_back({0, 32});
657
658 immediates.push_back({1, 1});
659 immediates.push_back({1, 15});
660 immediates.push_back({1, 31});
661
662 immediates.push_back({8, 1});
663 immediates.push_back({8, 15});
664 immediates.push_back({8, 16});
665 immediates.push_back({8, 24});
666
667 immediates.push_back({31, 1});
668
669 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
670 "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
671 }
672
TEST_F(AssemblerArm32Test,Ubfx)673 TEST_F(AssemblerArm32Test, Ubfx) {
674 std::vector<std::pair<uint32_t, uint32_t>> immediates;
675 immediates.push_back({0, 1});
676 immediates.push_back({0, 8});
677 immediates.push_back({0, 15});
678 immediates.push_back({0, 16});
679 immediates.push_back({0, 31});
680 immediates.push_back({0, 32});
681
682 immediates.push_back({1, 1});
683 immediates.push_back({1, 15});
684 immediates.push_back({1, 31});
685
686 immediates.push_back({8, 1});
687 immediates.push_back({8, 15});
688 immediates.push_back({8, 16});
689 immediates.push_back({8, 24});
690
691 immediates.push_back({31, 1});
692
693 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
694 "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
695 }
696
TEST_F(AssemblerArm32Test,Mul)697 TEST_F(AssemblerArm32Test, Mul) {
698 T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
699 }
700
TEST_F(AssemblerArm32Test,Mla)701 TEST_F(AssemblerArm32Test, Mla) {
702 T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
703 }
704
TEST_F(AssemblerArm32Test,Umull)705 TEST_F(AssemblerArm32Test, Umull) {
706 T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
707 "umull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
708 }
709
TEST_F(AssemblerArm32Test,Smull)710 TEST_F(AssemblerArm32Test, Smull) {
711 T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
712 "smull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
713 }
714
TEST_F(AssemblerArm32Test,Sdiv)715 TEST_F(AssemblerArm32Test, Sdiv) {
716 T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
717 }
718
TEST_F(AssemblerArm32Test,Udiv)719 TEST_F(AssemblerArm32Test, Udiv) {
720 T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
721 }
722
TEST_F(AssemblerArm32Test,And)723 TEST_F(AssemblerArm32Test, And) {
724 T5Helper(&arm::Arm32Assembler::and_, true, "and{cond}{s} {reg1}, {reg2}, {shift}", "and");
725 }
726
TEST_F(AssemblerArm32Test,Ands)727 TEST_F(AssemblerArm32Test, Ands) {
728 T4Helper(&arm::Arm32Assembler::ands, true, "and{cond}s {reg1}, {reg2}, {shift}", "ands");
729 }
730
TEST_F(AssemblerArm32Test,Eor)731 TEST_F(AssemblerArm32Test, Eor) {
732 T5Helper(&arm::Arm32Assembler::eor, true, "eor{cond}{s} {reg1}, {reg2}, {shift}", "eor");
733 }
734
TEST_F(AssemblerArm32Test,Eors)735 TEST_F(AssemblerArm32Test, Eors) {
736 T4Helper(&arm::Arm32Assembler::eors, true, "eor{cond}s {reg1}, {reg2}, {shift}", "eors");
737 }
738
TEST_F(AssemblerArm32Test,Orr)739 TEST_F(AssemblerArm32Test, Orr) {
740 T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr");
741 }
742
TEST_F(AssemblerArm32Test,Orrs)743 TEST_F(AssemblerArm32Test, Orrs) {
744 T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
745 }
746
TEST_F(AssemblerArm32Test,Bic)747 TEST_F(AssemblerArm32Test, Bic) {
748 T5Helper(&arm::Arm32Assembler::bic, true, "bic{cond}{s} {reg1}, {reg2}, {shift}", "bic");
749 }
750
TEST_F(AssemblerArm32Test,Bics)751 TEST_F(AssemblerArm32Test, Bics) {
752 T4Helper(&arm::Arm32Assembler::bics, true, "bic{cond}s {reg1}, {reg2}, {shift}", "bics");
753 }
754
TEST_F(AssemblerArm32Test,Mov)755 TEST_F(AssemblerArm32Test, Mov) {
756 T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov");
757 }
758
TEST_F(AssemblerArm32Test,Movs)759 TEST_F(AssemblerArm32Test, Movs) {
760 T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
761 }
762
TEST_F(AssemblerArm32Test,Mvn)763 TEST_F(AssemblerArm32Test, Mvn) {
764 T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn");
765 }
766
TEST_F(AssemblerArm32Test,Mvns)767 TEST_F(AssemblerArm32Test, Mvns) {
768 T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
769 }
770
TEST_F(AssemblerArm32Test,Add)771 TEST_F(AssemblerArm32Test, Add) {
772 T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add");
773 }
774
TEST_F(AssemblerArm32Test,Adds)775 TEST_F(AssemblerArm32Test, Adds) {
776 T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
777 }
778
TEST_F(AssemblerArm32Test,Adc)779 TEST_F(AssemblerArm32Test, Adc) {
780 T5Helper(&arm::Arm32Assembler::adc, false, "adc{cond}{s} {reg1}, {reg2}, {shift}", "adc");
781 }
782
TEST_F(AssemblerArm32Test,Adcs)783 TEST_F(AssemblerArm32Test, Adcs) {
784 T4Helper(&arm::Arm32Assembler::adcs, false, "adc{cond}s {reg1}, {reg2}, {shift}", "adcs");
785 }
786
TEST_F(AssemblerArm32Test,Sub)787 TEST_F(AssemblerArm32Test, Sub) {
788 T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub");
789 }
790
TEST_F(AssemblerArm32Test,Subs)791 TEST_F(AssemblerArm32Test, Subs) {
792 T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
793 }
794
TEST_F(AssemblerArm32Test,Sbc)795 TEST_F(AssemblerArm32Test, Sbc) {
796 T5Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond}{s} {reg1}, {reg2}, {shift}", "sbc");
797 }
798
TEST_F(AssemblerArm32Test,Sbcs)799 TEST_F(AssemblerArm32Test, Sbcs) {
800 T4Helper(&arm::Arm32Assembler::sbcs, false, "sbc{cond}s {reg1}, {reg2}, {shift}", "sbcs");
801 }
802
TEST_F(AssemblerArm32Test,Rsb)803 TEST_F(AssemblerArm32Test, Rsb) {
804 T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb");
805 }
806
TEST_F(AssemblerArm32Test,Rsbs)807 TEST_F(AssemblerArm32Test, Rsbs) {
808 T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
809 }
810
TEST_F(AssemblerArm32Test,Rsc)811 TEST_F(AssemblerArm32Test, Rsc) {
812 T5Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond}{s} {reg1}, {reg2}, {shift}", "rsc");
813 }
814
TEST_F(AssemblerArm32Test,Rscs)815 TEST_F(AssemblerArm32Test, Rscs) {
816 T4Helper(&arm::Arm32Assembler::rscs, false, "rsc{cond}s {reg1}, {reg2}, {shift}", "rscs");
817 }
818
819 /* TODO: Need better filter support.
820 TEST_F(AssemblerArm32Test, Strex) {
821 T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
822 "{reg1}={reg2}||{reg1}={reg3}"); // Skip the cases where reg1 == reg2 || reg1 == reg3.
823 }
824 */
825
TEST_F(AssemblerArm32Test,Clz)826 TEST_F(AssemblerArm32Test, Clz) {
827 T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
828 }
829
TEST_F(AssemblerArm32Test,Tst)830 TEST_F(AssemblerArm32Test, Tst) {
831 T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
832 }
833
TEST_F(AssemblerArm32Test,Teq)834 TEST_F(AssemblerArm32Test, Teq) {
835 T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
836 }
837
TEST_F(AssemblerArm32Test,Cmp)838 TEST_F(AssemblerArm32Test, Cmp) {
839 T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
840 }
841
TEST_F(AssemblerArm32Test,Cmn)842 TEST_F(AssemblerArm32Test, Cmn) {
843 T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
844 }
845
TEST_F(AssemblerArm32Test,Blx)846 TEST_F(AssemblerArm32Test, Blx) {
847 T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
848 }
849
TEST_F(AssemblerArm32Test,Bx)850 TEST_F(AssemblerArm32Test, Bx) {
851 T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
852 }
853
TEST_F(AssemblerArm32Test,Vmstat)854 TEST_F(AssemblerArm32Test, Vmstat) {
855 GetAssembler()->vmstat();
856
857 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
858
859 DriverStr(expected, "vmrs");
860 }
861
TEST_F(AssemblerArm32Test,ldrexd)862 TEST_F(AssemblerArm32Test, ldrexd) {
863 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
864 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
865 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
866
867 const char* expected =
868 "ldrexd r0, r1, [r0]\n"
869 "ldrexd r0, r1, [r1]\n"
870 "ldrexd r0, r1, [r2]\n";
871 DriverStr(expected, "ldrexd");
872 }
873
TEST_F(AssemblerArm32Test,strexd)874 TEST_F(AssemblerArm32Test, strexd) {
875 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
876 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
877 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
878
879 const char* expected =
880 "strexd r9, r0, r1, [r0]\n"
881 "strexd r9, r0, r1, [r1]\n"
882 "strexd r9, r0, r1, [r2]\n";
883 DriverStr(expected, "strexd");
884 }
885
TEST_F(AssemblerArm32Test,rbit)886 TEST_F(AssemblerArm32Test, rbit) {
887 T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit");
888 }
889
TEST_F(AssemblerArm32Test,rev)890 TEST_F(AssemblerArm32Test, rev) {
891 T3Helper(&arm::Arm32Assembler::rev, true, "rev{cond} {reg1}, {reg2}", "rev");
892 }
893
TEST_F(AssemblerArm32Test,rev16)894 TEST_F(AssemblerArm32Test, rev16) {
895 T3Helper(&arm::Arm32Assembler::rev16, true, "rev16{cond} {reg1}, {reg2}", "rev16");
896 }
897
TEST_F(AssemblerArm32Test,revsh)898 TEST_F(AssemblerArm32Test, revsh) {
899 T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh");
900 }
901
902 } // namespace art
903