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