blob: fe12a226c81c67c45aafcb17016c806de2ae520e [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 {
52 return " -march=armv7ve"; // Arm-v7a with virtualization extension (means we have sdiv).
53 }
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) {
424 WarnOnCombinations(CountHelper<Args...>(without_pc));
425
426 std::ostringstream oss;
427
428 TemplateHelper(f, 0, without_pc, fmt, oss);
429
430 oss << "\n"; // Trailing newline.
431
432 DriverStr(oss.str(), test_name);
433 }
434
435 template <typename... Args>
436 void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
437 std::string test_name) {
438 GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
439 }
440
441 template <typename... Args>
442 void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
443 std::string test_name) {
444 GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
445 }
446
447 template <typename... Args>
448 void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
449 std::string test_name) {
450 GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
451 }
452
453 template <typename... Args>
454 void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
455 std::string test_name) {
456 GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
457 }
458
Roland Levillain1a28fc42014-11-13 18:03:06 +0000459 private:
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800460 template <typename T>
461 size_t CountHelper(bool without_pc) {
462 size_t tmp;
463 if (std::is_same<T, arm::Register>::value) {
464 tmp = GetRegisters().size();
465 if (without_pc) {
466 tmp--;; // Approximation...
467 }
468 return tmp;
469 } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
470 return GetShiftOperands().size();
471 } else if (std::is_same<T, arm::Condition>::value) {
472 return GetConditions().size();
473 } else {
474 LOG(WARNING) << "Unknown type while counting.";
475 return 1;
476 }
477 }
478
479 template <typename T1, typename T2, typename... Args>
480 size_t CountHelper(bool without_pc) {
481 size_t tmp;
482 if (std::is_same<T1, arm::Register>::value) {
483 tmp = GetRegisters().size();
484 if (without_pc) {
485 tmp--;; // Approximation...
486 }
487 } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
488 tmp = GetShiftOperands().size();
489 } else if (std::is_same<T1, arm::Condition>::value) {
490 tmp = GetConditions().size();
491 } else {
492 LOG(WARNING) << "Unknown type while counting.";
493 tmp = 1;
494 }
495 size_t rec = CountHelper<T2, Args...>(without_pc);
496 return rec * tmp;
497 }
498
499 bool first_;
500
501 static constexpr const char* kArm32AssemblyHeader = ".arm\n";
502
Roland Levillain1a28fc42014-11-13 18:03:06 +0000503 std::vector<arm::Register*> registers_;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800504 std::vector<arm::Condition> conditions_;
505 std::vector<arm::ShifterOperand> shifter_operands_;
Roland Levillain1a28fc42014-11-13 18:03:06 +0000506};
507
508
509TEST_F(AssemblerArm32Test, Toolchain) {
510 EXPECT_TRUE(CheckTools());
511}
512
Roland Levillain1a28fc42014-11-13 18:03:06 +0000513TEST_F(AssemblerArm32Test, Sbfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800514 std::vector<std::pair<uint32_t, uint32_t>> immediates;
515 immediates.push_back({0, 1});
516 immediates.push_back({0, 8});
517 immediates.push_back({0, 15});
518 immediates.push_back({0, 16});
519 immediates.push_back({0, 31});
520 immediates.push_back({0, 32});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000521
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800522 immediates.push_back({1, 1});
523 immediates.push_back({1, 15});
524 immediates.push_back({1, 31});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000525
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800526 immediates.push_back({8, 1});
527 immediates.push_back({8, 15});
528 immediates.push_back({8, 16});
529 immediates.push_back({8, 24});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000530
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800531 immediates.push_back({31, 1});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000532
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800533 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
534 "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
Roland Levillain1a28fc42014-11-13 18:03:06 +0000535}
536
Roland Levillain981e4542014-11-14 11:47:14 +0000537TEST_F(AssemblerArm32Test, Ubfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800538 std::vector<std::pair<uint32_t, uint32_t>> immediates;
539 immediates.push_back({0, 1});
540 immediates.push_back({0, 8});
541 immediates.push_back({0, 15});
542 immediates.push_back({0, 16});
543 immediates.push_back({0, 31});
544 immediates.push_back({0, 32});
Roland Levillain981e4542014-11-14 11:47:14 +0000545
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800546 immediates.push_back({1, 1});
547 immediates.push_back({1, 15});
548 immediates.push_back({1, 31});
Roland Levillain981e4542014-11-14 11:47:14 +0000549
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800550 immediates.push_back({8, 1});
551 immediates.push_back({8, 15});
552 immediates.push_back({8, 16});
553 immediates.push_back({8, 24});
Roland Levillain981e4542014-11-14 11:47:14 +0000554
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800555 immediates.push_back({31, 1});
Roland Levillain981e4542014-11-14 11:47:14 +0000556
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800557 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
558 "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
559}
Roland Levillain981e4542014-11-14 11:47:14 +0000560
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800561TEST_F(AssemblerArm32Test, Mul) {
562 T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
563}
Roland Levillain981e4542014-11-14 11:47:14 +0000564
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800565TEST_F(AssemblerArm32Test, Mla) {
566 T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
567}
Roland Levillain981e4542014-11-14 11:47:14 +0000568
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800569/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
570TEST_F(AssemblerArm32Test, Umull) {
571 T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
572 "umull");
573}
574*/
575
576TEST_F(AssemblerArm32Test, Sdiv) {
577 T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
578}
579
580TEST_F(AssemblerArm32Test, Udiv) {
581 T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
582}
583
584TEST_F(AssemblerArm32Test, And) {
585 T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and");
586}
587
588TEST_F(AssemblerArm32Test, Eor) {
589 T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor");
590}
591
592TEST_F(AssemblerArm32Test, Orr) {
593 T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr");
594}
595
596TEST_F(AssemblerArm32Test, Orrs) {
597 T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
598}
599
600TEST_F(AssemblerArm32Test, Bic) {
601 T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic");
602}
603
604TEST_F(AssemblerArm32Test, Mov) {
605 T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov");
606}
607
608TEST_F(AssemblerArm32Test, Movs) {
609 T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
610}
611
612TEST_F(AssemblerArm32Test, Mvn) {
613 T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn");
614}
615
616TEST_F(AssemblerArm32Test, Mvns) {
617 T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
618}
619
620TEST_F(AssemblerArm32Test, Add) {
621 T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add");
622}
623
624TEST_F(AssemblerArm32Test, Adds) {
625 T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
626}
627
628TEST_F(AssemblerArm32Test, Adc) {
629 T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc");
630}
631
632TEST_F(AssemblerArm32Test, Sub) {
633 T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub");
634}
635
636TEST_F(AssemblerArm32Test, Subs) {
637 T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
638}
639
640TEST_F(AssemblerArm32Test, Sbc) {
641 T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc");
642}
643
644TEST_F(AssemblerArm32Test, Rsb) {
645 T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb");
646}
647
648TEST_F(AssemblerArm32Test, Rsbs) {
649 T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
650}
651
652TEST_F(AssemblerArm32Test, Rsc) {
653 T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
654}
655
656/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
657TEST_F(AssemblerArm32Test, Strex) {
658 RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
659}
660*/
661
662TEST_F(AssemblerArm32Test, Clz) {
663 T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
664}
665
666TEST_F(AssemblerArm32Test, Tst) {
667 T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
668}
669
670TEST_F(AssemblerArm32Test, Teq) {
671 T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
672}
673
674TEST_F(AssemblerArm32Test, Cmp) {
675 T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
676}
677
678TEST_F(AssemblerArm32Test, Cmn) {
679 T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
680}
681
682TEST_F(AssemblerArm32Test, Blx) {
683 T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
684}
685
686TEST_F(AssemblerArm32Test, Bx) {
687 T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
Roland Levillain981e4542014-11-14 11:47:14 +0000688}
689
Roland Levillain1a28fc42014-11-13 18:03:06 +0000690} // namespace art