blob: 43805966a92f624ecbec849678a95b569790595a [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,
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010045 uint32_t, arm::ShifterOperand, arm::Condition,
46 arm::SetCc> {
Roland Levillain1a28fc42014-11-13 18:03:06 +000047 protected:
48 std::string GetArchitectureString() OVERRIDE {
49 return "arm";
50 }
51
Andreas Gampe849cc5e2014-11-18 13:46:46 -080052 std::string GetAssemblerParameters() OVERRIDE {
Calin Juravleddb7df22014-11-25 20:56:51 +000053 // Arm-v7a, cortex-a15 (means we have sdiv).
54 return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
Andreas Gampe849cc5e2014-11-18 13:46:46 -080055 }
56
57 const char* GetAssemblyHeader() OVERRIDE {
58 return kArm32AssemblyHeader;
59 }
60
Roland Levillain1a28fc42014-11-13 18:03:06 +000061 std::string GetDisassembleParameters() OVERRIDE {
62 return " -D -bbinary -marm --no-show-raw-insn";
63 }
64
65 void SetUpHelpers() OVERRIDE {
66 if (registers_.size() == 0) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -080067 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
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100129 set_ccs_.push_back(arm::kCcDontCare);
130 set_ccs_.push_back(arm::kCcSet);
131 set_ccs_.push_back(arm::kCcKeep);
132
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800133 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 }
Roland Levillain1a28fc42014-11-13 18:03:06 +0000199 }
200 }
201
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800202 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
Roland Levillain1a28fc42014-11-13 18:03:06 +0000225 void TearDown() OVERRIDE {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800226 AssemblerArmTest::TearDown();
Roland Levillain1a28fc42014-11-13 18:03:06 +0000227 STLDeleteElements(&registers_);
228 }
229
230 std::vector<arm::Register*> GetRegisters() OVERRIDE {
231 return registers_;
232 }
233
234 uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
235 return imm_value;
236 }
237
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800238 std::vector<arm::Condition>& GetConditions() OVERRIDE {
239 return conditions_;
240 }
241
242 std::string GetConditionString(arm::Condition c) OVERRIDE {
243 std::ostringstream oss;
244 oss << c;
245 return oss.str();
246 }
247
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100248 std::vector<arm::SetCc>& GetSetCcs() OVERRIDE {
249 return set_ccs_;
250 }
251
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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800257 arm::Register GetPCRegister() OVERRIDE {
258 return arm::R15;
259 }
260
261 std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
262 return shifter_operands_;
263 }
264
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
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:
Chris Larsendbce0d72015-09-17 13:34:00 -0700290 return Base::REG3_TOKEN;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800291 case 3:
292 return REG4_TOKEN;
293 default:
294 LOG(FATAL) << "Depth problem.";
295 UNREACHABLE();
296 }
297 }
298
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
Zheng Xuc6667102015-05-15 16:08:45 +0800310 // NOTE: Only support simple test like "aaa=bbb"
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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800326 void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
Zheng Xuc6667102015-05-15 16:08:45 +0800327 bool without_pc, std::string fmt, std::string filter,
328 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800329 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
330 for (auto reg : registers) {
331 std::string after_reg = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800332 std::string after_reg_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800333
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
Zheng Xuc6667102015-05-15 16:08:45 +0800342 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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800349 ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
350 }
351 }
352
353 void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
Zheng Xuc6667102015-05-15 16:08:45 +0800354 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
355 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800356 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
357 std::string after_shift = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800358 std::string after_shift_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800359
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
Zheng Xuc6667102015-05-15 16:08:45 +0800366 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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800373 ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
374 }
375 }
376
377 void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
Zheng Xuc6667102015-05-15 16:08:45 +0800378 bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
379 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800380 for (arm::Condition c : GetConditions()) {
381 std::string after_cond = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800382 std::string after_cond_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800383
384 size_t cond_index = after_cond.find(COND_TOKEN);
385 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100386 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800387 }
388
Zheng Xuc6667102015-05-15 16:08:45 +0800389 cond_index = after_cond_filter.find(COND_TOKEN);
390 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100391 after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Zheng Xuc6667102015-05-15 16:08:45 +0800392 }
393 if (EvalFilterString(after_cond_filter)) {
394 continue;
395 }
396
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800397 ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
398 }
399 }
400
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100401 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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800425 template <typename... Args>
426 void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800427 std::string fmt, std::string filter, std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800428 std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
429 for (auto reg : registers) {
430 std::string after_reg = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800431 std::string after_reg_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800432
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
Zheng Xuc6667102015-05-15 16:08:45 +0800441 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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800448 auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
449 TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800450 after_reg, after_reg_filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800451 }
452 }
453
454 template <typename... Args>
455 void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
Zheng Xuc6667102015-05-15 16:08:45 +0800456 bool without_pc, std::string fmt, std::string filter,
457 std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800458 for (const arm::ShifterOperand& shift : GetShiftOperands()) {
459 std::string after_shift = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800460 std::string after_shift_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800461
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
Zheng Xuc6667102015-05-15 16:08:45 +0800468 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
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800475 auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
476 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800477 after_shift, after_shift_filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800478 }
479 }
480
481 template <typename... Args>
482 void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800483 std::string fmt, std::string filter, std::ostringstream& oss) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800484 for (arm::Condition c : GetConditions()) {
485 std::string after_cond = fmt;
Zheng Xuc6667102015-05-15 16:08:45 +0800486 std::string after_cond_filter = filter;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800487
488 size_t cond_index = after_cond.find(COND_TOKEN);
489 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100490 after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800491 }
492
Zheng Xuc6667102015-05-15 16:08:45 +0800493 cond_index = after_cond_filter.find(COND_TOKEN);
494 if (cond_index != std::string::npos) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100495 after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
Zheng Xuc6667102015-05-15 16:08:45 +0800496 }
497 if (EvalFilterString(after_cond_filter)) {
498 continue;
499 }
500
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800501 auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
502 TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800503 after_cond, after_cond_filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800504 }
505 }
506
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100507 template <typename... Args>
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>
534 std::function<void(T1, T2)> GetBoundFunction2(void (Assembler::*f)(T1, T2)) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800535 return std::bind(f, GetAssembler(), _1, _2);
536 }
537
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100538 template <typename Assembler, typename T1, typename T2, typename T3>
539 std::function<void(T1, T2, T3)> GetBoundFunction3(void (Assembler::*f)(T1, T2, T3)) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800540 return std::bind(f, GetAssembler(), _1, _2, _3);
541 }
542
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100543 template <typename Assembler, typename T1, typename T2, typename T3, typename T4>
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800544 std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100545 void (Assembler::*f)(T1, T2, T3, T4)) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800546 return std::bind(f, GetAssembler(), _1, _2, _3, _4);
547 }
548
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100549 template <typename Assembler, typename T1, typename T2, typename T3, typename T4, typename T5>
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800550 std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100551 void (Assembler::*f)(T1, T2, T3, T4, T5)) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800552 return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
553 }
554
555 template <typename... Args>
556 void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
Zheng Xuc6667102015-05-15 16:08:45 +0800557 std::string fmt, std::string test_name, std::string filter) {
Andreas Gampeab65c672014-11-20 20:22:31 -0800558 first_ = false;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800559 WarnOnCombinations(CountHelper<Args...>(without_pc));
560
561 std::ostringstream oss;
562
Zheng Xuc6667102015-05-15 16:08:45 +0800563 TemplateHelper(f, 0, without_pc, fmt, filter, oss);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800564
565 oss << "\n"; // Trailing newline.
566
567 DriverStr(oss.str(), test_name);
568 }
569
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100570 template <typename Assembler, typename... Args>
571 void T2Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800572 std::string test_name, std::string filter = "") {
573 GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800574 }
575
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100576 template <typename Assembler, typename... Args>
577 void T3Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800578 std::string test_name, std::string filter = "") {
579 GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800580 }
581
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100582 template <typename Assembler, typename... Args>
583 void T4Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800584 std::string test_name, std::string filter = "") {
585 GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800586 }
587
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100588 template <typename Assembler, typename... Args>
589 void T5Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
Zheng Xuc6667102015-05-15 16:08:45 +0800590 std::string test_name, std::string filter = "") {
591 GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800592 }
593
Roland Levillain1a28fc42014-11-13 18:03:06 +0000594 private:
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800595 template <typename T>
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>
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
Roland Levillain1a28fc42014-11-13 18:03:06 +0000638 std::vector<arm::Register*> registers_;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800639 std::vector<arm::Condition> conditions_;
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100640 std::vector<arm::SetCc> set_ccs_;
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800641 std::vector<arm::ShifterOperand> shifter_operands_;
Roland Levillain1a28fc42014-11-13 18:03:06 +0000642};
643
644
645TEST_F(AssemblerArm32Test, Toolchain) {
646 EXPECT_TRUE(CheckTools());
647}
648
Roland Levillain1a28fc42014-11-13 18:03:06 +0000649TEST_F(AssemblerArm32Test, Sbfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800650 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});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000657
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800658 immediates.push_back({1, 1});
659 immediates.push_back({1, 15});
660 immediates.push_back({1, 31});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000661
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800662 immediates.push_back({8, 1});
663 immediates.push_back({8, 15});
664 immediates.push_back({8, 16});
665 immediates.push_back({8, 24});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000666
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800667 immediates.push_back({31, 1});
Roland Levillain1a28fc42014-11-13 18:03:06 +0000668
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800669 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
670 "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
Roland Levillain1a28fc42014-11-13 18:03:06 +0000671}
672
Roland Levillain981e4542014-11-14 11:47:14 +0000673TEST_F(AssemblerArm32Test, Ubfx) {
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800674 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});
Roland Levillain981e4542014-11-14 11:47:14 +0000681
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800682 immediates.push_back({1, 1});
683 immediates.push_back({1, 15});
684 immediates.push_back({1, 31});
Roland Levillain981e4542014-11-14 11:47:14 +0000685
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800686 immediates.push_back({8, 1});
687 immediates.push_back({8, 15});
688 immediates.push_back({8, 16});
689 immediates.push_back({8, 24});
Roland Levillain981e4542014-11-14 11:47:14 +0000690
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800691 immediates.push_back({31, 1});
Roland Levillain981e4542014-11-14 11:47:14 +0000692
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800693 DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
694 "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
695}
Roland Levillain981e4542014-11-14 11:47:14 +0000696
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800697TEST_F(AssemblerArm32Test, Mul) {
698 T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
699}
Roland Levillain981e4542014-11-14 11:47:14 +0000700
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800701TEST_F(AssemblerArm32Test, Mla) {
Zheng Xuc6667102015-05-15 16:08:45 +0800702 T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800703}
Roland Levillain981e4542014-11-14 11:47:14 +0000704
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800705TEST_F(AssemblerArm32Test, Umull) {
706 T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
Zheng Xuc6667102015-05-15 16:08:45 +0800707 "umull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800708}
Zheng Xuc6667102015-05-15 16:08:45 +0800709
710TEST_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}
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800714
715TEST_F(AssemblerArm32Test, Sdiv) {
716 T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
717}
718
719TEST_F(AssemblerArm32Test, Udiv) {
720 T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
721}
722
723TEST_F(AssemblerArm32Test, And) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100724 T5Helper(&arm::Arm32Assembler::and_, true, "and{cond}{s} {reg1}, {reg2}, {shift}", "and");
725}
726
727TEST_F(AssemblerArm32Test, Ands) {
728 T4Helper(&arm::Arm32Assembler::ands, true, "and{cond}s {reg1}, {reg2}, {shift}", "ands");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800729}
730
731TEST_F(AssemblerArm32Test, Eor) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100732 T5Helper(&arm::Arm32Assembler::eor, true, "eor{cond}{s} {reg1}, {reg2}, {shift}", "eor");
733}
734
735TEST_F(AssemblerArm32Test, Eors) {
736 T4Helper(&arm::Arm32Assembler::eors, true, "eor{cond}s {reg1}, {reg2}, {shift}", "eors");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800737}
738
739TEST_F(AssemblerArm32Test, Orr) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100740 T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800741}
742
743TEST_F(AssemblerArm32Test, Orrs) {
744 T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
745}
746
747TEST_F(AssemblerArm32Test, Bic) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100748 T5Helper(&arm::Arm32Assembler::bic, true, "bic{cond}{s} {reg1}, {reg2}, {shift}", "bic");
749}
750
751TEST_F(AssemblerArm32Test, Bics) {
752 T4Helper(&arm::Arm32Assembler::bics, true, "bic{cond}s {reg1}, {reg2}, {shift}", "bics");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800753}
754
755TEST_F(AssemblerArm32Test, Mov) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100756 T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800757}
758
759TEST_F(AssemblerArm32Test, Movs) {
760 T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
761}
762
763TEST_F(AssemblerArm32Test, Mvn) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100764 T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800765}
766
767TEST_F(AssemblerArm32Test, Mvns) {
768 T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
769}
770
771TEST_F(AssemblerArm32Test, Add) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100772 T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800773}
774
775TEST_F(AssemblerArm32Test, Adds) {
776 T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
777}
778
779TEST_F(AssemblerArm32Test, Adc) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100780 T5Helper(&arm::Arm32Assembler::adc, false, "adc{cond}{s} {reg1}, {reg2}, {shift}", "adc");
781}
782
783TEST_F(AssemblerArm32Test, Adcs) {
784 T4Helper(&arm::Arm32Assembler::adcs, false, "adc{cond}s {reg1}, {reg2}, {shift}", "adcs");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800785}
786
787TEST_F(AssemblerArm32Test, Sub) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100788 T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800789}
790
791TEST_F(AssemblerArm32Test, Subs) {
792 T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
793}
794
795TEST_F(AssemblerArm32Test, Sbc) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100796 T5Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond}{s} {reg1}, {reg2}, {shift}", "sbc");
797}
798
799TEST_F(AssemblerArm32Test, Sbcs) {
800 T4Helper(&arm::Arm32Assembler::sbcs, false, "sbc{cond}s {reg1}, {reg2}, {shift}", "sbcs");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800801}
802
803TEST_F(AssemblerArm32Test, Rsb) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100804 T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800805}
806
807TEST_F(AssemblerArm32Test, Rsbs) {
808 T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
809}
810
811TEST_F(AssemblerArm32Test, Rsc) {
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100812 T5Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond}{s} {reg1}, {reg2}, {shift}", "rsc");
813}
814
815TEST_F(AssemblerArm32Test, Rscs) {
816 T4Helper(&arm::Arm32Assembler::rscs, false, "rsc{cond}s {reg1}, {reg2}, {shift}", "rscs");
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800817}
818
Zheng Xuc6667102015-05-15 16:08:45 +0800819/* TODO: Need better filter support.
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800820TEST_F(AssemblerArm32Test, Strex) {
Zheng Xuc6667102015-05-15 16:08:45 +0800821 T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
822 "{reg1}={reg2}||{reg1}={reg3}"); // Skip the cases where reg1 == reg2 || reg1 == reg3.
Andreas Gampe849cc5e2014-11-18 13:46:46 -0800823}
824*/
825
826TEST_F(AssemblerArm32Test, Clz) {
827 T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
828}
829
830TEST_F(AssemblerArm32Test, Tst) {
831 T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
832}
833
834TEST_F(AssemblerArm32Test, Teq) {
835 T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
836}
837
838TEST_F(AssemblerArm32Test, Cmp) {
839 T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
840}
841
842TEST_F(AssemblerArm32Test, Cmn) {
843 T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
844}
845
846TEST_F(AssemblerArm32Test, Blx) {
847 T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
848}
849
850TEST_F(AssemblerArm32Test, Bx) {
851 T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
Roland Levillain981e4542014-11-14 11:47:14 +0000852}
853
Calin Juravleddb7df22014-11-25 20:56:51 +0000854TEST_F(AssemblerArm32Test, Vmstat) {
855 GetAssembler()->vmstat();
856
857 const char* expected = "vmrs APSR_nzcv, FPSCR\n";
858
859 DriverStr(expected, "vmrs");
860}
861
Calin Juravle52c48962014-12-16 17:02:57 +0000862TEST_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
874TEST_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
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100886TEST_F(AssemblerArm32Test, rbit) {
887 T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit");
888}
889
Roland Levillain1a28fc42014-11-13 18:03:06 +0000890} // namespace art