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(&registers_);
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