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