• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of Arm Limited nor the names of its contributors may be
13 //     used to endorse or promote products derived from this software without
14 //     specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "cpu-features.h"
28 #include "globals-vixl.h"
29 #include "utils-vixl.h"
30 #include "decoder-aarch64.h"
31 
32 #include "cpu-features-auditor-aarch64.h"
33 
34 namespace vixl {
35 namespace aarch64 {
36 
37 // Every instruction must update last_instruction_, even if only to clear it,
38 // and every instruction must also update seen_ once it has been fully handled.
39 // This scope makes that simple, and allows early returns in the decode logic.
40 class CPUFeaturesAuditor::RecordInstructionFeaturesScope {
41  public:
RecordInstructionFeaturesScope(CPUFeaturesAuditor * auditor)42   explicit RecordInstructionFeaturesScope(CPUFeaturesAuditor* auditor)
43       : auditor_(auditor) {
44     auditor_->last_instruction_ = CPUFeatures::None();
45   }
~RecordInstructionFeaturesScope()46   ~RecordInstructionFeaturesScope() {
47     auditor_->seen_.Combine(auditor_->last_instruction_);
48   }
49 
Record(const CPUFeatures & features)50   void Record(const CPUFeatures& features) {
51     auditor_->last_instruction_.Combine(features);
52   }
53 
Record(CPUFeatures::Feature feature0,CPUFeatures::Feature feature1=CPUFeatures::kNone,CPUFeatures::Feature feature2=CPUFeatures::kNone,CPUFeatures::Feature feature3=CPUFeatures::kNone)54   void Record(CPUFeatures::Feature feature0,
55               CPUFeatures::Feature feature1 = CPUFeatures::kNone,
56               CPUFeatures::Feature feature2 = CPUFeatures::kNone,
57               CPUFeatures::Feature feature3 = CPUFeatures::kNone) {
58     auditor_->last_instruction_.Combine(feature0, feature1, feature2, feature3);
59   }
60 
61   // If exactly one of a or b is known to be available, record it. Otherwise,
62   // record both. This is intended for encodings that can be provided by two
63   // different features.
RecordOneOrBothOf(CPUFeatures::Feature a,CPUFeatures::Feature b)64   void RecordOneOrBothOf(CPUFeatures::Feature a, CPUFeatures::Feature b) {
65     bool hint_a = auditor_->available_.Has(a);
66     bool hint_b = auditor_->available_.Has(b);
67     if (hint_a && !hint_b) {
68       Record(a);
69     } else if (hint_b && !hint_a) {
70       Record(b);
71     } else {
72       Record(a, b);
73     }
74   }
75 
76  private:
77   CPUFeaturesAuditor* auditor_;
78 };
79 
LoadStoreHelper(const Instruction * instr)80 void CPUFeaturesAuditor::LoadStoreHelper(const Instruction* instr) {
81   RecordInstructionFeaturesScope scope(this);
82   switch (instr->Mask(LoadStoreMask)) {
83     case LDR_b:
84     case LDR_q:
85     case STR_b:
86     case STR_q:
87       scope.Record(CPUFeatures::kNEON);
88       return;
89     case LDR_h:
90     case LDR_s:
91     case LDR_d:
92     case STR_h:
93     case STR_s:
94     case STR_d:
95       scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
96       return;
97     default:
98       // No special CPU features.
99       return;
100   }
101 }
102 
LoadStorePairHelper(const Instruction * instr)103 void CPUFeaturesAuditor::LoadStorePairHelper(const Instruction* instr) {
104   RecordInstructionFeaturesScope scope(this);
105   switch (instr->Mask(LoadStorePairMask)) {
106     case LDP_q:
107     case STP_q:
108       scope.Record(CPUFeatures::kNEON);
109       return;
110     case LDP_s:
111     case LDP_d:
112     case STP_s:
113     case STP_d: {
114       scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
115       return;
116     }
117     default:
118       // No special CPU features.
119       return;
120   }
121 }
122 
VisitAddSubExtended(const Instruction * instr)123 void CPUFeaturesAuditor::VisitAddSubExtended(const Instruction* instr) {
124   RecordInstructionFeaturesScope scope(this);
125   USE(instr);
126 }
127 
VisitAddSubImmediate(const Instruction * instr)128 void CPUFeaturesAuditor::VisitAddSubImmediate(const Instruction* instr) {
129   RecordInstructionFeaturesScope scope(this);
130   USE(instr);
131 }
132 
VisitAddSubShifted(const Instruction * instr)133 void CPUFeaturesAuditor::VisitAddSubShifted(const Instruction* instr) {
134   RecordInstructionFeaturesScope scope(this);
135   USE(instr);
136 }
137 
VisitAddSubWithCarry(const Instruction * instr)138 void CPUFeaturesAuditor::VisitAddSubWithCarry(const Instruction* instr) {
139   RecordInstructionFeaturesScope scope(this);
140   USE(instr);
141 }
142 
VisitRotateRightIntoFlags(const Instruction * instr)143 void CPUFeaturesAuditor::VisitRotateRightIntoFlags(const Instruction* instr) {
144   RecordInstructionFeaturesScope scope(this);
145   switch (instr->Mask(RotateRightIntoFlagsMask)) {
146     case RMIF:
147       scope.Record(CPUFeatures::kFlagM);
148       return;
149   }
150 }
151 
VisitEvaluateIntoFlags(const Instruction * instr)152 void CPUFeaturesAuditor::VisitEvaluateIntoFlags(const Instruction* instr) {
153   RecordInstructionFeaturesScope scope(this);
154   switch (instr->Mask(EvaluateIntoFlagsMask)) {
155     case SETF8:
156     case SETF16:
157       scope.Record(CPUFeatures::kFlagM);
158       return;
159   }
160 }
161 
VisitAtomicMemory(const Instruction * instr)162 void CPUFeaturesAuditor::VisitAtomicMemory(const Instruction* instr) {
163   RecordInstructionFeaturesScope scope(this);
164   switch (instr->Mask(AtomicMemoryMask)) {
165     case LDAPRB:
166     case LDAPRH:
167     case LDAPR_w:
168     case LDAPR_x:
169       scope.Record(CPUFeatures::kRCpc);
170       return;
171     default:
172       // Everything else belongs to the Atomics extension.
173       scope.Record(CPUFeatures::kAtomics);
174       return;
175   }
176 }
177 
VisitBitfield(const Instruction * instr)178 void CPUFeaturesAuditor::VisitBitfield(const Instruction* instr) {
179   RecordInstructionFeaturesScope scope(this);
180   USE(instr);
181 }
182 
VisitCompareBranch(const Instruction * instr)183 void CPUFeaturesAuditor::VisitCompareBranch(const Instruction* instr) {
184   RecordInstructionFeaturesScope scope(this);
185   USE(instr);
186 }
187 
VisitConditionalBranch(const Instruction * instr)188 void CPUFeaturesAuditor::VisitConditionalBranch(const Instruction* instr) {
189   RecordInstructionFeaturesScope scope(this);
190   USE(instr);
191 }
192 
VisitConditionalCompareImmediate(const Instruction * instr)193 void CPUFeaturesAuditor::VisitConditionalCompareImmediate(
194     const Instruction* instr) {
195   RecordInstructionFeaturesScope scope(this);
196   USE(instr);
197 }
198 
VisitConditionalCompareRegister(const Instruction * instr)199 void CPUFeaturesAuditor::VisitConditionalCompareRegister(
200     const Instruction* instr) {
201   RecordInstructionFeaturesScope scope(this);
202   USE(instr);
203 }
204 
VisitConditionalSelect(const Instruction * instr)205 void CPUFeaturesAuditor::VisitConditionalSelect(const Instruction* instr) {
206   RecordInstructionFeaturesScope scope(this);
207   USE(instr);
208 }
209 
VisitCrypto2RegSHA(const Instruction * instr)210 void CPUFeaturesAuditor::VisitCrypto2RegSHA(const Instruction* instr) {
211   RecordInstructionFeaturesScope scope(this);
212   USE(instr);
213 }
214 
VisitCrypto3RegSHA(const Instruction * instr)215 void CPUFeaturesAuditor::VisitCrypto3RegSHA(const Instruction* instr) {
216   RecordInstructionFeaturesScope scope(this);
217   USE(instr);
218 }
219 
VisitCryptoAES(const Instruction * instr)220 void CPUFeaturesAuditor::VisitCryptoAES(const Instruction* instr) {
221   RecordInstructionFeaturesScope scope(this);
222   USE(instr);
223 }
224 
VisitDataProcessing1Source(const Instruction * instr)225 void CPUFeaturesAuditor::VisitDataProcessing1Source(const Instruction* instr) {
226   RecordInstructionFeaturesScope scope(this);
227   switch (instr->Mask(DataProcessing1SourceMask)) {
228     case PACIA:
229     case PACIB:
230     case PACDA:
231     case PACDB:
232     case AUTIA:
233     case AUTIB:
234     case AUTDA:
235     case AUTDB:
236     case PACIZA:
237     case PACIZB:
238     case PACDZA:
239     case PACDZB:
240     case AUTIZA:
241     case AUTIZB:
242     case AUTDZA:
243     case AUTDZB:
244     case XPACI:
245     case XPACD:
246       scope.Record(CPUFeatures::kPAuth);
247       return;
248     default:
249       // No special CPU features.
250       return;
251   }
252 }
253 
VisitDataProcessing2Source(const Instruction * instr)254 void CPUFeaturesAuditor::VisitDataProcessing2Source(const Instruction* instr) {
255   RecordInstructionFeaturesScope scope(this);
256   switch (instr->Mask(DataProcessing2SourceMask)) {
257     case CRC32B:
258     case CRC32H:
259     case CRC32W:
260     case CRC32X:
261     case CRC32CB:
262     case CRC32CH:
263     case CRC32CW:
264     case CRC32CX:
265       scope.Record(CPUFeatures::kCRC32);
266       return;
267     case PACGA:
268       scope.Record(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric);
269       return;
270     default:
271       // No special CPU features.
272       return;
273   }
274 }
275 
VisitLoadStoreRCpcUnscaledOffset(const Instruction * instr)276 void CPUFeaturesAuditor::VisitLoadStoreRCpcUnscaledOffset(
277     const Instruction* instr) {
278   RecordInstructionFeaturesScope scope(this);
279   switch (instr->Mask(LoadStoreRCpcUnscaledOffsetMask)) {
280     case LDAPURB:
281     case LDAPURSB_w:
282     case LDAPURSB_x:
283     case LDAPURH:
284     case LDAPURSH_w:
285     case LDAPURSH_x:
286     case LDAPUR_w:
287     case LDAPURSW:
288     case LDAPUR_x:
289 
290     // These stores don't actually have RCpc semantics but they're included with
291     // the RCpc extensions.
292     case STLURB:
293     case STLURH:
294     case STLUR_w:
295     case STLUR_x:
296       scope.Record(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm);
297       return;
298   }
299 }
300 
VisitLoadStorePAC(const Instruction * instr)301 void CPUFeaturesAuditor::VisitLoadStorePAC(const Instruction* instr) {
302   RecordInstructionFeaturesScope scope(this);
303   USE(instr);
304   scope.Record(CPUFeatures::kPAuth);
305 }
306 
VisitDataProcessing3Source(const Instruction * instr)307 void CPUFeaturesAuditor::VisitDataProcessing3Source(const Instruction* instr) {
308   RecordInstructionFeaturesScope scope(this);
309   USE(instr);
310 }
311 
VisitException(const Instruction * instr)312 void CPUFeaturesAuditor::VisitException(const Instruction* instr) {
313   RecordInstructionFeaturesScope scope(this);
314   USE(instr);
315 }
316 
VisitExtract(const Instruction * instr)317 void CPUFeaturesAuditor::VisitExtract(const Instruction* instr) {
318   RecordInstructionFeaturesScope scope(this);
319   USE(instr);
320 }
321 
VisitFPCompare(const Instruction * instr)322 void CPUFeaturesAuditor::VisitFPCompare(const Instruction* instr) {
323   RecordInstructionFeaturesScope scope(this);
324   // All of these instructions require FP.
325   scope.Record(CPUFeatures::kFP);
326   switch (instr->Mask(FPCompareMask)) {
327     case FCMP_h:
328     case FCMP_h_zero:
329     case FCMPE_h:
330     case FCMPE_h_zero:
331       scope.Record(CPUFeatures::kFPHalf);
332       return;
333     default:
334       // No special CPU features.
335       return;
336   }
337 }
338 
VisitFPConditionalCompare(const Instruction * instr)339 void CPUFeaturesAuditor::VisitFPConditionalCompare(const Instruction* instr) {
340   RecordInstructionFeaturesScope scope(this);
341   // All of these instructions require FP.
342   scope.Record(CPUFeatures::kFP);
343   switch (instr->Mask(FPConditionalCompareMask)) {
344     case FCCMP_h:
345     case FCCMPE_h:
346       scope.Record(CPUFeatures::kFPHalf);
347       return;
348     default:
349       // No special CPU features.
350       return;
351   }
352 }
353 
VisitFPConditionalSelect(const Instruction * instr)354 void CPUFeaturesAuditor::VisitFPConditionalSelect(const Instruction* instr) {
355   RecordInstructionFeaturesScope scope(this);
356   // All of these instructions require FP.
357   scope.Record(CPUFeatures::kFP);
358   if (instr->Mask(FPConditionalSelectMask) == FCSEL_h) {
359     scope.Record(CPUFeatures::kFPHalf);
360   }
361 }
362 
VisitFPDataProcessing1Source(const Instruction * instr)363 void CPUFeaturesAuditor::VisitFPDataProcessing1Source(
364     const Instruction* instr) {
365   RecordInstructionFeaturesScope scope(this);
366   // All of these instructions require FP.
367   scope.Record(CPUFeatures::kFP);
368   switch (instr->Mask(FPDataProcessing1SourceMask)) {
369     case FMOV_h:
370     case FABS_h:
371     case FNEG_h:
372     case FSQRT_h:
373     case FRINTN_h:
374     case FRINTP_h:
375     case FRINTM_h:
376     case FRINTZ_h:
377     case FRINTA_h:
378     case FRINTX_h:
379     case FRINTI_h:
380       scope.Record(CPUFeatures::kFPHalf);
381       return;
382     case FRINT32X_s:
383     case FRINT32X_d:
384     case FRINT32Z_s:
385     case FRINT32Z_d:
386     case FRINT64X_s:
387     case FRINT64X_d:
388     case FRINT64Z_s:
389     case FRINT64Z_d:
390       scope.Record(CPUFeatures::kFrintToFixedSizedInt);
391       return;
392     default:
393       // No special CPU features.
394       // This category includes some half-precision FCVT instructions that do
395       // not require FPHalf.
396       return;
397   }
398 }
399 
VisitFPDataProcessing2Source(const Instruction * instr)400 void CPUFeaturesAuditor::VisitFPDataProcessing2Source(
401     const Instruction* instr) {
402   RecordInstructionFeaturesScope scope(this);
403   // All of these instructions require FP.
404   scope.Record(CPUFeatures::kFP);
405   switch (instr->Mask(FPDataProcessing2SourceMask)) {
406     case FMUL_h:
407     case FDIV_h:
408     case FADD_h:
409     case FSUB_h:
410     case FMAX_h:
411     case FMIN_h:
412     case FMAXNM_h:
413     case FMINNM_h:
414     case FNMUL_h:
415       scope.Record(CPUFeatures::kFPHalf);
416       return;
417     default:
418       // No special CPU features.
419       return;
420   }
421 }
422 
VisitFPDataProcessing3Source(const Instruction * instr)423 void CPUFeaturesAuditor::VisitFPDataProcessing3Source(
424     const Instruction* instr) {
425   RecordInstructionFeaturesScope scope(this);
426   // All of these instructions require FP.
427   scope.Record(CPUFeatures::kFP);
428   switch (instr->Mask(FPDataProcessing3SourceMask)) {
429     case FMADD_h:
430     case FMSUB_h:
431     case FNMADD_h:
432     case FNMSUB_h:
433       scope.Record(CPUFeatures::kFPHalf);
434       return;
435     default:
436       // No special CPU features.
437       return;
438   }
439 }
440 
VisitFPFixedPointConvert(const Instruction * instr)441 void CPUFeaturesAuditor::VisitFPFixedPointConvert(const Instruction* instr) {
442   RecordInstructionFeaturesScope scope(this);
443   // All of these instructions require FP.
444   scope.Record(CPUFeatures::kFP);
445   switch (instr->Mask(FPFixedPointConvertMask)) {
446     case FCVTZS_wh_fixed:
447     case FCVTZS_xh_fixed:
448     case FCVTZU_wh_fixed:
449     case FCVTZU_xh_fixed:
450     case SCVTF_hw_fixed:
451     case SCVTF_hx_fixed:
452     case UCVTF_hw_fixed:
453     case UCVTF_hx_fixed:
454       scope.Record(CPUFeatures::kFPHalf);
455       return;
456     default:
457       // No special CPU features.
458       return;
459   }
460 }
461 
VisitFPImmediate(const Instruction * instr)462 void CPUFeaturesAuditor::VisitFPImmediate(const Instruction* instr) {
463   RecordInstructionFeaturesScope scope(this);
464   // All of these instructions require FP.
465   scope.Record(CPUFeatures::kFP);
466   if (instr->Mask(FPImmediateMask) == FMOV_h_imm) {
467     scope.Record(CPUFeatures::kFPHalf);
468   }
469 }
470 
VisitFPIntegerConvert(const Instruction * instr)471 void CPUFeaturesAuditor::VisitFPIntegerConvert(const Instruction* instr) {
472   RecordInstructionFeaturesScope scope(this);
473   // All of these instructions require FP.
474   scope.Record(CPUFeatures::kFP);
475   switch (instr->Mask(FPIntegerConvertMask)) {
476     case FCVTAS_wh:
477     case FCVTAS_xh:
478     case FCVTAU_wh:
479     case FCVTAU_xh:
480     case FCVTMS_wh:
481     case FCVTMS_xh:
482     case FCVTMU_wh:
483     case FCVTMU_xh:
484     case FCVTNS_wh:
485     case FCVTNS_xh:
486     case FCVTNU_wh:
487     case FCVTNU_xh:
488     case FCVTPS_wh:
489     case FCVTPS_xh:
490     case FCVTPU_wh:
491     case FCVTPU_xh:
492     case FCVTZS_wh:
493     case FCVTZS_xh:
494     case FCVTZU_wh:
495     case FCVTZU_xh:
496     case FMOV_hw:
497     case FMOV_hx:
498     case FMOV_wh:
499     case FMOV_xh:
500     case SCVTF_hw:
501     case SCVTF_hx:
502     case UCVTF_hw:
503     case UCVTF_hx:
504       scope.Record(CPUFeatures::kFPHalf);
505       return;
506     case FMOV_d1_x:
507     case FMOV_x_d1:
508       scope.Record(CPUFeatures::kNEON);
509       return;
510     case FJCVTZS:
511       scope.Record(CPUFeatures::kJSCVT);
512       return;
513     default:
514       // No special CPU features.
515       return;
516   }
517 }
518 
VisitLoadLiteral(const Instruction * instr)519 void CPUFeaturesAuditor::VisitLoadLiteral(const Instruction* instr) {
520   RecordInstructionFeaturesScope scope(this);
521   switch (instr->Mask(LoadLiteralMask)) {
522     case LDR_s_lit:
523     case LDR_d_lit:
524       scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
525       return;
526     case LDR_q_lit:
527       scope.Record(CPUFeatures::kNEON);
528       return;
529     default:
530       // No special CPU features.
531       return;
532   }
533 }
534 
VisitLoadStoreExclusive(const Instruction * instr)535 void CPUFeaturesAuditor::VisitLoadStoreExclusive(const Instruction* instr) {
536   RecordInstructionFeaturesScope scope(this);
537   switch (instr->Mask(LoadStoreExclusiveMask)) {
538     case CAS_w:
539     case CASA_w:
540     case CASL_w:
541     case CASAL_w:
542     case CAS_x:
543     case CASA_x:
544     case CASL_x:
545     case CASAL_x:
546     case CASB:
547     case CASAB:
548     case CASLB:
549     case CASALB:
550     case CASH:
551     case CASAH:
552     case CASLH:
553     case CASALH:
554     case CASP_w:
555     case CASPA_w:
556     case CASPL_w:
557     case CASPAL_w:
558     case CASP_x:
559     case CASPA_x:
560     case CASPL_x:
561     case CASPAL_x:
562       scope.Record(CPUFeatures::kAtomics);
563       return;
564     case STLLRB:
565     case LDLARB:
566     case STLLRH:
567     case LDLARH:
568     case STLLR_w:
569     case LDLAR_w:
570     case STLLR_x:
571     case LDLAR_x:
572       scope.Record(CPUFeatures::kLORegions);
573       return;
574     default:
575       // No special CPU features.
576       return;
577   }
578 }
579 
VisitLoadStorePairNonTemporal(const Instruction * instr)580 void CPUFeaturesAuditor::VisitLoadStorePairNonTemporal(
581     const Instruction* instr) {
582   LoadStorePairHelper(instr);
583 }
584 
VisitLoadStorePairOffset(const Instruction * instr)585 void CPUFeaturesAuditor::VisitLoadStorePairOffset(const Instruction* instr) {
586   LoadStorePairHelper(instr);
587 }
588 
VisitLoadStorePairPostIndex(const Instruction * instr)589 void CPUFeaturesAuditor::VisitLoadStorePairPostIndex(const Instruction* instr) {
590   LoadStorePairHelper(instr);
591 }
592 
VisitLoadStorePairPreIndex(const Instruction * instr)593 void CPUFeaturesAuditor::VisitLoadStorePairPreIndex(const Instruction* instr) {
594   LoadStorePairHelper(instr);
595 }
596 
VisitLoadStorePostIndex(const Instruction * instr)597 void CPUFeaturesAuditor::VisitLoadStorePostIndex(const Instruction* instr) {
598   LoadStoreHelper(instr);
599 }
600 
VisitLoadStorePreIndex(const Instruction * instr)601 void CPUFeaturesAuditor::VisitLoadStorePreIndex(const Instruction* instr) {
602   LoadStoreHelper(instr);
603 }
604 
VisitLoadStoreRegisterOffset(const Instruction * instr)605 void CPUFeaturesAuditor::VisitLoadStoreRegisterOffset(
606     const Instruction* instr) {
607   LoadStoreHelper(instr);
608 }
609 
VisitLoadStoreUnscaledOffset(const Instruction * instr)610 void CPUFeaturesAuditor::VisitLoadStoreUnscaledOffset(
611     const Instruction* instr) {
612   LoadStoreHelper(instr);
613 }
614 
VisitLoadStoreUnsignedOffset(const Instruction * instr)615 void CPUFeaturesAuditor::VisitLoadStoreUnsignedOffset(
616     const Instruction* instr) {
617   LoadStoreHelper(instr);
618 }
619 
VisitLogicalImmediate(const Instruction * instr)620 void CPUFeaturesAuditor::VisitLogicalImmediate(const Instruction* instr) {
621   RecordInstructionFeaturesScope scope(this);
622   USE(instr);
623 }
624 
VisitLogicalShifted(const Instruction * instr)625 void CPUFeaturesAuditor::VisitLogicalShifted(const Instruction* instr) {
626   RecordInstructionFeaturesScope scope(this);
627   USE(instr);
628 }
629 
VisitMoveWideImmediate(const Instruction * instr)630 void CPUFeaturesAuditor::VisitMoveWideImmediate(const Instruction* instr) {
631   RecordInstructionFeaturesScope scope(this);
632   USE(instr);
633 }
634 
VisitNEON2RegMisc(const Instruction * instr)635 void CPUFeaturesAuditor::VisitNEON2RegMisc(const Instruction* instr) {
636   RecordInstructionFeaturesScope scope(this);
637   // All of these instructions require NEON.
638   scope.Record(CPUFeatures::kNEON);
639   switch (instr->Mask(NEON2RegMiscFPMask)) {
640     case NEON_FABS:
641     case NEON_FNEG:
642     case NEON_FSQRT:
643     case NEON_FCVTL:
644     case NEON_FCVTN:
645     case NEON_FCVTXN:
646     case NEON_FRINTI:
647     case NEON_FRINTX:
648     case NEON_FRINTA:
649     case NEON_FRINTM:
650     case NEON_FRINTN:
651     case NEON_FRINTP:
652     case NEON_FRINTZ:
653     case NEON_FCVTNS:
654     case NEON_FCVTNU:
655     case NEON_FCVTPS:
656     case NEON_FCVTPU:
657     case NEON_FCVTMS:
658     case NEON_FCVTMU:
659     case NEON_FCVTZS:
660     case NEON_FCVTZU:
661     case NEON_FCVTAS:
662     case NEON_FCVTAU:
663     case NEON_SCVTF:
664     case NEON_UCVTF:
665     case NEON_FRSQRTE:
666     case NEON_FRECPE:
667     case NEON_FCMGT_zero:
668     case NEON_FCMGE_zero:
669     case NEON_FCMEQ_zero:
670     case NEON_FCMLE_zero:
671     case NEON_FCMLT_zero:
672       scope.Record(CPUFeatures::kFP);
673       return;
674     case NEON_FRINT32X:
675     case NEON_FRINT32Z:
676     case NEON_FRINT64X:
677     case NEON_FRINT64Z:
678       scope.Record(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt);
679       return;
680     default:
681       // No additional features.
682       return;
683   }
684 }
685 
VisitNEON2RegMiscFP16(const Instruction * instr)686 void CPUFeaturesAuditor::VisitNEON2RegMiscFP16(const Instruction* instr) {
687   RecordInstructionFeaturesScope scope(this);
688   // All of these instructions require NEONHalf.
689   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
690   USE(instr);
691 }
692 
VisitNEON3Different(const Instruction * instr)693 void CPUFeaturesAuditor::VisitNEON3Different(const Instruction* instr) {
694   RecordInstructionFeaturesScope scope(this);
695   // All of these instructions require NEON.
696   scope.Record(CPUFeatures::kNEON);
697   USE(instr);
698 }
699 
VisitNEON3Same(const Instruction * instr)700 void CPUFeaturesAuditor::VisitNEON3Same(const Instruction* instr) {
701   RecordInstructionFeaturesScope scope(this);
702   // All of these instructions require NEON.
703   scope.Record(CPUFeatures::kNEON);
704   if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
705     scope.Record(CPUFeatures::kFP);
706   }
707   switch (instr->Mask(NEON3SameFHMMask)) {
708     case NEON_FMLAL:
709     case NEON_FMLAL2:
710     case NEON_FMLSL:
711     case NEON_FMLSL2:
712       scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf, CPUFeatures::kFHM);
713       return;
714     default:
715       // No additional features.
716       return;
717   }
718 }
719 
VisitNEON3SameExtra(const Instruction * instr)720 void CPUFeaturesAuditor::VisitNEON3SameExtra(const Instruction* instr) {
721   RecordInstructionFeaturesScope scope(this);
722   // All of these instructions require NEON.
723   scope.Record(CPUFeatures::kNEON);
724   if ((instr->Mask(NEON3SameExtraFCMLAMask) == NEON_FCMLA) ||
725       (instr->Mask(NEON3SameExtraFCADDMask) == NEON_FCADD)) {
726     scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma);
727     if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf);
728   } else {
729     switch (instr->Mask(NEON3SameExtraMask)) {
730       case NEON_SDOT:
731       case NEON_UDOT:
732         scope.Record(CPUFeatures::kDotProduct);
733         return;
734       case NEON_SQRDMLAH:
735       case NEON_SQRDMLSH:
736         scope.Record(CPUFeatures::kRDM);
737         return;
738       default:
739         // No additional features.
740         return;
741     }
742   }
743 }
744 
VisitNEON3SameFP16(const Instruction * instr)745 void CPUFeaturesAuditor::VisitNEON3SameFP16(const Instruction* instr) {
746   RecordInstructionFeaturesScope scope(this);
747   // All of these instructions require NEON FP16 support.
748   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
749   USE(instr);
750 }
751 
VisitNEONAcrossLanes(const Instruction * instr)752 void CPUFeaturesAuditor::VisitNEONAcrossLanes(const Instruction* instr) {
753   RecordInstructionFeaturesScope scope(this);
754   // All of these instructions require NEON.
755   scope.Record(CPUFeatures::kNEON);
756   if (instr->Mask(NEONAcrossLanesFP16FMask) == NEONAcrossLanesFP16Fixed) {
757     // FMAXV_H, FMINV_H, FMAXNMV_H, FMINNMV_H
758     scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf);
759   } else if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
760     // FMAXV, FMINV, FMAXNMV, FMINNMV
761     scope.Record(CPUFeatures::kFP);
762   }
763 }
764 
VisitNEONByIndexedElement(const Instruction * instr)765 void CPUFeaturesAuditor::VisitNEONByIndexedElement(const Instruction* instr) {
766   RecordInstructionFeaturesScope scope(this);
767   // All of these instructions require NEON.
768   scope.Record(CPUFeatures::kNEON);
769   switch (instr->Mask(NEONByIndexedElementMask)) {
770     case NEON_SDOT_byelement:
771     case NEON_UDOT_byelement:
772       scope.Record(CPUFeatures::kDotProduct);
773       return;
774     case NEON_SQRDMLAH_byelement:
775     case NEON_SQRDMLSH_byelement:
776       scope.Record(CPUFeatures::kRDM);
777       return;
778     default:
779       // Fall through to check other instructions.
780       break;
781   }
782   switch (instr->Mask(NEONByIndexedElementFPLongMask)) {
783     case NEON_FMLAL_H_byelement:
784     case NEON_FMLAL2_H_byelement:
785     case NEON_FMLSL_H_byelement:
786     case NEON_FMLSL2_H_byelement:
787       scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf, CPUFeatures::kFHM);
788       return;
789     default:
790       // Fall through to check other instructions.
791       break;
792   }
793   switch (instr->Mask(NEONByIndexedElementFPMask)) {
794     case NEON_FMLA_H_byelement:
795     case NEON_FMLS_H_byelement:
796     case NEON_FMUL_H_byelement:
797     case NEON_FMULX_H_byelement:
798       scope.Record(CPUFeatures::kNEONHalf);
799       VIXL_FALLTHROUGH();
800     case NEON_FMLA_byelement:
801     case NEON_FMLS_byelement:
802     case NEON_FMUL_byelement:
803     case NEON_FMULX_byelement:
804       scope.Record(CPUFeatures::kFP);
805       return;
806     default:
807       switch (instr->Mask(NEONByIndexedElementFPComplexMask)) {
808         case NEON_FCMLA_byelement:
809           scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma);
810           if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf);
811           return;
812       }
813       // No additional features.
814       return;
815   }
816 }
817 
VisitNEONCopy(const Instruction * instr)818 void CPUFeaturesAuditor::VisitNEONCopy(const Instruction* instr) {
819   RecordInstructionFeaturesScope scope(this);
820   // All of these instructions require NEON.
821   scope.Record(CPUFeatures::kNEON);
822   USE(instr);
823 }
824 
VisitNEONExtract(const Instruction * instr)825 void CPUFeaturesAuditor::VisitNEONExtract(const Instruction* instr) {
826   RecordInstructionFeaturesScope scope(this);
827   // All of these instructions require NEON.
828   scope.Record(CPUFeatures::kNEON);
829   USE(instr);
830 }
831 
VisitNEONLoadStoreMultiStruct(const Instruction * instr)832 void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStruct(
833     const Instruction* instr) {
834   RecordInstructionFeaturesScope scope(this);
835   // All of these instructions require NEON.
836   scope.Record(CPUFeatures::kNEON);
837   USE(instr);
838 }
839 
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)840 void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStructPostIndex(
841     const Instruction* instr) {
842   RecordInstructionFeaturesScope scope(this);
843   // All of these instructions require NEON.
844   scope.Record(CPUFeatures::kNEON);
845   USE(instr);
846 }
847 
VisitNEONLoadStoreSingleStruct(const Instruction * instr)848 void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStruct(
849     const Instruction* instr) {
850   RecordInstructionFeaturesScope scope(this);
851   // All of these instructions require NEON.
852   scope.Record(CPUFeatures::kNEON);
853   USE(instr);
854 }
855 
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)856 void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStructPostIndex(
857     const Instruction* instr) {
858   RecordInstructionFeaturesScope scope(this);
859   // All of these instructions require NEON.
860   scope.Record(CPUFeatures::kNEON);
861   USE(instr);
862 }
863 
VisitNEONModifiedImmediate(const Instruction * instr)864 void CPUFeaturesAuditor::VisitNEONModifiedImmediate(const Instruction* instr) {
865   RecordInstructionFeaturesScope scope(this);
866   // All of these instructions require NEON.
867   scope.Record(CPUFeatures::kNEON);
868   if (instr->GetNEONCmode() == 0xf) {
869     // FMOV (vector, immediate), double-, single- or half-precision.
870     scope.Record(CPUFeatures::kFP);
871     if (instr->ExtractBit(11)) scope.Record(CPUFeatures::kNEONHalf);
872   }
873 }
874 
VisitNEONPerm(const Instruction * instr)875 void CPUFeaturesAuditor::VisitNEONPerm(const Instruction* instr) {
876   RecordInstructionFeaturesScope scope(this);
877   // All of these instructions require NEON.
878   scope.Record(CPUFeatures::kNEON);
879   USE(instr);
880 }
881 
VisitNEONScalar2RegMisc(const Instruction * instr)882 void CPUFeaturesAuditor::VisitNEONScalar2RegMisc(const Instruction* instr) {
883   RecordInstructionFeaturesScope scope(this);
884   // All of these instructions require NEON.
885   scope.Record(CPUFeatures::kNEON);
886   switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
887     case NEON_FRECPE_scalar:
888     case NEON_FRECPX_scalar:
889     case NEON_FRSQRTE_scalar:
890     case NEON_FCMGT_zero_scalar:
891     case NEON_FCMGE_zero_scalar:
892     case NEON_FCMEQ_zero_scalar:
893     case NEON_FCMLE_zero_scalar:
894     case NEON_FCMLT_zero_scalar:
895     case NEON_SCVTF_scalar:
896     case NEON_UCVTF_scalar:
897     case NEON_FCVTNS_scalar:
898     case NEON_FCVTNU_scalar:
899     case NEON_FCVTPS_scalar:
900     case NEON_FCVTPU_scalar:
901     case NEON_FCVTMS_scalar:
902     case NEON_FCVTMU_scalar:
903     case NEON_FCVTZS_scalar:
904     case NEON_FCVTZU_scalar:
905     case NEON_FCVTAS_scalar:
906     case NEON_FCVTAU_scalar:
907     case NEON_FCVTXN_scalar:
908       scope.Record(CPUFeatures::kFP);
909       return;
910     default:
911       // No additional features.
912       return;
913   }
914 }
915 
VisitNEONScalar2RegMiscFP16(const Instruction * instr)916 void CPUFeaturesAuditor::VisitNEONScalar2RegMiscFP16(const Instruction* instr) {
917   RecordInstructionFeaturesScope scope(this);
918   // All of these instructions require NEONHalf.
919   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
920   USE(instr);
921 }
922 
VisitNEONScalar3Diff(const Instruction * instr)923 void CPUFeaturesAuditor::VisitNEONScalar3Diff(const Instruction* instr) {
924   RecordInstructionFeaturesScope scope(this);
925   // All of these instructions require NEON.
926   scope.Record(CPUFeatures::kNEON);
927   USE(instr);
928 }
929 
VisitNEONScalar3Same(const Instruction * instr)930 void CPUFeaturesAuditor::VisitNEONScalar3Same(const Instruction* instr) {
931   RecordInstructionFeaturesScope scope(this);
932   // All of these instructions require NEON.
933   scope.Record(CPUFeatures::kNEON);
934   if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
935     scope.Record(CPUFeatures::kFP);
936   }
937 }
938 
VisitNEONScalar3SameExtra(const Instruction * instr)939 void CPUFeaturesAuditor::VisitNEONScalar3SameExtra(const Instruction* instr) {
940   RecordInstructionFeaturesScope scope(this);
941   // All of these instructions require NEON and RDM.
942   scope.Record(CPUFeatures::kNEON, CPUFeatures::kRDM);
943   USE(instr);
944 }
945 
VisitNEONScalar3SameFP16(const Instruction * instr)946 void CPUFeaturesAuditor::VisitNEONScalar3SameFP16(const Instruction* instr) {
947   RecordInstructionFeaturesScope scope(this);
948   // All of these instructions require NEONHalf.
949   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
950   USE(instr);
951 }
952 
VisitNEONScalarByIndexedElement(const Instruction * instr)953 void CPUFeaturesAuditor::VisitNEONScalarByIndexedElement(
954     const Instruction* instr) {
955   RecordInstructionFeaturesScope scope(this);
956   // All of these instructions require NEON.
957   scope.Record(CPUFeatures::kNEON);
958   switch (instr->Mask(NEONScalarByIndexedElementMask)) {
959     case NEON_SQRDMLAH_byelement_scalar:
960     case NEON_SQRDMLSH_byelement_scalar:
961       scope.Record(CPUFeatures::kRDM);
962       return;
963     default:
964       switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
965         case NEON_FMLA_H_byelement_scalar:
966         case NEON_FMLS_H_byelement_scalar:
967         case NEON_FMUL_H_byelement_scalar:
968         case NEON_FMULX_H_byelement_scalar:
969           scope.Record(CPUFeatures::kNEONHalf);
970           VIXL_FALLTHROUGH();
971         case NEON_FMLA_byelement_scalar:
972         case NEON_FMLS_byelement_scalar:
973         case NEON_FMUL_byelement_scalar:
974         case NEON_FMULX_byelement_scalar:
975           scope.Record(CPUFeatures::kFP);
976           return;
977       }
978       // No additional features.
979       return;
980   }
981 }
982 
VisitNEONScalarCopy(const Instruction * instr)983 void CPUFeaturesAuditor::VisitNEONScalarCopy(const Instruction* instr) {
984   RecordInstructionFeaturesScope scope(this);
985   // All of these instructions require NEON.
986   scope.Record(CPUFeatures::kNEON);
987   USE(instr);
988 }
989 
VisitNEONScalarPairwise(const Instruction * instr)990 void CPUFeaturesAuditor::VisitNEONScalarPairwise(const Instruction* instr) {
991   RecordInstructionFeaturesScope scope(this);
992   // All of these instructions require NEON.
993   scope.Record(CPUFeatures::kNEON);
994   switch (instr->Mask(NEONScalarPairwiseMask)) {
995     case NEON_FMAXNMP_h_scalar:
996     case NEON_FADDP_h_scalar:
997     case NEON_FMAXP_h_scalar:
998     case NEON_FMINNMP_h_scalar:
999     case NEON_FMINP_h_scalar:
1000       scope.Record(CPUFeatures::kNEONHalf);
1001       VIXL_FALLTHROUGH();
1002     case NEON_FADDP_scalar:
1003     case NEON_FMAXP_scalar:
1004     case NEON_FMAXNMP_scalar:
1005     case NEON_FMINP_scalar:
1006     case NEON_FMINNMP_scalar:
1007       scope.Record(CPUFeatures::kFP);
1008       return;
1009     default:
1010       // No additional features.
1011       return;
1012   }
1013 }
1014 
VisitNEONScalarShiftImmediate(const Instruction * instr)1015 void CPUFeaturesAuditor::VisitNEONScalarShiftImmediate(
1016     const Instruction* instr) {
1017   RecordInstructionFeaturesScope scope(this);
1018   // All of these instructions require NEON.
1019   scope.Record(CPUFeatures::kNEON);
1020   switch (instr->Mask(NEONScalarShiftImmediateMask)) {
1021     case NEON_FCVTZS_imm_scalar:
1022     case NEON_FCVTZU_imm_scalar:
1023     case NEON_SCVTF_imm_scalar:
1024     case NEON_UCVTF_imm_scalar:
1025       scope.Record(CPUFeatures::kFP);
1026       // If immh is 0b001x then the data type is FP16, and requires kNEONHalf.
1027       if ((instr->GetImmNEONImmh() & 0xe) == 0x2) {
1028         scope.Record(CPUFeatures::kNEONHalf);
1029       }
1030       return;
1031     default:
1032       // No additional features.
1033       return;
1034   }
1035 }
1036 
VisitNEONShiftImmediate(const Instruction * instr)1037 void CPUFeaturesAuditor::VisitNEONShiftImmediate(const Instruction* instr) {
1038   RecordInstructionFeaturesScope scope(this);
1039   // All of these instructions require NEON.
1040   scope.Record(CPUFeatures::kNEON);
1041   switch (instr->Mask(NEONShiftImmediateMask)) {
1042     case NEON_SCVTF_imm:
1043     case NEON_UCVTF_imm:
1044     case NEON_FCVTZS_imm:
1045     case NEON_FCVTZU_imm:
1046       scope.Record(CPUFeatures::kFP);
1047       // If immh is 0b001x then the data type is FP16, and requires kNEONHalf.
1048       if ((instr->GetImmNEONImmh() & 0xe) == 0x2) {
1049         scope.Record(CPUFeatures::kNEONHalf);
1050       }
1051       return;
1052     default:
1053       // No additional features.
1054       return;
1055   }
1056 }
1057 
VisitNEONTable(const Instruction * instr)1058 void CPUFeaturesAuditor::VisitNEONTable(const Instruction* instr) {
1059   RecordInstructionFeaturesScope scope(this);
1060   // All of these instructions require NEON.
1061   scope.Record(CPUFeatures::kNEON);
1062   USE(instr);
1063 }
1064 
VisitPCRelAddressing(const Instruction * instr)1065 void CPUFeaturesAuditor::VisitPCRelAddressing(const Instruction* instr) {
1066   RecordInstructionFeaturesScope scope(this);
1067   USE(instr);
1068 }
1069 
1070 // Most SVE visitors require only SVE.
1071 #define VIXL_SIMPLE_SVE_VISITOR_LIST(V)                          \
1072   V(SVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets)           \
1073   V(SVE32BitGatherLoad_VectorPlusImm)                            \
1074   V(SVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets)    \
1075   V(SVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets)        \
1076   V(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets)         \
1077   V(SVE32BitGatherPrefetch_VectorPlusImm)                        \
1078   V(SVE32BitScatterStore_ScalarPlus32BitScaledOffsets)           \
1079   V(SVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets)         \
1080   V(SVE32BitScatterStore_VectorPlusImm)                          \
1081   V(SVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets)     \
1082   V(SVE64BitGatherLoad_ScalarPlus64BitScaledOffsets)             \
1083   V(SVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets)           \
1084   V(SVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets)   \
1085   V(SVE64BitGatherLoad_VectorPlusImm)                            \
1086   V(SVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets)         \
1087   V(SVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets) \
1088   V(SVE64BitGatherPrefetch_VectorPlusImm)                        \
1089   V(SVE64BitScatterStore_ScalarPlus64BitScaledOffsets)           \
1090   V(SVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets)         \
1091   V(SVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets)   \
1092   V(SVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets) \
1093   V(SVE64BitScatterStore_VectorPlusImm)                          \
1094   V(SVEAddressGeneration)                                        \
1095   V(SVEBitwiseLogicalUnpredicated)                               \
1096   V(SVEBitwiseShiftUnpredicated)                                 \
1097   V(SVEFFRInitialise)                                            \
1098   V(SVEFFRWriteFromPredicate)                                    \
1099   V(SVEFPAccumulatingReduction)                                  \
1100   V(SVEFPArithmeticUnpredicated)                                 \
1101   V(SVEFPCompareVectors)                                         \
1102   V(SVEFPCompareWithZero)                                        \
1103   V(SVEFPComplexAddition)                                        \
1104   V(SVEFPComplexMulAdd)                                          \
1105   V(SVEFPComplexMulAddIndex)                                     \
1106   V(SVEFPFastReduction)                                          \
1107   V(SVEFPMulIndex)                                               \
1108   V(SVEFPMulAdd)                                                 \
1109   V(SVEFPMulAddIndex)                                            \
1110   V(SVEFPUnaryOpUnpredicated)                                    \
1111   V(SVEIncDecByPredicateCount)                                   \
1112   V(SVEIndexGeneration)                                          \
1113   V(SVEIntArithmeticUnpredicated)                                \
1114   V(SVEIntCompareSignedImm)                                      \
1115   V(SVEIntCompareUnsignedImm)                                    \
1116   V(SVEIntCompareVectors)                                        \
1117   V(SVEIntMulAddPredicated)                                      \
1118   V(SVEIntMulAddUnpredicated)                                    \
1119   V(SVEIntReduction)                                             \
1120   V(SVEIntUnaryArithmeticPredicated)                             \
1121   V(SVEMovprfx)                                                  \
1122   V(SVEMulIndex)                                                 \
1123   V(SVEPermuteVectorExtract)                                     \
1124   V(SVEPermuteVectorInterleaving)                                \
1125   V(SVEPredicateCount)                                           \
1126   V(SVEPredicateLogical)                                         \
1127   V(SVEPropagateBreak)                                           \
1128   V(SVEStackFrameAdjustment)                                     \
1129   V(SVEStackFrameSize)                                           \
1130   V(SVEVectorSelect)                                             \
1131   V(SVEBitwiseLogical_Predicated)                                \
1132   V(SVEBitwiseLogicalWithImm_Unpredicated)                       \
1133   V(SVEBitwiseShiftByImm_Predicated)                             \
1134   V(SVEBitwiseShiftByVector_Predicated)                          \
1135   V(SVEBitwiseShiftByWideElements_Predicated)                    \
1136   V(SVEBroadcastBitmaskImm)                                      \
1137   V(SVEBroadcastFPImm_Unpredicated)                              \
1138   V(SVEBroadcastGeneralRegister)                                 \
1139   V(SVEBroadcastIndexElement)                                    \
1140   V(SVEBroadcastIntImm_Unpredicated)                             \
1141   V(SVECompressActiveElements)                                   \
1142   V(SVEConditionallyBroadcastElementToVector)                    \
1143   V(SVEConditionallyExtractElementToSIMDFPScalar)                \
1144   V(SVEConditionallyExtractElementToGeneralRegister)             \
1145   V(SVEConditionallyTerminateScalars)                            \
1146   V(SVEConstructivePrefix_Unpredicated)                          \
1147   V(SVEContiguousFirstFaultLoad_ScalarPlusScalar)                \
1148   V(SVEContiguousLoad_ScalarPlusImm)                             \
1149   V(SVEContiguousLoad_ScalarPlusScalar)                          \
1150   V(SVEContiguousNonFaultLoad_ScalarPlusImm)                     \
1151   V(SVEContiguousNonTemporalLoad_ScalarPlusImm)                  \
1152   V(SVEContiguousNonTemporalLoad_ScalarPlusScalar)               \
1153   V(SVEContiguousNonTemporalStore_ScalarPlusImm)                 \
1154   V(SVEContiguousNonTemporalStore_ScalarPlusScalar)              \
1155   V(SVEContiguousPrefetch_ScalarPlusImm)                         \
1156   V(SVEContiguousPrefetch_ScalarPlusScalar)                      \
1157   V(SVEContiguousStore_ScalarPlusImm)                            \
1158   V(SVEContiguousStore_ScalarPlusScalar)                         \
1159   V(SVECopySIMDFPScalarRegisterToVector_Predicated)              \
1160   V(SVECopyFPImm_Predicated)                                     \
1161   V(SVECopyGeneralRegisterToVector_Predicated)                   \
1162   V(SVECopyIntImm_Predicated)                                    \
1163   V(SVEElementCount)                                             \
1164   V(SVEExtractElementToSIMDFPScalarRegister)                     \
1165   V(SVEExtractElementToGeneralRegister)                          \
1166   V(SVEFPArithmetic_Predicated)                                  \
1167   V(SVEFPArithmeticWithImm_Predicated)                           \
1168   V(SVEFPConvertPrecision)                                       \
1169   V(SVEFPConvertToInt)                                           \
1170   V(SVEFPExponentialAccelerator)                                 \
1171   V(SVEFPRoundToIntegralValue)                                   \
1172   V(SVEFPTrigMulAddCoefficient)                                  \
1173   V(SVEFPTrigSelectCoefficient)                                  \
1174   V(SVEFPUnaryOp)                                                \
1175   V(SVEIncDecRegisterByElementCount)                             \
1176   V(SVEIncDecVectorByElementCount)                               \
1177   V(SVEInsertSIMDFPScalarRegister)                               \
1178   V(SVEInsertGeneralRegister)                                    \
1179   V(SVEIntAddSubtractImm_Unpredicated)                           \
1180   V(SVEIntAddSubtractVectors_Predicated)                         \
1181   V(SVEIntCompareScalarCountAndLimit)                            \
1182   V(SVEIntConvertToFP)                                           \
1183   V(SVEIntDivideVectors_Predicated)                              \
1184   V(SVEIntMinMaxImm_Unpredicated)                                \
1185   V(SVEIntMinMaxDifference_Predicated)                           \
1186   V(SVEIntMulImm_Unpredicated)                                   \
1187   V(SVEIntMulVectors_Predicated)                                 \
1188   V(SVELoadAndBroadcastElement)                                  \
1189   V(SVELoadAndBroadcastQuadword_ScalarPlusImm)                   \
1190   V(SVELoadAndBroadcastQuadword_ScalarPlusScalar)                \
1191   V(SVELoadMultipleStructures_ScalarPlusImm)                     \
1192   V(SVELoadMultipleStructures_ScalarPlusScalar)                  \
1193   V(SVELoadPredicateRegister)                                    \
1194   V(SVELoadVectorRegister)                                       \
1195   V(SVEPartitionBreakCondition)                                  \
1196   V(SVEPermutePredicateElements)                                 \
1197   V(SVEPredicateFirstActive)                                     \
1198   V(SVEPredicateInitialize)                                      \
1199   V(SVEPredicateNextActive)                                      \
1200   V(SVEPredicateReadFromFFR_Predicated)                          \
1201   V(SVEPredicateReadFromFFR_Unpredicated)                        \
1202   V(SVEPredicateTest)                                            \
1203   V(SVEPredicateZero)                                            \
1204   V(SVEPropagateBreakToNextPartition)                            \
1205   V(SVEReversePredicateElements)                                 \
1206   V(SVEReverseVectorElements)                                    \
1207   V(SVEReverseWithinElements)                                    \
1208   V(SVESaturatingIncDecRegisterByElementCount)                   \
1209   V(SVESaturatingIncDecVectorByElementCount)                     \
1210   V(SVEStoreMultipleStructures_ScalarPlusImm)                    \
1211   V(SVEStoreMultipleStructures_ScalarPlusScalar)                 \
1212   V(SVEStorePredicateRegister)                                   \
1213   V(SVEStoreVectorRegister)                                      \
1214   V(SVETableLookup)                                              \
1215   V(SVEUnpackPredicateElements)                                  \
1216   V(SVEUnpackVectorElements)                                     \
1217   V(SVEVectorSplice_Destructive)
1218 
1219 #define VIXL_DEFINE_SIMPLE_SVE_VISITOR(NAME)                       \
1220   void CPUFeaturesAuditor::Visit##NAME(const Instruction* instr) { \
1221     RecordInstructionFeaturesScope scope(this);                    \
1222     scope.Record(CPUFeatures::kSVE);                               \
1223     USE(instr);                                                    \
1224   }
VIXL_SIMPLE_SVE_VISITOR_LIST(VIXL_DEFINE_SIMPLE_SVE_VISITOR)1225 VIXL_SIMPLE_SVE_VISITOR_LIST(VIXL_DEFINE_SIMPLE_SVE_VISITOR)
1226 #undef VIXL_DEFINE_SIMPLE_SVE_VISITOR
1227 #undef VIXL_SIMPLE_SVE_VISITOR_LIST
1228 
1229 void CPUFeaturesAuditor::VisitSystem(const Instruction* instr) {
1230   RecordInstructionFeaturesScope scope(this);
1231   if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1232     CPUFeatures required;
1233     switch (instr->GetInstructionBits()) {
1234       case PACIA1716:
1235       case PACIB1716:
1236       case AUTIA1716:
1237       case AUTIB1716:
1238       case PACIAZ:
1239       case PACIASP:
1240       case PACIBZ:
1241       case PACIBSP:
1242       case AUTIAZ:
1243       case AUTIASP:
1244       case AUTIBZ:
1245       case AUTIBSP:
1246       case XPACLRI:
1247         required.Combine(CPUFeatures::kPAuth);
1248         break;
1249       default:
1250         switch (instr->GetImmHint()) {
1251           case ESB:
1252             required.Combine(CPUFeatures::kRAS);
1253             break;
1254           case BTI:
1255           case BTI_j:
1256           case BTI_c:
1257           case BTI_jc:
1258             required.Combine(CPUFeatures::kBTI);
1259             break;
1260           default:
1261             break;
1262         }
1263         break;
1264     }
1265 
1266     // These are all HINT instructions, and behave as NOPs if the corresponding
1267     // features are not implemented, so we record the corresponding features
1268     // only if they are available.
1269     if (available_.Has(required)) scope.Record(required);
1270   } else if (instr->Mask(SystemSysMask) == SYS) {
1271     switch (instr->GetSysOp()) {
1272       // DC instruction variants.
1273       case CVAP:
1274         scope.Record(CPUFeatures::kDCPoP);
1275         break;
1276       case CVADP:
1277         scope.Record(CPUFeatures::kDCCVADP);
1278         break;
1279       case IVAU:
1280       case CVAC:
1281       case CVAU:
1282       case CIVAC:
1283         // No special CPU features.
1284         break;
1285     }
1286   } else if (instr->Mask(SystemPStateFMask) == SystemPStateFixed) {
1287     switch (instr->Mask(SystemPStateMask)) {
1288       case CFINV:
1289         scope.Record(CPUFeatures::kFlagM);
1290         break;
1291       case AXFLAG:
1292       case XAFLAG:
1293         scope.Record(CPUFeatures::kAXFlag);
1294         break;
1295     }
1296   } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1297     if (instr->Mask(SystemSysRegMask) == MRS) {
1298       switch (instr->GetImmSystemRegister()) {
1299         case RNDR:
1300         case RNDRRS:
1301           scope.Record(CPUFeatures::kRNG);
1302           break;
1303       }
1304     }
1305   }
1306 }
1307 
VisitTestBranch(const Instruction * instr)1308 void CPUFeaturesAuditor::VisitTestBranch(const Instruction* instr) {
1309   RecordInstructionFeaturesScope scope(this);
1310   USE(instr);
1311 }
1312 
VisitUnallocated(const Instruction * instr)1313 void CPUFeaturesAuditor::VisitUnallocated(const Instruction* instr) {
1314   RecordInstructionFeaturesScope scope(this);
1315   USE(instr);
1316 }
1317 
VisitUnconditionalBranch(const Instruction * instr)1318 void CPUFeaturesAuditor::VisitUnconditionalBranch(const Instruction* instr) {
1319   RecordInstructionFeaturesScope scope(this);
1320   USE(instr);
1321 }
1322 
VisitUnconditionalBranchToRegister(const Instruction * instr)1323 void CPUFeaturesAuditor::VisitUnconditionalBranchToRegister(
1324     const Instruction* instr) {
1325   RecordInstructionFeaturesScope scope(this);
1326   switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
1327     case BRAAZ:
1328     case BRABZ:
1329     case BLRAAZ:
1330     case BLRABZ:
1331     case RETAA:
1332     case RETAB:
1333     case BRAA:
1334     case BRAB:
1335     case BLRAA:
1336     case BLRAB:
1337       scope.Record(CPUFeatures::kPAuth);
1338       return;
1339     default:
1340       // No additional features.
1341       return;
1342   }
1343 }
1344 
VisitReserved(const Instruction * instr)1345 void CPUFeaturesAuditor::VisitReserved(const Instruction* instr) {
1346   RecordInstructionFeaturesScope scope(this);
1347   USE(instr);
1348 }
1349 
VisitUnimplemented(const Instruction * instr)1350 void CPUFeaturesAuditor::VisitUnimplemented(const Instruction* instr) {
1351   RecordInstructionFeaturesScope scope(this);
1352   USE(instr);
1353 }
1354 
1355 
1356 }  // namespace aarch64
1357 }  // namespace vixl
1358