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 protected:
GetArchitectureString()47 std::string GetArchitectureString() OVERRIDE {
48 return "arm";
49 }
50
GetAssemblerParameters()51 std::string GetAssemblerParameters() OVERRIDE {
52 // Arm-v7a, cortex-a15 (means we have sdiv).
53 return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
54 }
55
GetAssemblyHeader()56 const char* GetAssemblyHeader() OVERRIDE {
57 return kArm32AssemblyHeader;
58 }
59
GetDisassembleParameters()60 std::string GetDisassembleParameters() OVERRIDE {
61 return " -D -bbinary -marm --no-show-raw-insn";
62 }
63
SetUpHelpers()64 void SetUpHelpers() OVERRIDE {
65 if (registers_.size() == 0) {
66 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 }
194 }
195 }
196
CreateRegisterShifts(std::vector<arm::Register * > & base_regs,int32_t shift_min,int32_t shift_max)197 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
TearDown()220 void TearDown() OVERRIDE {
221 AssemblerArmTest::TearDown();
222 STLDeleteElements(®isters_);
223 }
224
GetRegisters()225 std::vector<arm::Register*> GetRegisters() OVERRIDE {
226 return registers_;
227 }
228
CreateImmediate(int64_t imm_value)229 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
230 return imm_value;
231 }
232
GetConditions()233 std::vector<arm::Condition>& GetConditions() OVERRIDE {
234 return conditions_;
235 }
236
GetConditionString(arm::Condition c)237 std::string GetConditionString(arm::Condition c) OVERRIDE {
238 std::ostringstream oss;
239 oss << c;
240 return oss.str();
241 }
242
GetPCRegister()243 arm::Register GetPCRegister() OVERRIDE {
244 return arm::R15;
245 }
246
GetShiftOperands()247 std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
248 return shifter_operands_;
249 }
250
GetShiftString(arm::ShifterOperand sop)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
GetRegTokenFromDepth(int depth)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
ExecuteAndPrint(std::function<void ()> f,std::string fmt,std::ostringstream & oss)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
TemplateHelper(std::function<void (arm::Register)> f,int depth ATTRIBUTE_UNUSED,bool without_pc,std::string fmt,std::ostringstream & oss)296 void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
297 bool without_pc,
298 std::string fmt, std::ostringstream& oss) {
299 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
300 for (auto reg : registers) {
301 std::string after_reg = fmt;
302
303 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
304 size_t reg_index;
305 const char* reg_token = GetRegTokenFromDepth(depth);
306
307 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
308 after_reg.replace(reg_index, strlen(reg_token), reg_string);
309 }
310
311 ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
312 }
313 }
314
TemplateHelper(std::function<void (const arm::ShifterOperand &)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::ostringstream & oss)315 void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
316 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
317 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
318 std::string after_shift = fmt;
319
320 std::string shift_string = GetShiftString(shift);
321 size_t shift_index;
322 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
323 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
324 }
325
326 ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
327 }
328 }
329
TemplateHelper(std::function<void (arm::Condition)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::ostringstream & oss)330 void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
331 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
332 for (arm::Condition c : GetConditions()) {
333 std::string after_cond = fmt;
334
335 size_t cond_index = after_cond.find(COND_TOKEN);
336 if (cond_index != std::string::npos) {
337 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
338 }
339
340 ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
341 }
342 }
343
344 template <typename... Args>
TemplateHelper(std::function<void (arm::Register,Args...)> f,int depth,bool without_pc,std::string fmt,std::ostringstream & oss)345 void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
346 std::string fmt, std::ostringstream& oss) {
347 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
348 for (auto reg : registers) {
349 std::string after_reg = fmt;
350
351 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
352 size_t reg_index;
353 const char* reg_token = GetRegTokenFromDepth(depth);
354
355 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
356 after_reg.replace(reg_index, strlen(reg_token), reg_string);
357 }
358
359 auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
360 TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
361 after_reg, oss);
362 }
363 }
364
365 template <typename... Args>
TemplateHelper(std::function<void (const arm::ShifterOperand &,Args...)> f,int depth,bool without_pc,std::string fmt,std::ostringstream & oss)366 void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
367 bool without_pc, std::string fmt, std::ostringstream& oss) {
368 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
369 std::string after_shift = fmt;
370
371 std::string shift_string = GetShiftString(shift);
372 size_t shift_index;
373 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
374 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
375 }
376
377 auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
378 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
379 after_shift, oss);
380 }
381 }
382
383 template <typename... Args>
TemplateHelper(std::function<void (arm::Condition,Args...)> f,int depth,bool without_pc,std::string fmt,std::ostringstream & oss)384 void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
385 std::string fmt, std::ostringstream& oss) {
386 for (arm::Condition c : GetConditions()) {
387 std::string after_cond = fmt;
388
389 size_t cond_index = after_cond.find(COND_TOKEN);
390 if (cond_index != std::string::npos) {
391 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
392 }
393
394 auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
395 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
396 after_cond, oss);
397 }
398 }
399
400 template <typename T1, typename T2>
GetBoundFunction2(void (arm::Arm32Assembler::* f)(T1,T2))401 std::function<void(T1, T2)> GetBoundFunction2(void (arm::Arm32Assembler::*f)(T1, T2)) {
402 return std::bind(f, GetAssembler(), _1, _2);
403 }
404
405 template <typename T1, typename T2, typename T3>
GetBoundFunction3(void (arm::Arm32Assembler::* f)(T1,T2,T3))406 std::function<void(T1, T2, T3)> GetBoundFunction3(void (arm::Arm32Assembler::*f)(T1, T2, T3)) {
407 return std::bind(f, GetAssembler(), _1, _2, _3);
408 }
409
410 template <typename T1, typename T2, typename T3, typename T4>
GetBoundFunction4(void (arm::Arm32Assembler::* f)(T1,T2,T3,T4))411 std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
412 void (arm::Arm32Assembler::*f)(T1, T2, T3, T4)) {
413 return std::bind(f, GetAssembler(), _1, _2, _3, _4);
414 }
415
416 template <typename T1, typename T2, typename T3, typename T4, typename T5>
GetBoundFunction5(void (arm::Arm32Assembler::* f)(T1,T2,T3,T4,T5))417 std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
418 void (arm::Arm32Assembler::*f)(T1, T2, T3, T4, T5)) {
419 return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
420 }
421
422 template <typename... Args>
GenericTemplateHelper(std::function<void (Args...)> f,bool without_pc,std::string fmt,std::string test_name)423 void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
424 std::string fmt, std::string test_name) {
425 first_ = false;
426 WarnOnCombinations(CountHelper<Args...>(without_pc));
427
428 std::ostringstream oss;
429
430 TemplateHelper(f, 0, without_pc, fmt, oss);
431
432 oss << "\n"; // Trailing newline.
433
434 DriverStr(oss.str(), test_name);
435 }
436
437 template <typename... Args>
T2Helper(void (arm::Arm32Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name)438 void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
439 std::string test_name) {
440 GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
441 }
442
443 template <typename... Args>
T3Helper(void (arm::Arm32Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name)444 void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
445 std::string test_name) {
446 GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
447 }
448
449 template <typename... Args>
T4Helper(void (arm::Arm32Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name)450 void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
451 std::string test_name) {
452 GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
453 }
454
455 template <typename... Args>
T5Helper(void (arm::Arm32Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name)456 void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
457 std::string test_name) {
458 GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
459 }
460
461 private:
462 template <typename T>
CountHelper(bool without_pc)463 size_t CountHelper(bool without_pc) {
464 size_t tmp;
465 if (std::is_same<T, arm::Register>::value) {
466 tmp = GetRegisters().size();
467 if (without_pc) {
468 tmp--;; // Approximation...
469 }
470 return tmp;
471 } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
472 return GetShiftOperands().size();
473 } else if (std::is_same<T, arm::Condition>::value) {
474 return GetConditions().size();
475 } else {
476 LOG(WARNING) << "Unknown type while counting.";
477 return 1;
478 }
479 }
480
481 template <typename T1, typename T2, typename... Args>
CountHelper(bool without_pc)482 size_t CountHelper(bool without_pc) {
483 size_t tmp;
484 if (std::is_same<T1, arm::Register>::value) {
485 tmp = GetRegisters().size();
486 if (without_pc) {
487 tmp--;; // Approximation...
488 }
489 } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
490 tmp = GetShiftOperands().size();
491 } else if (std::is_same<T1, arm::Condition>::value) {
492 tmp = GetConditions().size();
493 } else {
494 LOG(WARNING) << "Unknown type while counting.";
495 tmp = 1;
496 }
497 size_t rec = CountHelper<T2, Args...>(without_pc);
498 return rec * tmp;
499 }
500
501 bool first_;
502
503 static constexpr const char* kArm32AssemblyHeader = ".arm\n";
504
505 std::vector<arm::Register*> registers_;
506 std::vector<arm::Condition> conditions_;
507 std::vector<arm::ShifterOperand> shifter_operands_;
508 };
509
510
TEST_F(AssemblerArm32Test,Toolchain)511 TEST_F(AssemblerArm32Test, Toolchain) {
512 EXPECT_TRUE(CheckTools());
513 }
514
TEST_F(AssemblerArm32Test,Sbfx)515 TEST_F(AssemblerArm32Test, Sbfx) {
516 std::vector<std::pair<uint32_t, uint32_t>> immediates;
517 immediates.push_back({0, 1});
518 immediates.push_back({0, 8});
519 immediates.push_back({0, 15});
520 immediates.push_back({0, 16});
521 immediates.push_back({0, 31});
522 immediates.push_back({0, 32});
523
524 immediates.push_back({1, 1});
525 immediates.push_back({1, 15});
526 immediates.push_back({1, 31});
527
528 immediates.push_back({8, 1});
529 immediates.push_back({8, 15});
530 immediates.push_back({8, 16});
531 immediates.push_back({8, 24});
532
533 immediates.push_back({31, 1});
534
535 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
536 "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
537 }
538
TEST_F(AssemblerArm32Test,Ubfx)539 TEST_F(AssemblerArm32Test, Ubfx) {
540 std::vector<std::pair<uint32_t, uint32_t>> immediates;
541 immediates.push_back({0, 1});
542 immediates.push_back({0, 8});
543 immediates.push_back({0, 15});
544 immediates.push_back({0, 16});
545 immediates.push_back({0, 31});
546 immediates.push_back({0, 32});
547
548 immediates.push_back({1, 1});
549 immediates.push_back({1, 15});
550 immediates.push_back({1, 31});
551
552 immediates.push_back({8, 1});
553 immediates.push_back({8, 15});
554 immediates.push_back({8, 16});
555 immediates.push_back({8, 24});
556
557 immediates.push_back({31, 1});
558
559 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
560 "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
561 }
562
TEST_F(AssemblerArm32Test,Mul)563 TEST_F(AssemblerArm32Test, Mul) {
564 T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
565 }
566
TEST_F(AssemblerArm32Test,Mla)567 TEST_F(AssemblerArm32Test, Mla) {
568 T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
569 }
570
571 /* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
572 TEST_F(AssemblerArm32Test, Umull) {
573 T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
574 "umull");
575 }
576 */
577
TEST_F(AssemblerArm32Test,Sdiv)578 TEST_F(AssemblerArm32Test, Sdiv) {
579 T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
580 }
581
TEST_F(AssemblerArm32Test,Udiv)582 TEST_F(AssemblerArm32Test, Udiv) {
583 T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
584 }
585
TEST_F(AssemblerArm32Test,And)586 TEST_F(AssemblerArm32Test, And) {
587 T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and");
588 }
589
TEST_F(AssemblerArm32Test,Eor)590 TEST_F(AssemblerArm32Test, Eor) {
591 T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor");
592 }
593
TEST_F(AssemblerArm32Test,Orr)594 TEST_F(AssemblerArm32Test, Orr) {
595 T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr");
596 }
597
TEST_F(AssemblerArm32Test,Orrs)598 TEST_F(AssemblerArm32Test, Orrs) {
599 T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
600 }
601
TEST_F(AssemblerArm32Test,Bic)602 TEST_F(AssemblerArm32Test, Bic) {
603 T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic");
604 }
605
TEST_F(AssemblerArm32Test,Mov)606 TEST_F(AssemblerArm32Test, Mov) {
607 T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov");
608 }
609
TEST_F(AssemblerArm32Test,Movs)610 TEST_F(AssemblerArm32Test, Movs) {
611 T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
612 }
613
TEST_F(AssemblerArm32Test,Mvn)614 TEST_F(AssemblerArm32Test, Mvn) {
615 T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn");
616 }
617
TEST_F(AssemblerArm32Test,Mvns)618 TEST_F(AssemblerArm32Test, Mvns) {
619 T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
620 }
621
TEST_F(AssemblerArm32Test,Add)622 TEST_F(AssemblerArm32Test, Add) {
623 T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add");
624 }
625
TEST_F(AssemblerArm32Test,Adds)626 TEST_F(AssemblerArm32Test, Adds) {
627 T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
628 }
629
TEST_F(AssemblerArm32Test,Adc)630 TEST_F(AssemblerArm32Test, Adc) {
631 T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc");
632 }
633
TEST_F(AssemblerArm32Test,Sub)634 TEST_F(AssemblerArm32Test, Sub) {
635 T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub");
636 }
637
TEST_F(AssemblerArm32Test,Subs)638 TEST_F(AssemblerArm32Test, Subs) {
639 T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
640 }
641
TEST_F(AssemblerArm32Test,Sbc)642 TEST_F(AssemblerArm32Test, Sbc) {
643 T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc");
644 }
645
TEST_F(AssemblerArm32Test,Rsb)646 TEST_F(AssemblerArm32Test, Rsb) {
647 T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb");
648 }
649
TEST_F(AssemblerArm32Test,Rsbs)650 TEST_F(AssemblerArm32Test, Rsbs) {
651 T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
652 }
653
TEST_F(AssemblerArm32Test,Rsc)654 TEST_F(AssemblerArm32Test, Rsc) {
655 T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
656 }
657
658 /* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
659 TEST_F(AssemblerArm32Test, Strex) {
660 RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
661 }
662 */
663
TEST_F(AssemblerArm32Test,Clz)664 TEST_F(AssemblerArm32Test, Clz) {
665 T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
666 }
667
TEST_F(AssemblerArm32Test,Tst)668 TEST_F(AssemblerArm32Test, Tst) {
669 T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
670 }
671
TEST_F(AssemblerArm32Test,Teq)672 TEST_F(AssemblerArm32Test, Teq) {
673 T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
674 }
675
TEST_F(AssemblerArm32Test,Cmp)676 TEST_F(AssemblerArm32Test, Cmp) {
677 T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
678 }
679
TEST_F(AssemblerArm32Test,Cmn)680 TEST_F(AssemblerArm32Test, Cmn) {
681 T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
682 }
683
TEST_F(AssemblerArm32Test,Blx)684 TEST_F(AssemblerArm32Test, Blx) {
685 T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
686 }
687
TEST_F(AssemblerArm32Test,Bx)688 TEST_F(AssemblerArm32Test, Bx) {
689 T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
690 }
691
TEST_F(AssemblerArm32Test,Vmstat)692 TEST_F(AssemblerArm32Test, Vmstat) {
693 GetAssembler()->vmstat();
694
695 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
696
697 DriverStr(expected, "vmrs");
698 }
699
TEST_F(AssemblerArm32Test,ldrexd)700 TEST_F(AssemblerArm32Test, ldrexd) {
701 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
702 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
703 GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
704
705 const char* expected =
706 "ldrexd r0, r1, [r0]\n"
707 "ldrexd r0, r1, [r1]\n"
708 "ldrexd r0, r1, [r2]\n";
709 DriverStr(expected, "ldrexd");
710 }
711
TEST_F(AssemblerArm32Test,strexd)712 TEST_F(AssemblerArm32Test, strexd) {
713 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
714 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
715 GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
716
717 const char* expected =
718 "strexd r9, r0, r1, [r0]\n"
719 "strexd r9, r0, r1, [r1]\n"
720 "strexd r9, r0, r1, [r2]\n";
721 DriverStr(expected, "strexd");
722 }
723
724 } // namespace art
725