• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                                                    arm::SetCc> {
47  protected:
GetArchitectureString()48   std::string GetArchitectureString() OVERRIDE {
49     return "arm";
50   }
51 
GetAssemblerParameters()52   std::string GetAssemblerParameters() OVERRIDE {
53     // Arm-v7a, cortex-a15 (means we have sdiv).
54     return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
55   }
56 
GetAssemblyHeader()57   const char* GetAssemblyHeader() OVERRIDE {
58     return kArm32AssemblyHeader;
59   }
60 
GetDisassembleParameters()61   std::string GetDisassembleParameters() OVERRIDE {
62     return " -D -bbinary -marm --no-show-raw-insn";
63   }
64 
SetUpHelpers()65   void SetUpHelpers() OVERRIDE {
66     if (registers_.size() == 0) {
67       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 
129     set_ccs_.push_back(arm::kCcDontCare);
130     set_ccs_.push_back(arm::kCcSet);
131     set_ccs_.push_back(arm::kCcKeep);
132 
133     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       }
199     }
200   }
201 
CreateRegisterShifts(std::vector<arm::Register * > & base_regs,int32_t shift_min,int32_t shift_max)202   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 
TearDown()225   void TearDown() OVERRIDE {
226     AssemblerArmTest::TearDown();
227     STLDeleteElements(&registers_);
228   }
229 
GetRegisters()230   std::vector<arm::Register*> GetRegisters() OVERRIDE {
231     return registers_;
232   }
233 
CreateImmediate(int64_t imm_value)234   uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
235     return imm_value;
236   }
237 
GetConditions()238   std::vector<arm::Condition>& GetConditions() OVERRIDE {
239     return conditions_;
240   }
241 
GetConditionString(arm::Condition c)242   std::string GetConditionString(arm::Condition c) OVERRIDE {
243     std::ostringstream oss;
244     oss << c;
245     return oss.str();
246   }
247 
GetSetCcs()248   std::vector<arm::SetCc>& GetSetCcs() OVERRIDE {
249     return set_ccs_;
250   }
251 
GetSetCcString(arm::SetCc s)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 
GetPCRegister()257   arm::Register GetPCRegister() OVERRIDE {
258     return arm::R15;
259   }
260 
GetShiftOperands()261   std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
262     return shifter_operands_;
263   }
264 
GetShiftString(arm::ShifterOperand sop)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 
GetRegTokenFromDepth(int depth)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:
290         return Base::REG3_TOKEN;
291       case 3:
292         return REG4_TOKEN;
293       default:
294         LOG(FATAL) << "Depth problem.";
295         UNREACHABLE();
296     }
297   }
298 
ExecuteAndPrint(std::function<void ()> f,std::string fmt,std::ostringstream & oss)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 
310   // NOTE: Only support simple test like "aaa=bbb"
EvalFilterString(std::string filter)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 
TemplateHelper(std::function<void (arm::Register)> f,int depth ATTRIBUTE_UNUSED,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)326   void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
327                       bool without_pc, std::string fmt, std::string filter,
328                       std::ostringstream& oss) {
329     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
330     for (auto reg : registers) {
331       std::string after_reg = fmt;
332       std::string after_reg_filter = filter;
333 
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 
342       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 
349       ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
350     }
351   }
352 
TemplateHelper(std::function<void (const arm::ShifterOperand &)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::string filter,std::ostringstream & oss)353   void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
354                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
355                       std::ostringstream& oss) {
356     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
357       std::string after_shift = fmt;
358       std::string after_shift_filter = filter;
359 
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 
366       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 
373       ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
374     }
375   }
376 
TemplateHelper(std::function<void (arm::Condition)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::string filter,std::ostringstream & oss)377   void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
378                       bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
379                       std::ostringstream& oss) {
380     for (arm::Condition c : GetConditions()) {
381       std::string after_cond = fmt;
382       std::string after_cond_filter = filter;
383 
384       size_t cond_index = after_cond.find(COND_TOKEN);
385       if (cond_index != std::string::npos) {
386         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
387       }
388 
389       cond_index = after_cond_filter.find(COND_TOKEN);
390       if (cond_index != std::string::npos) {
391         after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
392       }
393       if (EvalFilterString(after_cond_filter)) {
394         continue;
395       }
396 
397       ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
398     }
399   }
400 
TemplateHelper(std::function<void (arm::SetCc)> f,int depth ATTRIBUTE_UNUSED,bool without_pc ATTRIBUTE_UNUSED,std::string fmt,std::string filter,std::ostringstream & oss)401   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 
425   template <typename... Args>
TemplateHelper(std::function<void (arm::Register,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)426   void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
427                       std::string fmt, std::string filter, std::ostringstream& oss) {
428     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
429     for (auto reg : registers) {
430       std::string after_reg = fmt;
431       std::string after_reg_filter = filter;
432 
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 
441       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 
448       auto lambda = [&] (Args... args) { f(*reg, args...); };  // NOLINT [readability/braces] [4]
449       TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
450           after_reg, after_reg_filter, oss);
451     }
452   }
453 
454   template <typename... Args>
TemplateHelper(std::function<void (const arm::ShifterOperand &,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)455   void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
456                       bool without_pc, std::string fmt, std::string filter,
457                       std::ostringstream& oss) {
458     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
459       std::string after_shift = fmt;
460       std::string after_shift_filter = filter;
461 
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 
468       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 
475       auto lambda = [&] (Args... args) { f(shift, args...); };  // NOLINT [readability/braces] [4]
476       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
477           after_shift, after_shift_filter, oss);
478     }
479   }
480 
481   template <typename... Args>
TemplateHelper(std::function<void (arm::Condition,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)482   void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
483                       std::string fmt, std::string filter, std::ostringstream& oss) {
484     for (arm::Condition c : GetConditions()) {
485       std::string after_cond = fmt;
486       std::string after_cond_filter = filter;
487 
488       size_t cond_index = after_cond.find(COND_TOKEN);
489       if (cond_index != std::string::npos) {
490         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
491       }
492 
493       cond_index = after_cond_filter.find(COND_TOKEN);
494       if (cond_index != std::string::npos) {
495         after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
496       }
497       if (EvalFilterString(after_cond_filter)) {
498         continue;
499       }
500 
501       auto lambda = [&] (Args... args) { f(c, args...); };  // NOLINT [readability/braces] [4]
502       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
503           after_cond, after_cond_filter, oss);
504     }
505   }
506 
507   template <typename... Args>
TemplateHelper(std::function<void (arm::SetCc,Args...)> f,int depth,bool without_pc,std::string fmt,std::string filter,std::ostringstream & oss)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>
GetBoundFunction2(void (Assembler::* f)(T1,T2))534   std::function<void(T1, T2)> GetBoundFunction2(void (Assembler::*f)(T1, T2)) {
535     return std::bind(f, GetAssembler(), _1, _2);
536   }
537 
538   template <typename Assembler, typename T1, typename T2, typename T3>
GetBoundFunction3(void (Assembler::* f)(T1,T2,T3))539   std::function<void(T1, T2, T3)> GetBoundFunction3(void (Assembler::*f)(T1, T2, T3)) {
540     return std::bind(f, GetAssembler(), _1, _2, _3);
541   }
542 
543   template <typename Assembler, typename T1, typename T2, typename T3, typename T4>
GetBoundFunction4(void (Assembler::* f)(T1,T2,T3,T4))544   std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
545       void (Assembler::*f)(T1, T2, T3, T4)) {
546     return std::bind(f, GetAssembler(), _1, _2, _3, _4);
547   }
548 
549   template <typename Assembler, typename T1, typename T2, typename T3, typename T4, typename T5>
GetBoundFunction5(void (Assembler::* f)(T1,T2,T3,T4,T5))550   std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
551       void (Assembler::*f)(T1, T2, T3, T4, T5)) {
552     return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
553   }
554 
555   template <typename... Args>
GenericTemplateHelper(std::function<void (Args...)> f,bool without_pc,std::string fmt,std::string test_name,std::string filter)556   void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
557                              std::string fmt, std::string test_name, std::string filter) {
558     first_ = false;
559     WarnOnCombinations(CountHelper<Args...>(without_pc));
560 
561     std::ostringstream oss;
562 
563     TemplateHelper(f, 0, without_pc, fmt, filter, oss);
564 
565     oss << "\n";  // Trailing newline.
566 
567     DriverStr(oss.str(), test_name);
568   }
569 
570   template <typename Assembler, typename... Args>
T2Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")571   void T2Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
572                 std::string test_name, std::string filter = "") {
573     GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
574   }
575 
576   template <typename Assembler, typename... Args>
T3Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")577   void T3Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
578       std::string test_name, std::string filter = "") {
579     GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
580   }
581 
582   template <typename Assembler, typename... Args>
T4Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")583   void T4Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
584       std::string test_name, std::string filter = "") {
585     GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
586   }
587 
588   template <typename Assembler, typename... Args>
T5Helper(void (Assembler::* f)(Args...),bool without_pc,std::string fmt,std::string test_name,std::string filter="")589   void T5Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
590       std::string test_name, std::string filter = "") {
591     GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
592   }
593 
594  private:
595   template <typename T>
CountHelper(bool without_pc)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>
CountHelper(bool without_pc)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 
638   std::vector<arm::Register*> registers_;
639   std::vector<arm::Condition> conditions_;
640   std::vector<arm::SetCc> set_ccs_;
641   std::vector<arm::ShifterOperand> shifter_operands_;
642 };
643 
644 
TEST_F(AssemblerArm32Test,Toolchain)645 TEST_F(AssemblerArm32Test, Toolchain) {
646   EXPECT_TRUE(CheckTools());
647 }
648 
TEST_F(AssemblerArm32Test,Sbfx)649 TEST_F(AssemblerArm32Test, Sbfx) {
650   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});
657 
658   immediates.push_back({1, 1});
659   immediates.push_back({1, 15});
660   immediates.push_back({1, 31});
661 
662   immediates.push_back({8, 1});
663   immediates.push_back({8, 15});
664   immediates.push_back({8, 16});
665   immediates.push_back({8, 24});
666 
667   immediates.push_back({31, 1});
668 
669   DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
670                         "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
671 }
672 
TEST_F(AssemblerArm32Test,Ubfx)673 TEST_F(AssemblerArm32Test, Ubfx) {
674   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});
681 
682   immediates.push_back({1, 1});
683   immediates.push_back({1, 15});
684   immediates.push_back({1, 31});
685 
686   immediates.push_back({8, 1});
687   immediates.push_back({8, 15});
688   immediates.push_back({8, 16});
689   immediates.push_back({8, 24});
690 
691   immediates.push_back({31, 1});
692 
693   DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
694                         "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
695 }
696 
TEST_F(AssemblerArm32Test,Mul)697 TEST_F(AssemblerArm32Test, Mul) {
698   T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
699 }
700 
TEST_F(AssemblerArm32Test,Mla)701 TEST_F(AssemblerArm32Test, Mla) {
702   T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
703 }
704 
TEST_F(AssemblerArm32Test,Umull)705 TEST_F(AssemblerArm32Test, Umull) {
706   T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
707            "umull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
708 }
709 
TEST_F(AssemblerArm32Test,Smull)710 TEST_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 }
714 
TEST_F(AssemblerArm32Test,Sdiv)715 TEST_F(AssemblerArm32Test, Sdiv) {
716   T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
717 }
718 
TEST_F(AssemblerArm32Test,Udiv)719 TEST_F(AssemblerArm32Test, Udiv) {
720   T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
721 }
722 
TEST_F(AssemblerArm32Test,And)723 TEST_F(AssemblerArm32Test, And) {
724   T5Helper(&arm::Arm32Assembler::and_, true, "and{cond}{s} {reg1}, {reg2}, {shift}", "and");
725 }
726 
TEST_F(AssemblerArm32Test,Ands)727 TEST_F(AssemblerArm32Test, Ands) {
728   T4Helper(&arm::Arm32Assembler::ands, true, "and{cond}s {reg1}, {reg2}, {shift}", "ands");
729 }
730 
TEST_F(AssemblerArm32Test,Eor)731 TEST_F(AssemblerArm32Test, Eor) {
732   T5Helper(&arm::Arm32Assembler::eor, true, "eor{cond}{s} {reg1}, {reg2}, {shift}", "eor");
733 }
734 
TEST_F(AssemblerArm32Test,Eors)735 TEST_F(AssemblerArm32Test, Eors) {
736   T4Helper(&arm::Arm32Assembler::eors, true, "eor{cond}s {reg1}, {reg2}, {shift}", "eors");
737 }
738 
TEST_F(AssemblerArm32Test,Orr)739 TEST_F(AssemblerArm32Test, Orr) {
740   T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr");
741 }
742 
TEST_F(AssemblerArm32Test,Orrs)743 TEST_F(AssemblerArm32Test, Orrs) {
744   T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
745 }
746 
TEST_F(AssemblerArm32Test,Bic)747 TEST_F(AssemblerArm32Test, Bic) {
748   T5Helper(&arm::Arm32Assembler::bic, true, "bic{cond}{s} {reg1}, {reg2}, {shift}", "bic");
749 }
750 
TEST_F(AssemblerArm32Test,Bics)751 TEST_F(AssemblerArm32Test, Bics) {
752   T4Helper(&arm::Arm32Assembler::bics, true, "bic{cond}s {reg1}, {reg2}, {shift}", "bics");
753 }
754 
TEST_F(AssemblerArm32Test,Mov)755 TEST_F(AssemblerArm32Test, Mov) {
756   T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov");
757 }
758 
TEST_F(AssemblerArm32Test,Movs)759 TEST_F(AssemblerArm32Test, Movs) {
760   T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
761 }
762 
TEST_F(AssemblerArm32Test,Mvn)763 TEST_F(AssemblerArm32Test, Mvn) {
764   T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn");
765 }
766 
TEST_F(AssemblerArm32Test,Mvns)767 TEST_F(AssemblerArm32Test, Mvns) {
768   T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
769 }
770 
TEST_F(AssemblerArm32Test,Add)771 TEST_F(AssemblerArm32Test, Add) {
772   T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add");
773 }
774 
TEST_F(AssemblerArm32Test,Adds)775 TEST_F(AssemblerArm32Test, Adds) {
776   T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
777 }
778 
TEST_F(AssemblerArm32Test,Adc)779 TEST_F(AssemblerArm32Test, Adc) {
780   T5Helper(&arm::Arm32Assembler::adc, false, "adc{cond}{s} {reg1}, {reg2}, {shift}", "adc");
781 }
782 
TEST_F(AssemblerArm32Test,Adcs)783 TEST_F(AssemblerArm32Test, Adcs) {
784   T4Helper(&arm::Arm32Assembler::adcs, false, "adc{cond}s {reg1}, {reg2}, {shift}", "adcs");
785 }
786 
TEST_F(AssemblerArm32Test,Sub)787 TEST_F(AssemblerArm32Test, Sub) {
788   T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub");
789 }
790 
TEST_F(AssemblerArm32Test,Subs)791 TEST_F(AssemblerArm32Test, Subs) {
792   T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
793 }
794 
TEST_F(AssemblerArm32Test,Sbc)795 TEST_F(AssemblerArm32Test, Sbc) {
796   T5Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond}{s} {reg1}, {reg2}, {shift}", "sbc");
797 }
798 
TEST_F(AssemblerArm32Test,Sbcs)799 TEST_F(AssemblerArm32Test, Sbcs) {
800   T4Helper(&arm::Arm32Assembler::sbcs, false, "sbc{cond}s {reg1}, {reg2}, {shift}", "sbcs");
801 }
802 
TEST_F(AssemblerArm32Test,Rsb)803 TEST_F(AssemblerArm32Test, Rsb) {
804   T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb");
805 }
806 
TEST_F(AssemblerArm32Test,Rsbs)807 TEST_F(AssemblerArm32Test, Rsbs) {
808   T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
809 }
810 
TEST_F(AssemblerArm32Test,Rsc)811 TEST_F(AssemblerArm32Test, Rsc) {
812   T5Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond}{s} {reg1}, {reg2}, {shift}", "rsc");
813 }
814 
TEST_F(AssemblerArm32Test,Rscs)815 TEST_F(AssemblerArm32Test, Rscs) {
816   T4Helper(&arm::Arm32Assembler::rscs, false, "rsc{cond}s {reg1}, {reg2}, {shift}", "rscs");
817 }
818 
819 /* TODO: Need better filter support.
820 TEST_F(AssemblerArm32Test, Strex) {
821   T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
822            "{reg1}={reg2}||{reg1}={reg3}");  // Skip the cases where reg1 == reg2 || reg1 == reg3.
823 }
824 */
825 
TEST_F(AssemblerArm32Test,Clz)826 TEST_F(AssemblerArm32Test, Clz) {
827   T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
828 }
829 
TEST_F(AssemblerArm32Test,Tst)830 TEST_F(AssemblerArm32Test, Tst) {
831   T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
832 }
833 
TEST_F(AssemblerArm32Test,Teq)834 TEST_F(AssemblerArm32Test, Teq) {
835   T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
836 }
837 
TEST_F(AssemblerArm32Test,Cmp)838 TEST_F(AssemblerArm32Test, Cmp) {
839   T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
840 }
841 
TEST_F(AssemblerArm32Test,Cmn)842 TEST_F(AssemblerArm32Test, Cmn) {
843   T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
844 }
845 
TEST_F(AssemblerArm32Test,Blx)846 TEST_F(AssemblerArm32Test, Blx) {
847   T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
848 }
849 
TEST_F(AssemblerArm32Test,Bx)850 TEST_F(AssemblerArm32Test, Bx) {
851   T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
852 }
853 
TEST_F(AssemblerArm32Test,Vmstat)854 TEST_F(AssemblerArm32Test, Vmstat) {
855   GetAssembler()->vmstat();
856 
857   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
858 
859   DriverStr(expected, "vmrs");
860 }
861 
TEST_F(AssemblerArm32Test,ldrexd)862 TEST_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 
TEST_F(AssemblerArm32Test,strexd)874 TEST_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 
TEST_F(AssemblerArm32Test,rbit)886 TEST_F(AssemblerArm32Test, rbit) {
887   T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit");
888 }
889 
TEST_F(AssemblerArm32Test,rev)890 TEST_F(AssemblerArm32Test, rev) {
891   T3Helper(&arm::Arm32Assembler::rev, true, "rev{cond} {reg1}, {reg2}", "rev");
892 }
893 
TEST_F(AssemblerArm32Test,rev16)894 TEST_F(AssemblerArm32Test, rev16) {
895   T3Helper(&arm::Arm32Assembler::rev16, true, "rev16{cond} {reg1}, {reg2}", "rev16");
896 }
897 
TEST_F(AssemblerArm32Test,revsh)898 TEST_F(AssemblerArm32Test, revsh) {
899   T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh");
900 }
901 
902 }  // namespace art
903