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
26namespace art {
27
28using std::placeholders::_1;
29using std::placeholders::_2;
30using std::placeholders::_3;
31using std::placeholders::_4;
32using std::placeholders::_5;
33
34// To speed up tests, don't use all register combinations.
35static constexpr bool kUseSparseRegisterList = true;
36
37// To speed up tests, don't use all condition codes.
38static constexpr bool kUseSparseConditionList = true;
39
40// To speed up tests, don't use all shift immediates.
41static constexpr bool kUseSparseShiftImmediates = true;
42
43class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler,
44                                                   arm::Register, arm::SRegister,
45                                                   uint32_t, arm::ShifterOperand, arm::Condition,
46                                                   arm::SetCc> {
47 protected:
48  std::string GetArchitectureString() OVERRIDE {
49    return "arm";
50  }
51
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
57  const char* GetAssemblyHeader() OVERRIDE {
58    return kArm32AssemblyHeader;
59  }
60
61  std::string GetDisassembleParameters() OVERRIDE {
62    return " -D -bbinary -marm --no-show-raw-insn";
63  }
64
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
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
225  void TearDown() OVERRIDE {
226    AssemblerArmTest::TearDown();
227    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
238  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
248  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
257  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:
290        return Base::REG3_TOKEN;
291      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
310  // 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
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
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
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
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>
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>
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>
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>
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)) {
535    return std::bind(f, GetAssembler(), _1, _2);
536  }
537
538  template <typename Assembler, typename T1, typename T2, typename 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>
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>
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>
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>
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>
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>
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>
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>
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
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
645TEST_F(AssemblerArm32Test, Toolchain) {
646  EXPECT_TRUE(CheckTools());
647}
648
649TEST_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
673TEST_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
697TEST_F(AssemblerArm32Test, Mul) {
698  T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
699}
700
701TEST_F(AssemblerArm32Test, Mla) {
702  T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
703}
704
705TEST_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
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}
714
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) {
724  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");
729}
730
731TEST_F(AssemblerArm32Test, Eor) {
732  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");
737}
738
739TEST_F(AssemblerArm32Test, Orr) {
740  T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr");
741}
742
743TEST_F(AssemblerArm32Test, Orrs) {
744  T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
745}
746
747TEST_F(AssemblerArm32Test, Bic) {
748  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");
753}
754
755TEST_F(AssemblerArm32Test, Mov) {
756  T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov");
757}
758
759TEST_F(AssemblerArm32Test, Movs) {
760  T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
761}
762
763TEST_F(AssemblerArm32Test, Mvn) {
764  T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn");
765}
766
767TEST_F(AssemblerArm32Test, Mvns) {
768  T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
769}
770
771TEST_F(AssemblerArm32Test, Add) {
772  T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add");
773}
774
775TEST_F(AssemblerArm32Test, Adds) {
776  T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
777}
778
779TEST_F(AssemblerArm32Test, Adc) {
780  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");
785}
786
787TEST_F(AssemblerArm32Test, Sub) {
788  T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub");
789}
790
791TEST_F(AssemblerArm32Test, Subs) {
792  T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
793}
794
795TEST_F(AssemblerArm32Test, Sbc) {
796  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");
801}
802
803TEST_F(AssemblerArm32Test, Rsb) {
804  T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb");
805}
806
807TEST_F(AssemblerArm32Test, Rsbs) {
808  T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
809}
810
811TEST_F(AssemblerArm32Test, Rsc) {
812  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");
817}
818
819/* TODO: Need better filter support.
820TEST_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
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");
852}
853
854TEST_F(AssemblerArm32Test, Vmstat) {
855  GetAssembler()->vmstat();
856
857  const char* expected = "vmrs APSR_nzcv, FPSCR\n";
858
859  DriverStr(expected, "vmrs");
860}
861
862TEST_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
886TEST_F(AssemblerArm32Test, rbit) {
887  T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit");
888}
889
890TEST_F(AssemblerArm32Test, rev) {
891  T3Helper(&arm::Arm32Assembler::rev, true, "rev{cond} {reg1}, {reg2}", "rev");
892}
893
894TEST_F(AssemblerArm32Test, rev16) {
895  T3Helper(&arm::Arm32Assembler::rev16, true, "rev16{cond} {reg1}, {reg2}", "rev16");
896}
897
898TEST_F(AssemblerArm32Test, revsh) {
899  T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh");
900}
901
902}  // namespace art
903