blob: 837fe1ec18f1af1f8ffd1a4b7263acd3ac050212 [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 {
Andreas Gampe8205c772014-11-20 17:01:10 -080052 return " -march=armv7-a -mcpu=cortex-a15"; // Arm-v7a, cortex-a15 (means we have sdiv).
Andreas Gampe849cc5e2014-11-18 13:46:46 -080053 }
54
55 const char* GetAssemblyHeader() OVERRIDE {
56 return kArm32AssemblyHeader;
57 }
58
Roland Levillain1a28fc42014-11-13 18:03:06 +000059 std::string GetDisassembleParameters() OVERRIDE {
60 return " -D -bbinary -marm --no-show-raw-insn";
61 }
62
63 void SetUpHelpers() OVERRIDE {
64 if (registers_.size() == 0) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -080065 if (kUseSparseRegisterList) {
66 registers_.insert(end(registers_),
67 { // NOLINT(whitespace/braces)
68 new arm::Register(arm::R0),
69 new arm::Register(arm::R1),
70 new arm::Register(arm::R4),
71 new arm::Register(arm::R8),
72 new arm::Register(arm::R11),
73 new arm::Register(arm::R12),
74 new arm::Register(arm::R13),
75 new arm::Register(arm::R14),
76 new arm::Register(arm::R15)
77 });
78 } else {
79 registers_.insert(end(registers_),
80 { // NOLINT(whitespace/braces)
81 new arm::Register(arm::R0),
82 new arm::Register(arm::R1),
83 new arm::Register(arm::R2),
84 new arm::Register(arm::R3),
85 new arm::Register(arm::R4),
86 new arm::Register(arm::R5),
87 new arm::Register(arm::R6),
88 new arm::Register(arm::R7),
89 new arm::Register(arm::R8),
90 new arm::Register(arm::R9),
91 new arm::Register(arm::R10),
92 new arm::Register(arm::R11),
93 new arm::Register(arm::R12),
94 new arm::Register(arm::R13),
95 new arm::Register(arm::R14),
96 new arm::Register(arm::R15)
97 });
98 }
99 }
100
101 if (!kUseSparseConditionList) {
102 conditions_.push_back(arm::Condition::EQ);
103 conditions_.push_back(arm::Condition::NE);
104 conditions_.push_back(arm::Condition::CS);
105 conditions_.push_back(arm::Condition::CC);
106 conditions_.push_back(arm::Condition::MI);
107 conditions_.push_back(arm::Condition::PL);
108 conditions_.push_back(arm::Condition::VS);
109 conditions_.push_back(arm::Condition::VC);
110 conditions_.push_back(arm::Condition::HI);
111 conditions_.push_back(arm::Condition::LS);
112 conditions_.push_back(arm::Condition::GE);
113 conditions_.push_back(arm::Condition::LT);
114 conditions_.push_back(arm::Condition::GT);
115 conditions_.push_back(arm::Condition::LE);
116 conditions_.push_back(arm::Condition::AL);
117 } else {
118 conditions_.push_back(arm::Condition::EQ);
119 conditions_.push_back(arm::Condition::NE);
120 conditions_.push_back(arm::Condition::CC);
121 conditions_.push_back(arm::Condition::VC);
122 conditions_.push_back(arm::Condition::HI);
123 conditions_.push_back(arm::Condition::LT);
124 conditions_.push_back(arm::Condition::AL);
125 }
126
127 shifter_operands_.push_back(arm::ShifterOperand(0));
128 shifter_operands_.push_back(arm::ShifterOperand(1));
129 shifter_operands_.push_back(arm::ShifterOperand(2));
130 shifter_operands_.push_back(arm::ShifterOperand(3));
131 shifter_operands_.push_back(arm::ShifterOperand(4));
132 shifter_operands_.push_back(arm::ShifterOperand(5));
133 shifter_operands_.push_back(arm::ShifterOperand(127));
134 shifter_operands_.push_back(arm::ShifterOperand(128));
135 shifter_operands_.push_back(arm::ShifterOperand(254));
136 shifter_operands_.push_back(arm::ShifterOperand(255));
137
138 if (!kUseSparseRegisterList) {
139 shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
140 shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
141 shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
142 shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
143 shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
144 shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
145 shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
146 shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
147 shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
148 shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
149 shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
150 shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
151 shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
152 shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
153 } else {
154 shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
155 shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
156 shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
157 shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
158 shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
159 shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
160 shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
161 }
162
163 std::vector<arm::Shift> shifts {
164 arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
165 };
166
167 // ShifterOperands of form "reg shift-type imm."
168 for (arm::Shift shift : shifts) {
169 for (arm::Register* reg : registers_) { // Note: this will pick up the sparse set.
170 if (*reg == arm::R15) { // Skip PC.
171 continue;
172 }
173 if (shift != arm::Shift::RRX) {
174 if (!kUseSparseShiftImmediates) {
175 for (uint32_t imm = 1; imm < 32; ++imm) {
176 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
177 }
178 } else {
179 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
180 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
181 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
182 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
183 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
184 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
185 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
186 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
187 }
188 } else {
189 // RRX doesn't have an immediate.
190 shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
191 }
192 }
Roland Levillain1a28fc42014-11-13 18:03:06 +0000193 }
194 }
195
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800196 std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
197 int32_t shift_min, int32_t shift_max) {
198 std::vector<arm::ShifterOperand> res;
199 static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
200 arm::Shift::ROR };
201
202 for (arm::Shift shift : kShifts) {
203 for (arm::Register* reg : base_regs) {
204 // Take the min, the max, and three values in between.
205 res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
206 if (shift_min != shift_max) {
207 res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
208 int32_t middle = (shift_min + shift_max) / 2;
209 res.push_back(arm::ShifterOperand(*reg, shift, middle));
210 res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
211 res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
212 }
213 }
214 }
215
216 return res;
217 }
218
Roland Levillain1a28fc42014-11-13 18:03:06 +0000219 void TearDown() OVERRIDE {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800220 AssemblerArmTest::TearDown();
Roland Levillain1a28fc42014-11-13 18:03:06 +0000221 STLDeleteElements(&registers_);
222 }
223
224 std::vector<arm::Register*> GetRegisters() OVERRIDE {
225 return registers_;
226 }
227
228 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
229 return imm_value;
230 }
231
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800232 std::vector<arm::Condition>& GetConditions() OVERRIDE {
233 return conditions_;
234 }
235
236 std::string GetConditionString(arm::Condition c) OVERRIDE {
237 std::ostringstream oss;
238 oss << c;
239 return oss.str();
240 }
241
242 arm::Register GetPCRegister() OVERRIDE {
243 return arm::R15;
244 }
245
246 std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
247 return shifter_operands_;
248 }
249
250 std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
251 std::ostringstream oss;
252 if (sop.IsShift()) {
253 // Not a rotate...
254 if (sop.GetShift() == arm::Shift::RRX) {
255 oss << sop.GetRegister() << ", " << sop.GetShift();
256 } else {
257 oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
258 }
259 } else if (sop.IsRegister()) {
260 oss << sop.GetRegister();
261 } else {
262 CHECK(sop.IsImmediate());
263 oss << "#" << sop.GetImmediate();
264 }
265 return oss.str();
266 }
267
268 static const char* GetRegTokenFromDepth(int depth) {
269 switch (depth) {
270 case 0:
271 return Base::REG1_TOKEN;
272 case 1:
273 return Base::REG2_TOKEN;
274 case 2:
275 return REG3_TOKEN;
276 case 3:
277 return REG4_TOKEN;
278 default:
279 LOG(FATAL) << "Depth problem.";
280 UNREACHABLE();
281 }
282 }
283
284 void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
285 if (first_) {
286 first_ = false;
287 } else {
288 oss << "\n";
289 }
290 oss << fmt;
291
292 f();
293 }
294
295 void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
296 bool without_pc,
297 std::string fmt, std::ostringstream& oss) {
298 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
299 for (auto reg : registers) {
300 std::string after_reg = fmt;
301
302 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
303 size_t reg_index;
304 const char* reg_token = GetRegTokenFromDepth(depth);
305
306 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
307 after_reg.replace(reg_index, strlen(reg_token), reg_string);
308 }
309
310 ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
311 }
312 }
313
314 void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
315 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
316 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
317 std::string after_shift = fmt;
318
319 std::string shift_string = GetShiftString(shift);
320 size_t shift_index;
321 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
322 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
323 }
324
325 ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
326 }
327 }
328
329 void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
330 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
331 for (arm::Condition c : GetConditions()) {
332 std::string after_cond = fmt;
333
334 size_t cond_index = after_cond.find(COND_TOKEN);
335 if (cond_index != std::string::npos) {
336 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
337 }
338
339 ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
340 }
341 }
342
343 template <typename... Args>
344 void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
345 std::string fmt, std::ostringstream& oss) {
346 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
347 for (auto reg : registers) {
348 std::string after_reg = fmt;
349
350 std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
351 size_t reg_index;
352 const char* reg_token = GetRegTokenFromDepth(depth);
353
354 while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
355 after_reg.replace(reg_index, strlen(reg_token), reg_string);
356 }
357
358 auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
359 TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
360 after_reg, oss);
361 }
362 }
363
364 template <typename... Args>
365 void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
366 bool without_pc, std::string fmt, std::ostringstream& oss) {
367 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
368 std::string after_shift = fmt;
369
370 std::string shift_string = GetShiftString(shift);
371 size_t shift_index;
372 while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
373 after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
374 }
375
376 auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
377 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
378 after_shift, oss);
379 }
380 }
381
382 template <typename... Args>
383 void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
384 std::string fmt, std::ostringstream& oss) {
385 for (arm::Condition c : GetConditions()) {
386 std::string after_cond = fmt;
387
388 size_t cond_index = after_cond.find(COND_TOKEN);
389 if (cond_index != std::string::npos) {
390 after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
391 }
392
393 auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
394 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
395 after_cond, oss);
396 }
397 }
398
399 template <typename T1, typename T2>
400 std::function<void(T1, T2)> GetBoundFunction2(void (arm::Arm32Assembler::*f)(T1, T2)) {
401 return std::bind(f, GetAssembler(), _1, _2);
402 }
403
404 template <typename T1, typename T2, typename T3>
405 std::function<void(T1, T2, T3)> GetBoundFunction3(void (arm::Arm32Assembler::*f)(T1, T2, T3)) {
406 return std::bind(f, GetAssembler(), _1, _2, _3);
407 }
408
409 template <typename T1, typename T2, typename T3, typename T4>
410 std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
411 void (arm::Arm32Assembler::*f)(T1, T2, T3, T4)) {
412 return std::bind(f, GetAssembler(), _1, _2, _3, _4);
413 }
414
415 template <typename T1, typename T2, typename T3, typename T4, typename T5>
416 std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
417 void (arm::Arm32Assembler::*f)(T1, T2, T3, T4, T5)) {
418 return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
419 }
420
421 template <typename... Args>
422 void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
423 std::string fmt, std::string test_name) {
Andreas Gampeab65c672014-11-20 20:22:31 -0800424 first_ = false;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800425 WarnOnCombinations(CountHelper<Args...>(without_pc));
426
427 std::ostringstream oss;
428
429 TemplateHelper(f, 0, without_pc, fmt, oss);
430
431 oss << "\n"; // Trailing newline.
432
433 DriverStr(oss.str(), test_name);
434 }
435
436 template <typename... Args>
437 void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
438 std::string test_name) {
439 GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
440 }
441
442 template <typename... Args>
443 void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
444 std::string test_name) {
445 GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
446 }
447
448 template <typename... Args>
449 void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
450 std::string test_name) {
451 GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
452 }
453
454 template <typename... Args>
455 void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
456 std::string test_name) {
457 GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
458 }
459
Roland Levillain1a28fc42014-11-13 18:03:06 +0000460 private:
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800461 template <typename T>
462 size_t CountHelper(bool without_pc) {
463 size_t tmp;
464 if (std::is_same<T, arm::Register>::value) {
465 tmp = GetRegisters().size();
466 if (without_pc) {
467 tmp--;; // Approximation...
468 }
469 return tmp;
470 } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
471 return GetShiftOperands().size();
472 } else if (std::is_same<T, arm::Condition>::value) {
473 return GetConditions().size();
474 } else {
475 LOG(WARNING) << "Unknown type while counting.";
476 return 1;
477 }
478 }
479
480 template <typename T1, typename T2, typename... Args>
481 size_t CountHelper(bool without_pc) {
482 size_t tmp;
483 if (std::is_same<T1, arm::Register>::value) {
484 tmp = GetRegisters().size();
485 if (without_pc) {
486 tmp--;; // Approximation...
487 }
488 } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
489 tmp = GetShiftOperands().size();
490 } else if (std::is_same<T1, arm::Condition>::value) {
491 tmp = GetConditions().size();
492 } else {
493 LOG(WARNING) << "Unknown type while counting.";
494 tmp = 1;
495 }
496 size_t rec = CountHelper<T2, Args...>(without_pc);
497 return rec * tmp;
498 }
499
500 bool first_;
501
502 static constexpr const char* kArm32AssemblyHeader = ".arm\n";
503
Roland Levillain1a28fc42014-11-13 18:03:06 +0000504 std::vector<arm::Register*> registers_;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800505 std::vector<arm::Condition> conditions_;
506 std::vector<arm::ShifterOperand> shifter_operands_;
Roland Levillain1a28fc42014-11-13 18:03:06 +0000507};
508
509
510TEST_F(AssemblerArm32Test, Toolchain) {
511 EXPECT_TRUE(CheckTools());
512}
513
Roland Levillain1a28fc42014-11-13 18:03:06 +0000514TEST_F(AssemblerArm32Test, Sbfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800515 std::vector<std::pair<uint32_t, uint32_t>> immediates;
516 immediates.push_back({0, 1});
517 immediates.push_back({0, 8});
518 immediates.push_back({0, 15});
519 immediates.push_back({0, 16});
520 immediates.push_back({0, 31});
521 immediates.push_back({0, 32});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000522
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800523 immediates.push_back({1, 1});
524 immediates.push_back({1, 15});
525 immediates.push_back({1, 31});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000526
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800527 immediates.push_back({8, 1});
528 immediates.push_back({8, 15});
529 immediates.push_back({8, 16});
530 immediates.push_back({8, 24});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000531
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800532 immediates.push_back({31, 1});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000533
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800534 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
535 "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
Roland Levillain1a28fc42014-11-13 18:03:06 +0000536}
537
Roland Levillain981e4542014-11-14 11:47:14 +0000538TEST_F(AssemblerArm32Test, Ubfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800539 std::vector<std::pair<uint32_t, uint32_t>> immediates;
540 immediates.push_back({0, 1});
541 immediates.push_back({0, 8});
542 immediates.push_back({0, 15});
543 immediates.push_back({0, 16});
544 immediates.push_back({0, 31});
545 immediates.push_back({0, 32});
Roland Levillain981e4542014-11-14 11:47:14 +0000546
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800547 immediates.push_back({1, 1});
548 immediates.push_back({1, 15});
549 immediates.push_back({1, 31});
Roland Levillain981e4542014-11-14 11:47:14 +0000550
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800551 immediates.push_back({8, 1});
552 immediates.push_back({8, 15});
553 immediates.push_back({8, 16});
554 immediates.push_back({8, 24});
Roland Levillain981e4542014-11-14 11:47:14 +0000555
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800556 immediates.push_back({31, 1});
Roland Levillain981e4542014-11-14 11:47:14 +0000557
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800558 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
559 "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
560}
Roland Levillain981e4542014-11-14 11:47:14 +0000561
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800562TEST_F(AssemblerArm32Test, Mul) {
563 T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
564}
Roland Levillain981e4542014-11-14 11:47:14 +0000565
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800566TEST_F(AssemblerArm32Test, Mla) {
567 T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
568}
Roland Levillain981e4542014-11-14 11:47:14 +0000569
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800570/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
571TEST_F(AssemblerArm32Test, Umull) {
572 T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
573 "umull");
574}
575*/
576
577TEST_F(AssemblerArm32Test, Sdiv) {
578 T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
579}
580
581TEST_F(AssemblerArm32Test, Udiv) {
582 T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
583}
584
585TEST_F(AssemblerArm32Test, And) {
586 T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and");
587}
588
589TEST_F(AssemblerArm32Test, Eor) {
590 T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor");
591}
592
593TEST_F(AssemblerArm32Test, Orr) {
594 T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr");
595}
596
597TEST_F(AssemblerArm32Test, Orrs) {
598 T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
599}
600
601TEST_F(AssemblerArm32Test, Bic) {
602 T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic");
603}
604
605TEST_F(AssemblerArm32Test, Mov) {
606 T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov");
607}
608
609TEST_F(AssemblerArm32Test, Movs) {
610 T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
611}
612
613TEST_F(AssemblerArm32Test, Mvn) {
614 T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn");
615}
616
617TEST_F(AssemblerArm32Test, Mvns) {
618 T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
619}
620
621TEST_F(AssemblerArm32Test, Add) {
622 T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add");
623}
624
625TEST_F(AssemblerArm32Test, Adds) {
626 T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
627}
628
629TEST_F(AssemblerArm32Test, Adc) {
630 T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc");
631}
632
633TEST_F(AssemblerArm32Test, Sub) {
634 T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub");
635}
636
637TEST_F(AssemblerArm32Test, Subs) {
638 T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
639}
640
641TEST_F(AssemblerArm32Test, Sbc) {
642 T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc");
643}
644
645TEST_F(AssemblerArm32Test, Rsb) {
646 T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb");
647}
648
649TEST_F(AssemblerArm32Test, Rsbs) {
650 T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
651}
652
653TEST_F(AssemblerArm32Test, Rsc) {
654 T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
655}
656
657/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
658TEST_F(AssemblerArm32Test, Strex) {
659 RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
660}
661*/
662
663TEST_F(AssemblerArm32Test, Clz) {
664 T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
665}
666
667TEST_F(AssemblerArm32Test, Tst) {
668 T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
669}
670
671TEST_F(AssemblerArm32Test, Teq) {
672 T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
673}
674
675TEST_F(AssemblerArm32Test, Cmp) {
676 T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
677}
678
679TEST_F(AssemblerArm32Test, Cmn) {
680 T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
681}
682
683TEST_F(AssemblerArm32Test, Blx) {
684 T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
685}
686
687TEST_F(AssemblerArm32Test, Bx) {
688 T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
Roland Levillain981e4542014-11-14 11:47:14 +0000689}
690
Roland Levillain1a28fc42014-11-13 18:03:06 +0000691} // namespace art