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 #ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
18 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
19 
20 #include "utils/assembler_test.h"
21 
22 namespace art {
23 
24 template<typename Ass,
25          typename Reg,
26          typename FPReg,
27          typename Imm,
28          typename SOp,
29          typename Cond,
30          typename SetCc>
31 class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> {
32  public:
33   typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base;
34 
35   using Base::GetRegisters;
36   using Base::GetRegName;
37   using Base::CreateImmediate;
38   using Base::WarnOnCombinations;
39 
40   static constexpr int64_t kFullImmRangeThreshold = 32;
41 
FillImmediates(std::vector<Imm> & immediates,int64_t imm_min,int64_t imm_max)42   virtual void FillImmediates(std::vector<Imm>& immediates, int64_t imm_min, int64_t imm_max) {
43     // Small range: do completely.
44     if (imm_max - imm_min <= kFullImmRangeThreshold) {
45       for (int64_t i = imm_min; i <= imm_max; ++i) {
46         immediates.push_back(CreateImmediate(i));
47       }
48     } else {
49       immediates.push_back(CreateImmediate(imm_min));
50       immediates.push_back(CreateImmediate(imm_max));
51       if (imm_min < imm_max - 1) {
52         immediates.push_back(CreateImmediate(imm_min + 1));
53       }
54       if (imm_min < imm_max - 2) {
55         immediates.push_back(CreateImmediate(imm_min + 2));
56       }
57       if (imm_min < imm_max - 3) {
58         immediates.push_back(CreateImmediate(imm_max - 1));
59       }
60       if (imm_min < imm_max - 4) {
61         immediates.push_back(CreateImmediate((imm_min + imm_max) / 2));
62       }
63     }
64   }
65 
RepeatRRIIC(void (Ass::* f)(Reg,Reg,Imm,Imm,Cond),int64_t imm1_min,int64_t imm1_max,int64_t imm2_min,int64_t imm2_max,std::string fmt)66   std::string RepeatRRIIC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
67                           int64_t imm1_min, int64_t imm1_max,
68                           int64_t imm2_min, int64_t imm2_max,
69                           std::string fmt) {
70     return RepeatTemplatedRRIIC(f, GetRegisters(), GetRegisters(),
71                                 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
72                                 &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
73                                 imm1_min, imm1_max, imm2_min, imm2_max,
74                                 fmt);
75   }
76 
77   template <typename Reg1, typename Reg2>
RepeatTemplatedRRIIC(void (Ass::* f)(Reg1,Reg2,Imm,Imm,Cond),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerArmTest::* GetName1)(const Reg1 &),std::string (AssemblerArmTest::* GetName2)(const Reg2 &),int64_t imm1_min,int64_t imm1_max,int64_t imm2_min,int64_t imm2_max,std::string fmt)78   std::string RepeatTemplatedRRIIC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
79                                    const std::vector<Reg1*> reg1_registers,
80                                    const std::vector<Reg2*> reg2_registers,
81                                    std::string (AssemblerArmTest::*GetName1)(const Reg1&),
82                                    std::string (AssemblerArmTest::*GetName2)(const Reg2&),
83                                    int64_t imm1_min, int64_t imm1_max,
84                                    int64_t imm2_min, int64_t imm2_max,
85                                    std::string fmt) {
86     std::vector<Imm> immediates1;
87     FillImmediates(immediates1, imm1_min, imm1_max);
88     std::vector<Imm> immediates2;
89     FillImmediates(immediates2, imm2_min, imm2_max);
90 
91     std::vector<Cond>& cond = GetConditions();
92 
93     WarnOnCombinations(cond.size() * immediates1.size() * immediates2.size() *
94                        reg1_registers.size() * reg2_registers.size());
95 
96     std::ostringstream oss;
97     bool first = true;
98     for (Cond& c : cond) {
99       std::string after_cond = fmt;
100 
101       size_t cond_index = after_cond.find(COND_TOKEN);
102       if (cond_index != std::string::npos) {
103         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
104       }
105 
106       for (Imm i : immediates1) {
107         std::string base = after_cond;
108 
109         size_t imm1_index = base.find(IMM1_TOKEN);
110         if (imm1_index != std::string::npos) {
111           std::ostringstream sreg;
112           sreg << i;
113           std::string imm_string = sreg.str();
114           base.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
115         }
116 
117         for (Imm j : immediates2) {
118           std::string base2 = base;
119 
120           size_t imm2_index = base2.find(IMM2_TOKEN);
121           if (imm2_index != std::string::npos) {
122             std::ostringstream sreg;
123             sreg << j;
124             std::string imm_string = sreg.str();
125             base2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
126           }
127 
128           for (auto reg1 : reg1_registers) {
129             std::string base3 = base2;
130 
131             std::string reg1_string = (this->*GetName1)(*reg1);
132             size_t reg1_index;
133             while ((reg1_index = base3.find(Base::REG1_TOKEN)) != std::string::npos) {
134               base3.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
135             }
136 
137             for (auto reg2 : reg2_registers) {
138               std::string base4 = base3;
139 
140               std::string reg2_string = (this->*GetName2)(*reg2);
141               size_t reg2_index;
142               while ((reg2_index = base4.find(Base::REG2_TOKEN)) != std::string::npos) {
143                 base4.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
144               }
145 
146               if (first) {
147                 first = false;
148               } else {
149                 oss << "\n";
150               }
151               oss << base4;
152 
153               (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
154             }
155           }
156         }
157       }
158     }
159     // Add a newline at the end.
160     oss << "\n";
161 
162     return oss.str();
163   }
164 
RepeatRRiiC(void (Ass::* f)(Reg,Reg,Imm,Imm,Cond),std::vector<std::pair<Imm,Imm>> & immediates,std::string fmt)165   std::string RepeatRRiiC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
166                           std::vector<std::pair<Imm, Imm>>& immediates,
167                           std::string fmt) {
168     return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(),
169         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
170         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
171         immediates, fmt);
172   }
173 
174   template <typename Reg1, typename Reg2>
RepeatTemplatedRRiiC(void (Ass::* f)(Reg1,Reg2,Imm,Imm,Cond),const std::vector<Reg1 * > reg1_registers,const std::vector<Reg2 * > reg2_registers,std::string (AssemblerArmTest::* GetName1)(const Reg1 &),std::string (AssemblerArmTest::* GetName2)(const Reg2 &),std::vector<std::pair<Imm,Imm>> & immediates,std::string fmt)175   std::string RepeatTemplatedRRiiC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
176         const std::vector<Reg1*> reg1_registers,
177         const std::vector<Reg2*> reg2_registers,
178         std::string (AssemblerArmTest::*GetName1)(const Reg1&),
179         std::string (AssemblerArmTest::*GetName2)(const Reg2&),
180         std::vector<std::pair<Imm, Imm>>& immediates,
181         std::string fmt) {
182     std::vector<Cond>& cond = GetConditions();
183 
184     WarnOnCombinations(cond.size() * immediates.size() * reg1_registers.size() *
185                        reg2_registers.size());
186 
187     std::ostringstream oss;
188     bool first = true;
189     for (Cond& c : cond) {
190       std::string after_cond = fmt;
191 
192       size_t cond_index = after_cond.find(COND_TOKEN);
193       if (cond_index != std::string::npos) {
194         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
195       }
196 
197       for (std::pair<Imm, Imm>& pair : immediates) {
198         Imm i = pair.first;
199         Imm j = pair.second;
200         std::string after_imm1 = after_cond;
201 
202         size_t imm1_index = after_imm1.find(IMM1_TOKEN);
203         if (imm1_index != std::string::npos) {
204           std::ostringstream sreg;
205           sreg << i;
206           std::string imm_string = sreg.str();
207           after_imm1.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
208         }
209 
210         std::string after_imm2 = after_imm1;
211 
212         size_t imm2_index = after_imm2.find(IMM2_TOKEN);
213         if (imm2_index != std::string::npos) {
214           std::ostringstream sreg;
215           sreg << j;
216           std::string imm_string = sreg.str();
217           after_imm2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
218         }
219 
220         for (auto reg1 : reg1_registers) {
221           std::string after_reg1 = after_imm2;
222 
223           std::string reg1_string = (this->*GetName1)(*reg1);
224           size_t reg1_index;
225           while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
226             after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
227           }
228 
229           for (auto reg2 : reg2_registers) {
230             std::string after_reg2 = after_reg1;
231 
232             std::string reg2_string = (this->*GetName2)(*reg2);
233             size_t reg2_index;
234             while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
235               after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
236             }
237 
238             if (first) {
239               first = false;
240             } else {
241               oss << "\n";
242             }
243             oss << after_reg2;
244 
245             (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
246           }
247         }
248       }
249     }
250     // Add a newline at the end.
251     oss << "\n";
252 
253     return oss.str();
254   }
255 
RepeatRRC(void (Ass::* f)(Reg,Reg,Cond),std::string fmt)256   std::string RepeatRRC(void (Ass::*f)(Reg, Reg, Cond), std::string fmt) {
257     return RepeatTemplatedRRC(f, GetRegisters(), GetRegisters(), GetConditions(),
258         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
259         &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
260         fmt);
261   }
262 
263   template <typename Reg1, typename Reg2>
RepeatTemplatedRRC(void (Ass::* f)(Reg1,Reg2,Cond),const std::vector<Reg1 * > & reg1_registers,const std::vector<Reg2 * > & reg2_registers,const std::vector<Cond> & cond,std::string (AssemblerArmTest::* GetName1)(const Reg1 &),std::string (AssemblerArmTest::* GetName2)(const Reg2 &),std::string fmt)264   std::string RepeatTemplatedRRC(void (Ass::*f)(Reg1, Reg2, Cond),
265                                  const std::vector<Reg1*>& reg1_registers,
266                                  const std::vector<Reg2*>& reg2_registers,
267                                  const std::vector<Cond>& cond,
268                                  std::string (AssemblerArmTest::*GetName1)(const Reg1&),
269                                  std::string (AssemblerArmTest::*GetName2)(const Reg2&),
270                                  std::string fmt) {
271     WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size());
272 
273     std::ostringstream oss;
274     bool first = true;
275     for (const Cond& c : cond) {
276       std::string after_cond = fmt;
277 
278       size_t cond_index = after_cond.find(COND_TOKEN);
279       if (cond_index != std::string::npos) {
280         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
281       }
282 
283       for (auto reg1 : reg1_registers) {
284         std::string after_reg1 = after_cond;
285 
286         std::string reg1_string = (this->*GetName1)(*reg1);
287         size_t reg1_index;
288         while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
289           after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
290         }
291 
292         for (auto reg2 : reg2_registers) {
293           std::string after_reg2 = after_reg1;
294 
295           std::string reg2_string = (this->*GetName2)(*reg2);
296           size_t reg2_index;
297           while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
298             after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
299           }
300 
301           if (first) {
302             first = false;
303           } else {
304             oss << "\n";
305           }
306           oss << after_reg2;
307 
308           (Base::GetAssembler()->*f)(*reg1, *reg2, c);
309         }
310       }
311     }
312     // Add a newline at the end.
313     oss << "\n";
314 
315     return oss.str();
316   }
317 
RepeatRRRC(void (Ass::* f)(Reg,Reg,Reg,Cond),std::string fmt)318   std::string RepeatRRRC(void (Ass::*f)(Reg, Reg, Reg, Cond), std::string fmt) {
319     return RepeatTemplatedRRRC(f, GetRegisters(), GetRegisters(), GetRegisters(), GetConditions(),
320                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
321                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
322                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
323                                fmt);
324   }
325 
326   template <typename Reg1, typename Reg2, typename Reg3>
RepeatTemplatedRRRC(void (Ass::* f)(Reg1,Reg2,Reg3,Cond),const std::vector<Reg1 * > & reg1_registers,const std::vector<Reg2 * > & reg2_registers,const std::vector<Reg3 * > & reg3_registers,const std::vector<Cond> & cond,std::string (AssemblerArmTest::* GetName1)(const Reg1 &),std::string (AssemblerArmTest::* GetName2)(const Reg2 &),std::string (AssemblerArmTest::* GetName3)(const Reg3 &),std::string fmt)327   std::string RepeatTemplatedRRRC(void (Ass::*f)(Reg1, Reg2, Reg3, Cond),
328                                   const std::vector<Reg1*>& reg1_registers,
329                                   const std::vector<Reg2*>& reg2_registers,
330                                   const std::vector<Reg3*>& reg3_registers,
331                                   const std::vector<Cond>& cond,
332                                   std::string (AssemblerArmTest::*GetName1)(const Reg1&),
333                                   std::string (AssemblerArmTest::*GetName2)(const Reg2&),
334                                   std::string (AssemblerArmTest::*GetName3)(const Reg3&),
335                                   std::string fmt) {
336     WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() *
337                        reg3_registers.size());
338 
339     std::ostringstream oss;
340     bool first = true;
341     for (const Cond& c : cond) {
342       std::string after_cond = fmt;
343 
344       size_t cond_index = after_cond.find(COND_TOKEN);
345       if (cond_index != std::string::npos) {
346         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
347       }
348 
349       for (auto reg1 : reg1_registers) {
350         std::string after_reg1 = after_cond;
351 
352         std::string reg1_string = (this->*GetName1)(*reg1);
353         size_t reg1_index;
354         while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
355           after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
356         }
357 
358         for (auto reg2 : reg2_registers) {
359           std::string after_reg2 = after_reg1;
360 
361           std::string reg2_string = (this->*GetName2)(*reg2);
362           size_t reg2_index;
363           while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
364             after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
365           }
366 
367           for (auto reg3 : reg3_registers) {
368             std::string after_reg3 = after_reg2;
369 
370             std::string reg3_string = (this->*GetName3)(*reg3);
371             size_t reg3_index;
372             while ((reg3_index = after_reg3.find(REG3_TOKEN)) != std::string::npos) {
373               after_reg3.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
374             }
375 
376             if (first) {
377               first = false;
378             } else {
379               oss << "\n";
380             }
381             oss << after_reg3;
382 
383             (Base::GetAssembler()->*f)(*reg1, *reg2, *reg3, c);
384           }
385         }
386       }
387     }
388     // Add a newline at the end.
389     oss << "\n";
390 
391     return oss.str();
392   }
393 
394   template <typename RegT>
RepeatTemplatedRSC(void (Ass::* f)(RegT,SOp,Cond),const std::vector<RegT * > & registers,const std::vector<SOp> & shifts,const std::vector<Cond> & cond,std::string (AssemblerArmTest::* GetName)(const RegT &),std::string fmt)395   std::string RepeatTemplatedRSC(void (Ass::*f)(RegT, SOp, Cond),
396                                  const std::vector<RegT*>& registers,
397                                  const std::vector<SOp>& shifts,
398                                  const std::vector<Cond>& cond,
399                                  std::string (AssemblerArmTest::*GetName)(const RegT&),
400                                  std::string fmt) {
401     WarnOnCombinations(cond.size() * registers.size() * shifts.size());
402 
403     std::ostringstream oss;
404     bool first = true;
405     for (const Cond& c : cond) {
406       std::string after_cond = fmt;
407 
408       size_t cond_index = after_cond.find(COND_TOKEN);
409       if (cond_index != std::string::npos) {
410         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
411       }
412 
413       for (const SOp& shift : shifts) {
414         std::string after_shift = after_cond;
415 
416         std::string shift_string = GetShiftString(shift);
417         size_t shift_index;
418         while ((shift_index = after_shift.find(Base::SHIFT_TOKEN)) != std::string::npos) {
419           after_shift.replace(shift_index, ConstexprStrLen(Base::SHIFT_TOKEN), shift_string);
420         }
421 
422         for (auto reg : registers) {
423           std::string after_reg = after_shift;
424 
425           std::string reg_string = (this->*GetName)(*reg);
426           size_t reg_index;
427           while ((reg_index = after_reg.find(Base::REG_TOKEN)) != std::string::npos) {
428             after_reg.replace(reg_index, ConstexprStrLen(Base::REG_TOKEN), reg_string);
429           }
430 
431           if (first) {
432             first = false;
433           } else {
434             oss << "\n";
435           }
436           oss << after_reg;
437 
438           (Base::GetAssembler()->*f)(*reg, shift, c);
439         }
440       }
441     }
442     // Add a newline at the end.
443     oss << "\n";
444 
445     return oss.str();
446   }
447 
448   template <typename Reg1, typename Reg2>
RepeatTemplatedRRSC(void (Ass::* f)(Reg1,Reg2,const SOp &,Cond),const std::vector<Reg1 * > & reg1_registers,const std::vector<Reg2 * > & reg2_registers,const std::vector<SOp> & shifts,const std::vector<Cond> & cond,std::string (AssemblerArmTest::* GetName1)(const Reg1 &),std::string (AssemblerArmTest::* GetName2)(const Reg2 &),std::string fmt)449   std::string RepeatTemplatedRRSC(void (Ass::*f)(Reg1, Reg2, const SOp&, Cond),
450                                   const std::vector<Reg1*>& reg1_registers,
451                                   const std::vector<Reg2*>& reg2_registers,
452                                   const std::vector<SOp>& shifts,
453                                   const std::vector<Cond>& cond,
454                                   std::string (AssemblerArmTest::*GetName1)(const Reg1&),
455                                   std::string (AssemblerArmTest::*GetName2)(const Reg2&),
456                                   std::string fmt) {
457     WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * shifts.size());
458 
459     std::ostringstream oss;
460     bool first = true;
461     for (const Cond& c : cond) {
462       std::string after_cond = fmt;
463 
464       size_t cond_index = after_cond.find(COND_TOKEN);
465       if (cond_index != std::string::npos) {
466         after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
467       }
468 
469       for (const SOp& shift : shifts) {
470         std::string after_shift = after_cond;
471 
472         std::string shift_string = GetShiftString(shift);
473         size_t shift_index;
474         while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
475           after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
476         }
477 
478         for (auto reg1 : reg1_registers) {
479           std::string after_reg1 = after_shift;
480 
481           std::string reg1_string = (this->*GetName1)(*reg1);
482           size_t reg1_index;
483           while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
484             after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
485           }
486 
487           for (auto reg2 : reg2_registers) {
488             std::string after_reg2 = after_reg1;
489 
490             std::string reg2_string = (this->*GetName2)(*reg2);
491             size_t reg2_index;
492             while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
493               after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
494             }
495 
496             if (first) {
497               first = false;
498             } else {
499               oss << "\n";
500             }
501             oss << after_reg2;
502 
503             (Base::GetAssembler()->*f)(*reg1, *reg2, shift, c);
504           }
505         }
506       }
507     }
508     // Add a newline at the end.
509     oss << "\n";
510 
511     return oss.str();
512   }
513 
514  protected:
AssemblerArmTest()515   explicit AssemblerArmTest() {}
516 
517   virtual std::vector<Cond>& GetConditions() = 0;
518   virtual std::string GetConditionString(Cond c) = 0;
519 
520   virtual std::vector<SetCc>& GetSetCcs() = 0;
521   virtual std::string GetSetCcString(SetCc s) = 0;
522 
523   virtual std::vector<SOp>& GetShiftOperands() = 0;
524   virtual std::string GetShiftString(SOp sop) = 0;
525 
526   virtual Reg GetPCRegister() = 0;
GetRegistersWithoutPC()527   virtual std::vector<Reg*> GetRegistersWithoutPC() {
528     std::vector<Reg*> without_pc = GetRegisters();
529     Reg pc_reg = GetPCRegister();
530 
531     for (auto it = without_pc.begin(); it != without_pc.end(); ++it) {
532       if (**it == pc_reg) {
533         without_pc.erase(it);
534         break;
535       }
536     }
537 
538     return without_pc;
539   }
540 
541   static constexpr const char* IMM1_TOKEN = "{imm1}";
542   static constexpr const char* IMM2_TOKEN = "{imm2}";
543   static constexpr const char* REG3_TOKEN = "{reg3}";
544   static constexpr const char* REG4_TOKEN = "{reg4}";
545   static constexpr const char* COND_TOKEN = "{cond}";
546   static constexpr const char* SET_CC_TOKEN = "{s}";
547   static constexpr const char* SHIFT_TOKEN = "{shift}";
548 
549  private:
550   DISALLOW_COPY_AND_ASSIGN(AssemblerArmTest);
551 };
552 
553 }  // namespace art
554 
555 #endif  // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
556