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 
VisitAtomicMemory(const Instruction * instr)143 void CPUFeaturesAuditor::VisitAtomicMemory(const Instruction* instr) {
144   RecordInstructionFeaturesScope scope(this);
145   switch (instr->Mask(AtomicMemoryMask)) {
146     case LDAPRB:
147     case LDAPRH:
148     case LDAPR_w:
149     case LDAPR_x:
150       scope.Record(CPUFeatures::kRCpc);
151       return;
152     default:
153       // Everything else belongs to the Atomics extension.
154       scope.Record(CPUFeatures::kAtomics);
155       return;
156   }
157 }
158 
VisitBitfield(const Instruction * instr)159 void CPUFeaturesAuditor::VisitBitfield(const Instruction* instr) {
160   RecordInstructionFeaturesScope scope(this);
161   USE(instr);
162 }
163 
VisitCompareBranch(const Instruction * instr)164 void CPUFeaturesAuditor::VisitCompareBranch(const Instruction* instr) {
165   RecordInstructionFeaturesScope scope(this);
166   USE(instr);
167 }
168 
VisitConditionalBranch(const Instruction * instr)169 void CPUFeaturesAuditor::VisitConditionalBranch(const Instruction* instr) {
170   RecordInstructionFeaturesScope scope(this);
171   USE(instr);
172 }
173 
VisitConditionalCompareImmediate(const Instruction * instr)174 void CPUFeaturesAuditor::VisitConditionalCompareImmediate(
175     const Instruction* instr) {
176   RecordInstructionFeaturesScope scope(this);
177   USE(instr);
178 }
179 
VisitConditionalCompareRegister(const Instruction * instr)180 void CPUFeaturesAuditor::VisitConditionalCompareRegister(
181     const Instruction* instr) {
182   RecordInstructionFeaturesScope scope(this);
183   USE(instr);
184 }
185 
VisitConditionalSelect(const Instruction * instr)186 void CPUFeaturesAuditor::VisitConditionalSelect(const Instruction* instr) {
187   RecordInstructionFeaturesScope scope(this);
188   USE(instr);
189 }
190 
VisitCrypto2RegSHA(const Instruction * instr)191 void CPUFeaturesAuditor::VisitCrypto2RegSHA(const Instruction* instr) {
192   RecordInstructionFeaturesScope scope(this);
193   USE(instr);
194 }
195 
VisitCrypto3RegSHA(const Instruction * instr)196 void CPUFeaturesAuditor::VisitCrypto3RegSHA(const Instruction* instr) {
197   RecordInstructionFeaturesScope scope(this);
198   USE(instr);
199 }
200 
VisitCryptoAES(const Instruction * instr)201 void CPUFeaturesAuditor::VisitCryptoAES(const Instruction* instr) {
202   RecordInstructionFeaturesScope scope(this);
203   USE(instr);
204 }
205 
VisitDataProcessing1Source(const Instruction * instr)206 void CPUFeaturesAuditor::VisitDataProcessing1Source(const Instruction* instr) {
207   RecordInstructionFeaturesScope scope(this);
208   switch (instr->Mask(DataProcessing1SourceMask)) {
209     case PACIA:
210     case PACIB:
211     case PACDA:
212     case PACDB:
213     case AUTIA:
214     case AUTIB:
215     case AUTDA:
216     case AUTDB:
217     case PACIZA:
218     case PACIZB:
219     case PACDZA:
220     case PACDZB:
221     case AUTIZA:
222     case AUTIZB:
223     case AUTDZA:
224     case AUTDZB:
225     case XPACI:
226     case XPACD:
227       scope.Record(CPUFeatures::kPAuth);
228       return;
229     default:
230       // No special CPU features.
231       return;
232   }
233 }
234 
VisitDataProcessing2Source(const Instruction * instr)235 void CPUFeaturesAuditor::VisitDataProcessing2Source(const Instruction* instr) {
236   RecordInstructionFeaturesScope scope(this);
237   switch (instr->Mask(DataProcessing2SourceMask)) {
238     case CRC32B:
239     case CRC32H:
240     case CRC32W:
241     case CRC32X:
242     case CRC32CB:
243     case CRC32CH:
244     case CRC32CW:
245     case CRC32CX:
246       scope.Record(CPUFeatures::kCRC32);
247       return;
248     case PACGA:
249       scope.Record(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric);
250       return;
251     default:
252       // No special CPU features.
253       return;
254   }
255 }
256 
VisitDataProcessing3Source(const Instruction * instr)257 void CPUFeaturesAuditor::VisitDataProcessing3Source(const Instruction* instr) {
258   RecordInstructionFeaturesScope scope(this);
259   USE(instr);
260 }
261 
VisitException(const Instruction * instr)262 void CPUFeaturesAuditor::VisitException(const Instruction* instr) {
263   RecordInstructionFeaturesScope scope(this);
264   USE(instr);
265 }
266 
VisitExtract(const Instruction * instr)267 void CPUFeaturesAuditor::VisitExtract(const Instruction* instr) {
268   RecordInstructionFeaturesScope scope(this);
269   USE(instr);
270 }
271 
VisitFPCompare(const Instruction * instr)272 void CPUFeaturesAuditor::VisitFPCompare(const Instruction* instr) {
273   RecordInstructionFeaturesScope scope(this);
274   // All of these instructions require FP.
275   scope.Record(CPUFeatures::kFP);
276   switch (instr->Mask(FPCompareMask)) {
277     case FCMP_h:
278     case FCMP_h_zero:
279     case FCMPE_h:
280     case FCMPE_h_zero:
281       scope.Record(CPUFeatures::kFPHalf);
282       return;
283     default:
284       // No special CPU features.
285       return;
286   }
287 }
288 
VisitFPConditionalCompare(const Instruction * instr)289 void CPUFeaturesAuditor::VisitFPConditionalCompare(const Instruction* instr) {
290   RecordInstructionFeaturesScope scope(this);
291   // All of these instructions require FP.
292   scope.Record(CPUFeatures::kFP);
293   switch (instr->Mask(FPConditionalCompareMask)) {
294     case FCCMP_h:
295     case FCCMPE_h:
296       scope.Record(CPUFeatures::kFPHalf);
297       return;
298     default:
299       // No special CPU features.
300       return;
301   }
302 }
303 
VisitFPConditionalSelect(const Instruction * instr)304 void CPUFeaturesAuditor::VisitFPConditionalSelect(const Instruction* instr) {
305   RecordInstructionFeaturesScope scope(this);
306   // All of these instructions require FP.
307   scope.Record(CPUFeatures::kFP);
308   if (instr->Mask(FPConditionalSelectMask) == FCSEL_h) {
309     scope.Record(CPUFeatures::kFPHalf);
310   }
311 }
312 
VisitFPDataProcessing1Source(const Instruction * instr)313 void CPUFeaturesAuditor::VisitFPDataProcessing1Source(
314     const Instruction* instr) {
315   RecordInstructionFeaturesScope scope(this);
316   // All of these instructions require FP.
317   scope.Record(CPUFeatures::kFP);
318   switch (instr->Mask(FPDataProcessing1SourceMask)) {
319     case FMOV_h:
320     case FABS_h:
321     case FNEG_h:
322     case FSQRT_h:
323     case FRINTN_h:
324     case FRINTP_h:
325     case FRINTM_h:
326     case FRINTZ_h:
327     case FRINTA_h:
328     case FRINTX_h:
329     case FRINTI_h:
330       scope.Record(CPUFeatures::kFPHalf);
331       return;
332     default:
333       // No special CPU features.
334       // This category includes some half-precision FCVT instructions that do
335       // not require FPHalf.
336       return;
337   }
338 }
339 
VisitFPDataProcessing2Source(const Instruction * instr)340 void CPUFeaturesAuditor::VisitFPDataProcessing2Source(
341     const Instruction* instr) {
342   RecordInstructionFeaturesScope scope(this);
343   // All of these instructions require FP.
344   scope.Record(CPUFeatures::kFP);
345   switch (instr->Mask(FPDataProcessing2SourceMask)) {
346     case FMUL_h:
347     case FDIV_h:
348     case FADD_h:
349     case FSUB_h:
350     case FMAX_h:
351     case FMIN_h:
352     case FMAXNM_h:
353     case FMINNM_h:
354     case FNMUL_h:
355       scope.Record(CPUFeatures::kFPHalf);
356       return;
357     default:
358       // No special CPU features.
359       return;
360   }
361 }
362 
VisitFPDataProcessing3Source(const Instruction * instr)363 void CPUFeaturesAuditor::VisitFPDataProcessing3Source(
364     const Instruction* instr) {
365   RecordInstructionFeaturesScope scope(this);
366   // All of these instructions require FP.
367   scope.Record(CPUFeatures::kFP);
368   switch (instr->Mask(FPDataProcessing3SourceMask)) {
369     case FMADD_h:
370     case FMSUB_h:
371     case FNMADD_h:
372     case FNMSUB_h:
373       scope.Record(CPUFeatures::kFPHalf);
374       return;
375     default:
376       // No special CPU features.
377       return;
378   }
379 }
380 
VisitFPFixedPointConvert(const Instruction * instr)381 void CPUFeaturesAuditor::VisitFPFixedPointConvert(const Instruction* instr) {
382   RecordInstructionFeaturesScope scope(this);
383   // All of these instructions require FP.
384   scope.Record(CPUFeatures::kFP);
385   switch (instr->Mask(FPFixedPointConvertMask)) {
386     case FCVTZS_wh_fixed:
387     case FCVTZS_xh_fixed:
388     case FCVTZU_wh_fixed:
389     case FCVTZU_xh_fixed:
390     case SCVTF_hw_fixed:
391     case SCVTF_hx_fixed:
392     case UCVTF_hw_fixed:
393     case UCVTF_hx_fixed:
394       scope.Record(CPUFeatures::kFPHalf);
395       return;
396     default:
397       // No special CPU features.
398       return;
399   }
400 }
401 
VisitFPImmediate(const Instruction * instr)402 void CPUFeaturesAuditor::VisitFPImmediate(const Instruction* instr) {
403   RecordInstructionFeaturesScope scope(this);
404   // All of these instructions require FP.
405   scope.Record(CPUFeatures::kFP);
406   if (instr->Mask(FPImmediateMask) == FMOV_h_imm) {
407     scope.Record(CPUFeatures::kFPHalf);
408   }
409 }
410 
VisitFPIntegerConvert(const Instruction * instr)411 void CPUFeaturesAuditor::VisitFPIntegerConvert(const Instruction* instr) {
412   RecordInstructionFeaturesScope scope(this);
413   // All of these instructions require FP.
414   scope.Record(CPUFeatures::kFP);
415   switch (instr->Mask(FPIntegerConvertMask)) {
416     case FCVTAS_wh:
417     case FCVTAS_xh:
418     case FCVTAU_wh:
419     case FCVTAU_xh:
420     case FCVTMS_wh:
421     case FCVTMS_xh:
422     case FCVTMU_wh:
423     case FCVTMU_xh:
424     case FCVTNS_wh:
425     case FCVTNS_xh:
426     case FCVTNU_wh:
427     case FCVTNU_xh:
428     case FCVTPS_wh:
429     case FCVTPS_xh:
430     case FCVTPU_wh:
431     case FCVTPU_xh:
432     case FCVTZS_wh:
433     case FCVTZS_xh:
434     case FCVTZU_wh:
435     case FCVTZU_xh:
436     case FMOV_hw:
437     case FMOV_hx:
438     case FMOV_wh:
439     case FMOV_xh:
440     case SCVTF_hw:
441     case SCVTF_hx:
442     case UCVTF_hw:
443     case UCVTF_hx:
444       scope.Record(CPUFeatures::kFPHalf);
445       return;
446     case FMOV_d1_x:
447     case FMOV_x_d1:
448       scope.Record(CPUFeatures::kNEON);
449       return;
450     case FJCVTZS:
451       scope.Record(CPUFeatures::kJSCVT);
452       return;
453     default:
454       // No special CPU features.
455       return;
456   }
457 }
458 
VisitLoadLiteral(const Instruction * instr)459 void CPUFeaturesAuditor::VisitLoadLiteral(const Instruction* instr) {
460   RecordInstructionFeaturesScope scope(this);
461   switch (instr->Mask(LoadLiteralMask)) {
462     case LDR_s_lit:
463     case LDR_d_lit:
464       scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
465       return;
466     case LDR_q_lit:
467       scope.Record(CPUFeatures::kNEON);
468       return;
469     default:
470       // No special CPU features.
471       return;
472   }
473 }
474 
VisitLoadStoreExclusive(const Instruction * instr)475 void CPUFeaturesAuditor::VisitLoadStoreExclusive(const Instruction* instr) {
476   RecordInstructionFeaturesScope scope(this);
477   switch (instr->Mask(LoadStoreExclusiveMask)) {
478     case CAS_w:
479     case CASA_w:
480     case CASL_w:
481     case CASAL_w:
482     case CAS_x:
483     case CASA_x:
484     case CASL_x:
485     case CASAL_x:
486     case CASB:
487     case CASAB:
488     case CASLB:
489     case CASALB:
490     case CASH:
491     case CASAH:
492     case CASLH:
493     case CASALH:
494     case CASP_w:
495     case CASPA_w:
496     case CASPL_w:
497     case CASPAL_w:
498     case CASP_x:
499     case CASPA_x:
500     case CASPL_x:
501     case CASPAL_x:
502       scope.Record(CPUFeatures::kAtomics);
503       return;
504     case STLLRB:
505     case LDLARB:
506     case STLLRH:
507     case LDLARH:
508     case STLLR_w:
509     case LDLAR_w:
510     case STLLR_x:
511     case LDLAR_x:
512       scope.Record(CPUFeatures::kLORegions);
513       return;
514     default:
515       // No special CPU features.
516       return;
517   }
518 }
519 
VisitLoadStorePairNonTemporal(const Instruction * instr)520 void CPUFeaturesAuditor::VisitLoadStorePairNonTemporal(
521     const Instruction* instr) {
522   LoadStorePairHelper(instr);
523 }
524 
VisitLoadStorePairOffset(const Instruction * instr)525 void CPUFeaturesAuditor::VisitLoadStorePairOffset(const Instruction* instr) {
526   LoadStorePairHelper(instr);
527 }
528 
VisitLoadStorePairPostIndex(const Instruction * instr)529 void CPUFeaturesAuditor::VisitLoadStorePairPostIndex(const Instruction* instr) {
530   LoadStorePairHelper(instr);
531 }
532 
VisitLoadStorePairPreIndex(const Instruction * instr)533 void CPUFeaturesAuditor::VisitLoadStorePairPreIndex(const Instruction* instr) {
534   LoadStorePairHelper(instr);
535 }
536 
VisitLoadStorePostIndex(const Instruction * instr)537 void CPUFeaturesAuditor::VisitLoadStorePostIndex(const Instruction* instr) {
538   LoadStoreHelper(instr);
539 }
540 
VisitLoadStorePreIndex(const Instruction * instr)541 void CPUFeaturesAuditor::VisitLoadStorePreIndex(const Instruction* instr) {
542   LoadStoreHelper(instr);
543 }
544 
VisitLoadStoreRegisterOffset(const Instruction * instr)545 void CPUFeaturesAuditor::VisitLoadStoreRegisterOffset(
546     const Instruction* instr) {
547   LoadStoreHelper(instr);
548 }
549 
VisitLoadStoreUnscaledOffset(const Instruction * instr)550 void CPUFeaturesAuditor::VisitLoadStoreUnscaledOffset(
551     const Instruction* instr) {
552   LoadStoreHelper(instr);
553 }
554 
VisitLoadStoreUnsignedOffset(const Instruction * instr)555 void CPUFeaturesAuditor::VisitLoadStoreUnsignedOffset(
556     const Instruction* instr) {
557   LoadStoreHelper(instr);
558 }
559 
VisitLogicalImmediate(const Instruction * instr)560 void CPUFeaturesAuditor::VisitLogicalImmediate(const Instruction* instr) {
561   RecordInstructionFeaturesScope scope(this);
562   USE(instr);
563 }
564 
VisitLogicalShifted(const Instruction * instr)565 void CPUFeaturesAuditor::VisitLogicalShifted(const Instruction* instr) {
566   RecordInstructionFeaturesScope scope(this);
567   USE(instr);
568 }
569 
VisitMoveWideImmediate(const Instruction * instr)570 void CPUFeaturesAuditor::VisitMoveWideImmediate(const Instruction* instr) {
571   RecordInstructionFeaturesScope scope(this);
572   USE(instr);
573 }
574 
VisitNEON2RegMisc(const Instruction * instr)575 void CPUFeaturesAuditor::VisitNEON2RegMisc(const Instruction* instr) {
576   RecordInstructionFeaturesScope scope(this);
577   // All of these instructions require NEON.
578   scope.Record(CPUFeatures::kNEON);
579   switch (instr->Mask(NEON2RegMiscFPMask)) {
580     case NEON_FABS:
581     case NEON_FNEG:
582     case NEON_FSQRT:
583     case NEON_FCVTL:
584     case NEON_FCVTN:
585     case NEON_FCVTXN:
586     case NEON_FRINTI:
587     case NEON_FRINTX:
588     case NEON_FRINTA:
589     case NEON_FRINTM:
590     case NEON_FRINTN:
591     case NEON_FRINTP:
592     case NEON_FRINTZ:
593     case NEON_FCVTNS:
594     case NEON_FCVTNU:
595     case NEON_FCVTPS:
596     case NEON_FCVTPU:
597     case NEON_FCVTMS:
598     case NEON_FCVTMU:
599     case NEON_FCVTZS:
600     case NEON_FCVTZU:
601     case NEON_FCVTAS:
602     case NEON_FCVTAU:
603     case NEON_SCVTF:
604     case NEON_UCVTF:
605     case NEON_FRSQRTE:
606     case NEON_FRECPE:
607     case NEON_FCMGT_zero:
608     case NEON_FCMGE_zero:
609     case NEON_FCMEQ_zero:
610     case NEON_FCMLE_zero:
611     case NEON_FCMLT_zero:
612       scope.Record(CPUFeatures::kFP);
613       return;
614     default:
615       // No additional features.
616       return;
617   }
618 }
619 
VisitNEON2RegMiscFP16(const Instruction * instr)620 void CPUFeaturesAuditor::VisitNEON2RegMiscFP16(const Instruction* instr) {
621   RecordInstructionFeaturesScope scope(this);
622   // All of these instructions require NEONHalf.
623   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
624   USE(instr);
625 }
626 
VisitNEON3Different(const Instruction * instr)627 void CPUFeaturesAuditor::VisitNEON3Different(const Instruction* instr) {
628   RecordInstructionFeaturesScope scope(this);
629   // All of these instructions require NEON.
630   scope.Record(CPUFeatures::kNEON);
631   USE(instr);
632 }
633 
VisitNEON3Same(const Instruction * instr)634 void CPUFeaturesAuditor::VisitNEON3Same(const Instruction* instr) {
635   RecordInstructionFeaturesScope scope(this);
636   // All of these instructions require NEON.
637   scope.Record(CPUFeatures::kNEON);
638   if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
639     scope.Record(CPUFeatures::kFP);
640   }
641 }
642 
VisitNEON3SameExtra(const Instruction * instr)643 void CPUFeaturesAuditor::VisitNEON3SameExtra(const Instruction* instr) {
644   RecordInstructionFeaturesScope scope(this);
645   // All of these instructions require NEON.
646   scope.Record(CPUFeatures::kNEON);
647   if ((instr->Mask(NEON3SameExtraFCMLAMask) == NEON_FCMLA) ||
648       (instr->Mask(NEON3SameExtraFCADDMask) == NEON_FCADD)) {
649     scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma);
650     if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf);
651   } else {
652     switch (instr->Mask(NEON3SameExtraMask)) {
653       case NEON_SDOT:
654       case NEON_UDOT:
655         scope.Record(CPUFeatures::kDotProduct);
656         return;
657       case NEON_SQRDMLAH:
658       case NEON_SQRDMLSH:
659         scope.Record(CPUFeatures::kRDM);
660         return;
661       default:
662         // No additional features.
663         return;
664     }
665   }
666 }
667 
VisitNEON3SameFP16(const Instruction * instr)668 void CPUFeaturesAuditor::VisitNEON3SameFP16(const Instruction* instr) {
669   RecordInstructionFeaturesScope scope(this);
670   // All of these instructions require NEON FP16 support.
671   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
672   USE(instr);
673 }
674 
VisitNEONAcrossLanes(const Instruction * instr)675 void CPUFeaturesAuditor::VisitNEONAcrossLanes(const Instruction* instr) {
676   RecordInstructionFeaturesScope scope(this);
677   // All of these instructions require NEON.
678   scope.Record(CPUFeatures::kNEON);
679   if (instr->Mask(NEONAcrossLanesFP16FMask) == NEONAcrossLanesFP16Fixed) {
680     // FMAXV_H, FMINV_H, FMAXNMV_H, FMINNMV_H
681     scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf);
682   } else if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
683     // FMAXV, FMINV, FMAXNMV, FMINNMV
684     scope.Record(CPUFeatures::kFP);
685   }
686 }
687 
VisitNEONByIndexedElement(const Instruction * instr)688 void CPUFeaturesAuditor::VisitNEONByIndexedElement(const Instruction* instr) {
689   RecordInstructionFeaturesScope scope(this);
690   // All of these instructions require NEON.
691   scope.Record(CPUFeatures::kNEON);
692   switch (instr->Mask(NEONByIndexedElementMask)) {
693     case NEON_SDOT_byelement:
694     case NEON_UDOT_byelement:
695       scope.Record(CPUFeatures::kDotProduct);
696       return;
697     case NEON_SQRDMLAH_byelement:
698     case NEON_SQRDMLSH_byelement:
699       scope.Record(CPUFeatures::kRDM);
700       return;
701     default:
702       // Fall through to check other FP instructions.
703       break;
704   }
705   switch (instr->Mask(NEONByIndexedElementFPMask)) {
706     case NEON_FMLA_H_byelement:
707     case NEON_FMLS_H_byelement:
708     case NEON_FMUL_H_byelement:
709     case NEON_FMULX_H_byelement:
710       scope.Record(CPUFeatures::kNEONHalf);
711       VIXL_FALLTHROUGH();
712     case NEON_FMLA_byelement:
713     case NEON_FMLS_byelement:
714     case NEON_FMUL_byelement:
715     case NEON_FMULX_byelement:
716       scope.Record(CPUFeatures::kFP);
717       return;
718     default:
719       switch (instr->Mask(NEONByIndexedElementFPComplexMask)) {
720         case NEON_FCMLA_byelement:
721           scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma);
722           if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf);
723           return;
724       }
725       // No additional features.
726       return;
727   }
728 }
729 
VisitNEONCopy(const Instruction * instr)730 void CPUFeaturesAuditor::VisitNEONCopy(const Instruction* instr) {
731   RecordInstructionFeaturesScope scope(this);
732   // All of these instructions require NEON.
733   scope.Record(CPUFeatures::kNEON);
734   USE(instr);
735 }
736 
VisitNEONExtract(const Instruction * instr)737 void CPUFeaturesAuditor::VisitNEONExtract(const Instruction* instr) {
738   RecordInstructionFeaturesScope scope(this);
739   // All of these instructions require NEON.
740   scope.Record(CPUFeatures::kNEON);
741   USE(instr);
742 }
743 
VisitNEONLoadStoreMultiStruct(const Instruction * instr)744 void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStruct(
745     const Instruction* instr) {
746   RecordInstructionFeaturesScope scope(this);
747   // All of these instructions require NEON.
748   scope.Record(CPUFeatures::kNEON);
749   USE(instr);
750 }
751 
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)752 void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStructPostIndex(
753     const Instruction* instr) {
754   RecordInstructionFeaturesScope scope(this);
755   // All of these instructions require NEON.
756   scope.Record(CPUFeatures::kNEON);
757   USE(instr);
758 }
759 
VisitNEONLoadStoreSingleStruct(const Instruction * instr)760 void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStruct(
761     const Instruction* instr) {
762   RecordInstructionFeaturesScope scope(this);
763   // All of these instructions require NEON.
764   scope.Record(CPUFeatures::kNEON);
765   USE(instr);
766 }
767 
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)768 void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStructPostIndex(
769     const Instruction* instr) {
770   RecordInstructionFeaturesScope scope(this);
771   // All of these instructions require NEON.
772   scope.Record(CPUFeatures::kNEON);
773   USE(instr);
774 }
775 
VisitNEONModifiedImmediate(const Instruction * instr)776 void CPUFeaturesAuditor::VisitNEONModifiedImmediate(const Instruction* instr) {
777   RecordInstructionFeaturesScope scope(this);
778   // All of these instructions require NEON.
779   scope.Record(CPUFeatures::kNEON);
780   if (instr->GetNEONCmode() == 0xf) {
781     // FMOV (vector, immediate), double-, single- or half-precision.
782     scope.Record(CPUFeatures::kFP);
783     if (instr->ExtractBit(11)) scope.Record(CPUFeatures::kNEONHalf);
784   }
785   USE(instr);
786 }
787 
VisitNEONPerm(const Instruction * instr)788 void CPUFeaturesAuditor::VisitNEONPerm(const Instruction* instr) {
789   RecordInstructionFeaturesScope scope(this);
790   // All of these instructions require NEON.
791   scope.Record(CPUFeatures::kNEON);
792   USE(instr);
793 }
794 
VisitNEONScalar2RegMisc(const Instruction * instr)795 void CPUFeaturesAuditor::VisitNEONScalar2RegMisc(const Instruction* instr) {
796   RecordInstructionFeaturesScope scope(this);
797   // All of these instructions require NEON.
798   scope.Record(CPUFeatures::kNEON);
799   switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
800     case NEON_FRECPE_scalar:
801     case NEON_FRECPX_scalar:
802     case NEON_FRSQRTE_scalar:
803     case NEON_FCMGT_zero_scalar:
804     case NEON_FCMGE_zero_scalar:
805     case NEON_FCMEQ_zero_scalar:
806     case NEON_FCMLE_zero_scalar:
807     case NEON_FCMLT_zero_scalar:
808     case NEON_SCVTF_scalar:
809     case NEON_UCVTF_scalar:
810     case NEON_FCVTNS_scalar:
811     case NEON_FCVTNU_scalar:
812     case NEON_FCVTPS_scalar:
813     case NEON_FCVTPU_scalar:
814     case NEON_FCVTMS_scalar:
815     case NEON_FCVTMU_scalar:
816     case NEON_FCVTZS_scalar:
817     case NEON_FCVTZU_scalar:
818     case NEON_FCVTAS_scalar:
819     case NEON_FCVTAU_scalar:
820     case NEON_FCVTXN_scalar:
821       scope.Record(CPUFeatures::kFP);
822       return;
823     default:
824       // No additional features.
825       return;
826   }
827 }
828 
VisitNEONScalar2RegMiscFP16(const Instruction * instr)829 void CPUFeaturesAuditor::VisitNEONScalar2RegMiscFP16(const Instruction* instr) {
830   RecordInstructionFeaturesScope scope(this);
831   // All of these instructions require NEONHalf.
832   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
833   USE(instr);
834 }
835 
VisitNEONScalar3Diff(const Instruction * instr)836 void CPUFeaturesAuditor::VisitNEONScalar3Diff(const Instruction* instr) {
837   RecordInstructionFeaturesScope scope(this);
838   // All of these instructions require NEON.
839   scope.Record(CPUFeatures::kNEON);
840   USE(instr);
841 }
842 
VisitNEONScalar3Same(const Instruction * instr)843 void CPUFeaturesAuditor::VisitNEONScalar3Same(const Instruction* instr) {
844   RecordInstructionFeaturesScope scope(this);
845   // All of these instructions require NEON.
846   scope.Record(CPUFeatures::kNEON);
847   if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
848     scope.Record(CPUFeatures::kFP);
849   }
850 }
851 
VisitNEONScalar3SameExtra(const Instruction * instr)852 void CPUFeaturesAuditor::VisitNEONScalar3SameExtra(const Instruction* instr) {
853   RecordInstructionFeaturesScope scope(this);
854   // All of these instructions require NEON and RDM.
855   scope.Record(CPUFeatures::kNEON, CPUFeatures::kRDM);
856   USE(instr);
857 }
858 
VisitNEONScalar3SameFP16(const Instruction * instr)859 void CPUFeaturesAuditor::VisitNEONScalar3SameFP16(const Instruction* instr) {
860   RecordInstructionFeaturesScope scope(this);
861   // All of these instructions require NEONHalf.
862   scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
863   USE(instr);
864 }
865 
VisitNEONScalarByIndexedElement(const Instruction * instr)866 void CPUFeaturesAuditor::VisitNEONScalarByIndexedElement(
867     const Instruction* instr) {
868   RecordInstructionFeaturesScope scope(this);
869   // All of these instructions require NEON.
870   scope.Record(CPUFeatures::kNEON);
871   switch (instr->Mask(NEONScalarByIndexedElementMask)) {
872     case NEON_SQRDMLAH_byelement_scalar:
873     case NEON_SQRDMLSH_byelement_scalar:
874       scope.Record(CPUFeatures::kRDM);
875       return;
876     default:
877       switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
878         case NEON_FMLA_H_byelement_scalar:
879         case NEON_FMLS_H_byelement_scalar:
880         case NEON_FMUL_H_byelement_scalar:
881         case NEON_FMULX_H_byelement_scalar:
882           scope.Record(CPUFeatures::kNEONHalf);
883           VIXL_FALLTHROUGH();
884         case NEON_FMLA_byelement_scalar:
885         case NEON_FMLS_byelement_scalar:
886         case NEON_FMUL_byelement_scalar:
887         case NEON_FMULX_byelement_scalar:
888           scope.Record(CPUFeatures::kFP);
889           return;
890       }
891       // No additional features.
892       return;
893   }
894 }
895 
VisitNEONScalarCopy(const Instruction * instr)896 void CPUFeaturesAuditor::VisitNEONScalarCopy(const Instruction* instr) {
897   RecordInstructionFeaturesScope scope(this);
898   // All of these instructions require NEON.
899   scope.Record(CPUFeatures::kNEON);
900   USE(instr);
901 }
902 
VisitNEONScalarPairwise(const Instruction * instr)903 void CPUFeaturesAuditor::VisitNEONScalarPairwise(const Instruction* instr) {
904   RecordInstructionFeaturesScope scope(this);
905   // All of these instructions require NEON.
906   scope.Record(CPUFeatures::kNEON);
907   switch (instr->Mask(NEONScalarPairwiseMask)) {
908     case NEON_FMAXNMP_h_scalar:
909     case NEON_FADDP_h_scalar:
910     case NEON_FMAXP_h_scalar:
911     case NEON_FMINNMP_h_scalar:
912     case NEON_FMINP_h_scalar:
913       scope.Record(CPUFeatures::kNEONHalf);
914       VIXL_FALLTHROUGH();
915     case NEON_FADDP_scalar:
916     case NEON_FMAXP_scalar:
917     case NEON_FMAXNMP_scalar:
918     case NEON_FMINP_scalar:
919     case NEON_FMINNMP_scalar:
920       scope.Record(CPUFeatures::kFP);
921       return;
922     default:
923       // No additional features.
924       return;
925   }
926 }
927 
VisitNEONScalarShiftImmediate(const Instruction * instr)928 void CPUFeaturesAuditor::VisitNEONScalarShiftImmediate(
929     const Instruction* instr) {
930   RecordInstructionFeaturesScope scope(this);
931   // All of these instructions require NEON.
932   scope.Record(CPUFeatures::kNEON);
933   switch (instr->Mask(NEONScalarShiftImmediateMask)) {
934     case NEON_FCVTZS_imm_scalar:
935     case NEON_FCVTZU_imm_scalar:
936     case NEON_SCVTF_imm_scalar:
937     case NEON_UCVTF_imm_scalar:
938       scope.Record(CPUFeatures::kFP);
939       // If immh is 0b001x then the data type is FP16, and requires kNEONHalf.
940       if ((instr->GetImmNEONImmh() & 0xe) == 0x2) {
941         scope.Record(CPUFeatures::kNEONHalf);
942       }
943       return;
944     default:
945       // No additional features.
946       return;
947   }
948 }
949 
VisitNEONShiftImmediate(const Instruction * instr)950 void CPUFeaturesAuditor::VisitNEONShiftImmediate(const Instruction* instr) {
951   RecordInstructionFeaturesScope scope(this);
952   // All of these instructions require NEON.
953   scope.Record(CPUFeatures::kNEON);
954   switch (instr->Mask(NEONShiftImmediateMask)) {
955     case NEON_SCVTF_imm:
956     case NEON_UCVTF_imm:
957     case NEON_FCVTZS_imm:
958     case NEON_FCVTZU_imm:
959       scope.Record(CPUFeatures::kFP);
960       // If immh is 0b001x then the data type is FP16, and requires kNEONHalf.
961       if ((instr->GetImmNEONImmh() & 0xe) == 0x2) {
962         scope.Record(CPUFeatures::kNEONHalf);
963       }
964       return;
965     default:
966       // No additional features.
967       return;
968   }
969 }
970 
VisitNEONTable(const Instruction * instr)971 void CPUFeaturesAuditor::VisitNEONTable(const Instruction* instr) {
972   RecordInstructionFeaturesScope scope(this);
973   // All of these instructions require NEON.
974   scope.Record(CPUFeatures::kNEON);
975   USE(instr);
976 }
977 
VisitPCRelAddressing(const Instruction * instr)978 void CPUFeaturesAuditor::VisitPCRelAddressing(const Instruction* instr) {
979   RecordInstructionFeaturesScope scope(this);
980   USE(instr);
981 }
982 
VisitSystem(const Instruction * instr)983 void CPUFeaturesAuditor::VisitSystem(const Instruction* instr) {
984   RecordInstructionFeaturesScope scope(this);
985   if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
986     CPUFeatures required;
987     switch (instr->GetInstructionBits()) {
988       case PACIA1716:
989       case PACIB1716:
990       case AUTIA1716:
991       case AUTIB1716:
992       case PACIAZ:
993       case PACIASP:
994       case PACIBZ:
995       case PACIBSP:
996       case AUTIAZ:
997       case AUTIASP:
998       case AUTIBZ:
999       case AUTIBSP:
1000       case XPACLRI:
1001         required.Combine(CPUFeatures::kPAuth);
1002         break;
1003       default:
1004         if (instr->GetImmHint() == ESB) required.Combine(CPUFeatures::kRAS);
1005         break;
1006     }
1007 
1008     // These are all HINT instructions, and behave as NOPs if the corresponding
1009     // features are not implemented, so we record the corresponding features
1010     // only if they are available.
1011     if (available_.Has(required)) scope.Record(required);
1012   }
1013 }
1014 
VisitTestBranch(const Instruction * instr)1015 void CPUFeaturesAuditor::VisitTestBranch(const Instruction* instr) {
1016   RecordInstructionFeaturesScope scope(this);
1017   USE(instr);
1018 }
1019 
VisitUnallocated(const Instruction * instr)1020 void CPUFeaturesAuditor::VisitUnallocated(const Instruction* instr) {
1021   RecordInstructionFeaturesScope scope(this);
1022   USE(instr);
1023 }
1024 
VisitUnconditionalBranch(const Instruction * instr)1025 void CPUFeaturesAuditor::VisitUnconditionalBranch(const Instruction* instr) {
1026   RecordInstructionFeaturesScope scope(this);
1027   USE(instr);
1028 }
1029 
VisitUnconditionalBranchToRegister(const Instruction * instr)1030 void CPUFeaturesAuditor::VisitUnconditionalBranchToRegister(
1031     const Instruction* instr) {
1032   RecordInstructionFeaturesScope scope(this);
1033   switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
1034     case BRAAZ:
1035     case BRABZ:
1036     case BLRAAZ:
1037     case BLRABZ:
1038     case RETAA:
1039     case RETAB:
1040     case BRAA:
1041     case BRAB:
1042     case BLRAA:
1043     case BLRAB:
1044       scope.Record(CPUFeatures::kPAuth);
1045       return;
1046     default:
1047       // No additional features.
1048       return;
1049   }
1050 }
1051 
VisitUnimplemented(const Instruction * instr)1052 void CPUFeaturesAuditor::VisitUnimplemented(const Instruction* instr) {
1053   RecordInstructionFeaturesScope scope(this);
1054   USE(instr);
1055 }
1056 
1057 
1058 }  // namespace aarch64
1059 }  // namespace vixl
1060