LLVM 24.0.0git
AArch64MacroFusion.cpp
Go to the documentation of this file.
1//===- AArch64MacroFusion.cpp - AArch64 Macro Fusion ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file This file contains the AArch64 implementation of the DAG scheduling
10/// mutation to pair instructions back to back.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AArch64MacroFusion.h"
15#include "AArch64Subtarget.h"
16#include "llvm/ADT/Statistic.h"
19
20#define DEBUG_TYPE "aarch64-macro-fusion"
21
22using namespace llvm;
23
24STATISTIC(NumFusedArithmeticBcc, "Number of arithmetic-Bcc fusions");
25STATISTIC(NumFusedArithmeticCbz, "Number of arithmetic-Cbz fusions");
26STATISTIC(NumFusedAES, "Number of AES fusions");
27STATISTIC(NumFusedCryptoEOR, "Number of crypto-EOR fusions");
28STATISTIC(NumFusedAdrpAdd, "Number of ADRP-ADD fusions");
29STATISTIC(NumFusedLiterals, "Number of literal-generation fusions");
30STATISTIC(NumFusedAddress, "Number of address-generation load/store fusions");
31STATISTIC(NumFusedCmpCSel, "Number of compare-CSEL fusions");
32STATISTIC(NumFusedFCmpFCSel, "Number of FP-compare-FCSEL fusions");
33STATISTIC(NumFusedCmpCSet, "Number of compare-CSET fusions");
34STATISTIC(NumFusedArithmeticLogic, "Number of arithmetic-logic fusions");
35STATISTIC(NumFusedAddSub2RegAndConstOne,
36 "Number of add/sub-two-register-and-constant-one fusions");
37STATISTIC(NumFusedAppleSMECompute, "Number of Apple SME compute fusions");
38STATISTIC(NumFusedFMinFMax, "Number of FMIN-FMAX fusions");
39
40/// CMN, CMP, TST followed by Bcc
41static bool isArithmeticBccPair(const MachineInstr *FirstMI,
42 const MachineInstr &SecondMI, bool CmpOnly) {
43 if (SecondMI.getOpcode() != AArch64::Bcc)
44 return false;
45
46 // Assume the 1st instr to be a wildcard if it is unspecified.
47 if (FirstMI == nullptr)
48 return true;
49
50 // If we're in CmpOnly mode, we only fuse arithmetic instructions that
51 // discard their result.
52 if (CmpOnly && FirstMI->getOperand(0).isReg() &&
53 !(FirstMI->getOperand(0).getReg() == AArch64::XZR ||
54 FirstMI->getOperand(0).getReg() == AArch64::WZR)) {
55 return false;
56 }
57
58 switch (FirstMI->getOpcode()) {
59 case AArch64::ADDSWri:
60 case AArch64::ADDSWrr:
61 case AArch64::ADDSXri:
62 case AArch64::ADDSXrr:
63 case AArch64::ANDSWri:
64 case AArch64::ANDSWrr:
65 case AArch64::ANDSXri:
66 case AArch64::ANDSXrr:
67 case AArch64::SUBSWri:
68 case AArch64::SUBSWrr:
69 case AArch64::SUBSXri:
70 case AArch64::SUBSXrr:
71 case AArch64::BICSWrr:
72 case AArch64::BICSXrr:
73 return true;
74 case AArch64::ADDSWrs:
75 case AArch64::ADDSXrs:
76 case AArch64::ANDSWrs:
77 case AArch64::ANDSXrs:
78 case AArch64::SUBSWrs:
79 case AArch64::SUBSXrs:
80 case AArch64::BICSWrs:
81 case AArch64::BICSXrs:
82 // Shift value can be 0 making these behave like the "rr" variant...
83 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
84 }
85
86 return false;
87}
88
89/// ALU operations followed by CBZ/CBNZ.
90static bool isArithmeticCbzPair(const MachineInstr *FirstMI,
91 const MachineInstr &SecondMI) {
92 if (SecondMI.getOpcode() != AArch64::CBZW &&
93 SecondMI.getOpcode() != AArch64::CBZX &&
94 SecondMI.getOpcode() != AArch64::CBNZW &&
95 SecondMI.getOpcode() != AArch64::CBNZX &&
96 SecondMI.getOpcode() != AArch64::TBZW &&
97 SecondMI.getOpcode() != AArch64::TBZX &&
98 SecondMI.getOpcode() != AArch64::TBNZW &&
99 SecondMI.getOpcode() != AArch64::TBNZX)
100 return false;
101
102 // Assume the 1st instr to be a wildcard if it is unspecified.
103 if (FirstMI == nullptr)
104 return true;
105
106 switch (FirstMI->getOpcode()) {
107 case AArch64::ADDWri:
108 case AArch64::ADDWrr:
109 case AArch64::ADDXri:
110 case AArch64::ADDXrr:
111 case AArch64::ANDWri:
112 case AArch64::ANDWrr:
113 case AArch64::ANDXri:
114 case AArch64::ANDXrr:
115 case AArch64::EORWri:
116 case AArch64::EORWrr:
117 case AArch64::EORXri:
118 case AArch64::EORXrr:
119 case AArch64::ORRWri:
120 case AArch64::ORRWrr:
121 case AArch64::ORRXri:
122 case AArch64::ORRXrr:
123 case AArch64::ORNWrr:
124 case AArch64::ORNXrr:
125 case AArch64::SUBWri:
126 case AArch64::SUBWrr:
127 case AArch64::SUBXri:
128 case AArch64::SUBXrr:
129 case AArch64::BICWrr:
130 case AArch64::BICXrr:
131 return true;
132 case AArch64::ADDWrs:
133 case AArch64::ADDXrs:
134 case AArch64::ANDWrs:
135 case AArch64::ANDXrs:
136 case AArch64::EORWrs:
137 case AArch64::EORXrs:
138 case AArch64::ORNWrs:
139 case AArch64::ORNXrs:
140 case AArch64::ORRWrs:
141 case AArch64::ORRXrs:
142 case AArch64::SUBWrs:
143 case AArch64::SUBXrs:
144 case AArch64::BICWrs:
145 case AArch64::BICXrs:
146 // Shift value can be 0 making these behave like the "rr" variant...
147 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
148 }
149
150 return false;
151}
152
153// True unless the pair provably writes different physical registers. Pre-RA
154// the dests are still virtual, and post-RA it requires a genuine WAW (same dest
155// reg).
156static bool mayHaveWAWDependency(const MachineInstr &FirstMI,
157 const MachineInstr &SecondMI) {
158 Register DestFirst = FirstMI.getOperand(0).getReg();
159 Register DestSecond = SecondMI.getOperand(0).getReg();
160 if (!DestFirst.isPhysical() || !DestSecond.isPhysical())
161 return true;
162 return DestFirst == DestSecond;
163}
164
165/// AES crypto encoding or decoding.
166static bool isAESPair(const MachineInstr *FirstMI,
167 const MachineInstr &SecondMI) {
168 // Assume the 1st instr to be a wildcard if it is unspecified.
169 unsigned SecondOpcode = SecondMI.getOpcode();
170 switch (SecondOpcode) {
171 // AES encode.
172 case AArch64::AESMCrr:
173 case AArch64::AESMCrrTied:
174 if (FirstMI == nullptr)
175 return true;
176 if (FirstMI->getOpcode() != AArch64::AESErr)
177 return false;
178 return SecondOpcode == AArch64::AESMCrrTied ||
179 mayHaveWAWDependency(*FirstMI, SecondMI);
180 // AES decode.
181 case AArch64::AESIMCrr:
182 case AArch64::AESIMCrrTied:
183 if (FirstMI == nullptr)
184 return true;
185 if (FirstMI->getOpcode() != AArch64::AESDrr)
186 return false;
187 return SecondOpcode == AArch64::AESIMCrrTied ||
188 mayHaveWAWDependency(*FirstMI, SecondMI);
189 }
190
191 return false;
192}
193
194/// AESE/AESD/PMULL + EOR.
195static bool isCryptoEORPair(const MachineInstr *FirstMI,
196 const MachineInstr &SecondMI) {
197 if (SecondMI.getOpcode() != AArch64::EORv16i8)
198 return false;
199
200 // Assume the 1st instr to be a wildcard if it is unspecified.
201 if (FirstMI == nullptr)
202 return true;
203
204 switch (FirstMI->getOpcode()) {
205 case AArch64::AESErr:
206 case AArch64::AESDrr:
207 case AArch64::PMULLv16i8:
208 case AArch64::PMULLv8i8:
209 case AArch64::PMULLv1i64:
210 case AArch64::PMULLv2i64:
211 return true;
212 }
213
214 return false;
215}
216
217static bool isAdrpAddPair(const MachineInstr *FirstMI,
218 const MachineInstr &SecondMI) {
219 // Assume the 1st instr to be a wildcard if it is unspecified.
220 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::ADRP) &&
221 SecondMI.getOpcode() == AArch64::ADDXri)
222 return true;
223 return false;
224}
225
226/// Literal generation.
227static bool isLiteralsPair(const MachineInstr *FirstMI,
228 const MachineInstr &SecondMI) {
229 // Assume the 1st instr to be a wildcard if it is unspecified.
230 // 32 bit immediate.
231 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&
232 (SecondMI.getOpcode() == AArch64::MOVKWi &&
233 SecondMI.getOperand(3).getImm() == 16))
234 return true;
235
236 // Lower half of 64 bit immediate.
237 if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&
238 (SecondMI.getOpcode() == AArch64::MOVKXi &&
239 SecondMI.getOperand(3).getImm() == 16))
240 return true;
241
242 // Upper half of 64 bit immediate.
243 if ((FirstMI == nullptr ||
244 (FirstMI->getOpcode() == AArch64::MOVKXi &&
245 FirstMI->getOperand(3).getImm() == 32)) &&
246 (SecondMI.getOpcode() == AArch64::MOVKXi &&
247 SecondMI.getOperand(3).getImm() == 48))
248 return true;
249
250 return false;
251}
252
253/// Fuse address generation and loads or stores.
254static bool isAddressLdStPair(const MachineInstr *FirstMI,
255 const MachineInstr &SecondMI) {
256 switch (SecondMI.getOpcode()) {
257 case AArch64::STRBBui:
258 case AArch64::STRBui:
259 case AArch64::STRDui:
260 case AArch64::STRHHui:
261 case AArch64::STRHui:
262 case AArch64::STRQui:
263 case AArch64::STRSui:
264 case AArch64::STRWui:
265 case AArch64::STRXui:
266 case AArch64::LDRBBui:
267 case AArch64::LDRBui:
268 case AArch64::LDRDui:
269 case AArch64::LDRHHui:
270 case AArch64::LDRHui:
271 case AArch64::LDRQui:
272 case AArch64::LDRSui:
273 case AArch64::LDRWui:
274 case AArch64::LDRXui:
275 case AArch64::LDRSBWui:
276 case AArch64::LDRSBXui:
277 case AArch64::LDRSHWui:
278 case AArch64::LDRSHXui:
279 case AArch64::LDRSWui:
280 // Assume the 1st instr to be a wildcard if it is unspecified.
281 if (FirstMI == nullptr)
282 return true;
283
284 switch (FirstMI->getOpcode()) {
285 case AArch64::ADR:
286 return SecondMI.getOperand(2).getImm() == 0;
287 case AArch64::ADRP:
288 return true;
289 }
290 }
291
292 return false;
293}
294
295/// Compare and conditional select.
296static bool isCmpCSelPair(const MachineInstr *FirstMI,
297 const MachineInstr &SecondMI) {
298 // 32 bits
299 if (SecondMI.getOpcode() == AArch64::CSELWr) {
300 // Assume the 1st instr to be a wildcard if it is unspecified.
301 if (FirstMI == nullptr)
302 return true;
303
304 if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr))
305 switch (FirstMI->getOpcode()) {
306 case AArch64::SUBSWrs:
307 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
308 case AArch64::SUBSWrx:
309 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
310 case AArch64::SUBSWrr:
311 case AArch64::SUBSWri:
312 return true;
313 }
314 }
315
316 // 64 bits
317 if (SecondMI.getOpcode() == AArch64::CSELXr) {
318 // Assume the 1st instr to be a wildcard if it is unspecified.
319 if (FirstMI == nullptr)
320 return true;
321
322 if (FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))
323 switch (FirstMI->getOpcode()) {
324 case AArch64::SUBSXrs:
325 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
326 case AArch64::SUBSXrx:
327 case AArch64::SUBSXrx64:
328 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
329 case AArch64::SUBSXrr:
330 case AArch64::SUBSXri:
331 return true;
332 }
333 }
334
335 return false;
336}
337
338/// Floating-point compare and floating-point conditional select.
339static bool isFCmpFCSelPair(const MachineInstr *FirstMI,
340 const MachineInstr &SecondMI) {
341 switch (SecondMI.getOpcode()) {
342 case AArch64::FCSELSrrr:
343 case AArch64::FCSELDrrr:
344 case AArch64::FCSELHrrr:
345 break;
346 default:
347 return false;
348 }
349
350 // Assume the 1st instr to be a wildcard if it is unspecified.
351 if (FirstMI == nullptr)
352 return true;
353
354 switch (FirstMI->getOpcode()) {
355 case AArch64::FCMPSrr:
356 case AArch64::FCMPDrr:
357 case AArch64::FCMPESrr:
358 case AArch64::FCMPEDrr:
359 case AArch64::FCMPHrr:
360 case AArch64::FCMPEHrr:
361 return true;
362 default:
363 return false;
364 }
365}
366
367/// Compare and cset.
368static bool isCmpCSetPair(const MachineInstr *FirstMI,
369 const MachineInstr &SecondMI) {
370 if ((SecondMI.getOpcode() == AArch64::CSINCWr &&
371 SecondMI.getOperand(1).getReg() == AArch64::WZR &&
372 SecondMI.getOperand(2).getReg() == AArch64::WZR) ||
373 (SecondMI.getOpcode() == AArch64::CSINCXr &&
374 SecondMI.getOperand(1).getReg() == AArch64::XZR &&
375 SecondMI.getOperand(2).getReg() == AArch64::XZR)) {
376 // Assume the 1st instr to be a wildcard if it is unspecified.
377 if (FirstMI == nullptr)
378 return true;
379
380 if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
381 FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))
382 switch (FirstMI->getOpcode()) {
383 case AArch64::SUBSWrs:
384 case AArch64::SUBSXrs:
385 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
386 case AArch64::SUBSWrx:
387 case AArch64::SUBSXrx:
388 case AArch64::SUBSXrx64:
389 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
390 case AArch64::SUBSWri:
391 case AArch64::SUBSWrr:
392 case AArch64::SUBSXri:
393 case AArch64::SUBSXrr:
394 return true;
395 }
396 }
397
398 return false;
399}
400
401// Arithmetic and logic.
402static bool isArithmeticLogicPair(const MachineInstr *FirstMI,
403 const MachineInstr &SecondMI) {
404 if (AArch64InstrInfo::hasShiftedReg(SecondMI))
405 return false;
406
407 switch (SecondMI.getOpcode()) {
408 // Arithmetic
409 case AArch64::ADDWrr:
410 case AArch64::ADDXrr:
411 case AArch64::SUBWrr:
412 case AArch64::SUBXrr:
413 case AArch64::ADDWrs:
414 case AArch64::ADDXrs:
415 case AArch64::SUBWrs:
416 case AArch64::SUBXrs:
417 // Logic
418 case AArch64::ANDWrr:
419 case AArch64::ANDXrr:
420 case AArch64::BICWrr:
421 case AArch64::BICXrr:
422 case AArch64::EONWrr:
423 case AArch64::EONXrr:
424 case AArch64::EORWrr:
425 case AArch64::EORXrr:
426 case AArch64::ORNWrr:
427 case AArch64::ORNXrr:
428 case AArch64::ORRWrr:
429 case AArch64::ORRXrr:
430 case AArch64::ANDWrs:
431 case AArch64::ANDXrs:
432 case AArch64::BICWrs:
433 case AArch64::BICXrs:
434 case AArch64::EONWrs:
435 case AArch64::EONXrs:
436 case AArch64::EORWrs:
437 case AArch64::EORXrs:
438 case AArch64::ORNWrs:
439 case AArch64::ORNXrs:
440 case AArch64::ORRWrs:
441 case AArch64::ORRXrs:
442 // Assume the 1st instr to be a wildcard if it is unspecified.
443 if (FirstMI == nullptr)
444 return true;
445
446 // Arithmetic
447 switch (FirstMI->getOpcode()) {
448 case AArch64::ADDWrr:
449 case AArch64::ADDXrr:
450 case AArch64::ADDSWrr:
451 case AArch64::ADDSXrr:
452 case AArch64::SUBWrr:
453 case AArch64::SUBXrr:
454 case AArch64::SUBSWrr:
455 case AArch64::SUBSXrr:
456 return true;
457 case AArch64::ADDWrs:
458 case AArch64::ADDXrs:
459 case AArch64::ADDSWrs:
460 case AArch64::ADDSXrs:
461 case AArch64::SUBWrs:
462 case AArch64::SUBXrs:
463 case AArch64::SUBSWrs:
464 case AArch64::SUBSXrs:
465 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
466 }
467 break;
468
469 // Arithmetic, setting flags.
470 case AArch64::ADDSWrr:
471 case AArch64::ADDSXrr:
472 case AArch64::SUBSWrr:
473 case AArch64::SUBSXrr:
474 case AArch64::ADDSWrs:
475 case AArch64::ADDSXrs:
476 case AArch64::SUBSWrs:
477 case AArch64::SUBSXrs:
478 // Assume the 1st instr to be a wildcard if it is unspecified.
479 if (FirstMI == nullptr)
480 return true;
481
482 // Arithmetic, not setting flags.
483 switch (FirstMI->getOpcode()) {
484 case AArch64::ADDWrr:
485 case AArch64::ADDXrr:
486 case AArch64::SUBWrr:
487 case AArch64::SUBXrr:
488 return true;
489 case AArch64::ADDWrs:
490 case AArch64::ADDXrs:
491 case AArch64::SUBWrs:
492 case AArch64::SUBXrs:
493 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
494 }
495 break;
496 }
497
498 return false;
499}
500
501// "(A + B) + 1" or "(A - B) - 1"
502static bool isAddSub2RegAndConstOnePair(const MachineInstr *FirstMI,
503 const MachineInstr &SecondMI) {
504 bool NeedsSubtract = false;
505
506 // The 2nd instr must be an add-immediate or subtract-immediate.
507 switch (SecondMI.getOpcode()) {
508 case AArch64::SUBWri:
509 case AArch64::SUBXri:
510 NeedsSubtract = true;
511 [[fallthrough]];
512 case AArch64::ADDWri:
513 case AArch64::ADDXri:
514 break;
515
516 default:
517 return false;
518 }
519
520 // The immediate in the 2nd instr must be "1".
521 if (!SecondMI.getOperand(2).isImm() || SecondMI.getOperand(2).getImm() != 1) {
522 return false;
523 }
524
525 // Assume the 1st instr to be a wildcard if it is unspecified.
526 if (FirstMI == nullptr) {
527 return true;
528 }
529
530 switch (FirstMI->getOpcode()) {
531 case AArch64::SUBWrs:
532 case AArch64::SUBXrs:
533 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
534 return false;
535 [[fallthrough]];
536 case AArch64::SUBWrr:
537 case AArch64::SUBXrr:
538 if (NeedsSubtract) {
539 return true;
540 }
541 break;
542
543 case AArch64::ADDWrs:
544 case AArch64::ADDXrs:
545 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
546 return false;
547 [[fallthrough]];
548 case AArch64::ADDWrr:
549 case AArch64::ADDXrr:
550 if (!NeedsSubtract) {
551 return true;
552 }
553 break;
554 }
555
556 return false;
557}
558
560 const TargetRegisterInfo *TRI,
561 const TargetRegisterClass &Class) {
562 return llvm::any_of(Class, [&MI, TRI](MCPhysReg Reg) {
563 return MI.definesRegister(Reg, TRI);
564 });
565}
566
567static bool readsRegInClass(const MachineInstr &MI,
568 const TargetRegisterInfo *TRI,
569 const TargetRegisterClass &Class) {
570 return llvm::any_of(
571 Class, [&MI, TRI](MCPhysReg Reg) { return MI.readsRegister(Reg, TRI); });
572}
573
575 const TargetInstrInfo &TII,
576 const TargetRegisterInfo *TRI) {
577 const bool ReadOrWriteZA = MI.readsRegister(AArch64::ZA, TRI) ||
578 MI.definesRegister(AArch64::ZA, TRI);
579
580 // (read/write ZA or read/write Z)
581 if (!ReadOrWriteZA && !definesRegInClass(MI, TRI, AArch64::ZPRRegClass))
582 return false;
583
584 // (NOT load/store)
585 if (MI.mayLoad() || MI.mayStore())
586 return false;
587
588 // (NOT write P)
589 if (definesRegInClass(MI, TRI, AArch64::PPRRegClass))
590 return false;
591
592 // (NOT write GPR)
593 const bool WriteGPR = definesRegInClass(MI, TRI, AArch64::GPR32RegClass) ||
594 definesRegInClass(MI, TRI, AArch64::GPR64RegClass);
595 if (WriteGPR)
596 return false;
597
598 // (NOT read/write NZCV)
599 if (MI.readsRegister(AArch64::NZCV, TRI) ||
600 MI.definesRegister(AArch64::NZCV, TRI))
601 return false;
602
603 const bool ReadGPR = readsRegInClass(MI, TRI, AArch64::GPR32RegClass) &&
604 readsRegInClass(MI, TRI, AArch64::GPR64RegClass);
605
606 // ( (NOT read GPR) or read/write ZA )
607 if (ReadGPR && !ReadOrWriteZA)
608 return false;
609
610 return true;
611}
612
613static bool isAppleSMEComputePair(const MachineInstr *FirstMI,
614 const MachineInstr &SecondMI,
615 const TargetInstrInfo &TII,
616 const TargetRegisterInfo *TRI) {
617 if (!isFusableAppleSMEComputeOp(SecondMI, TII, TRI))
618 return false;
619 // Assume the 1st instr to be a wildcard if it is unspecified.
620 if (FirstMI == nullptr)
621 return true;
622 if (isFusableAppleSMEComputeOp(*FirstMI, TII, TRI))
623 return true;
624 return false;
625}
626
627// Floating-point minimum or maximum, scalar (H/S/D) or vector (Vd).
628static bool isFMinFMax(unsigned Opcode) {
629 switch (Opcode) {
630 // Scalar.
631 case AArch64::FMAXHrr:
632 case AArch64::FMAXSrr:
633 case AArch64::FMAXDrr:
634 case AArch64::FMINHrr:
635 case AArch64::FMINSrr:
636 case AArch64::FMINDrr:
637 // Vector.
638 case AArch64::FMAXv4f16:
639 case AArch64::FMAXv8f16:
640 case AArch64::FMAXv2f32:
641 case AArch64::FMAXv4f32:
642 case AArch64::FMAXv2f64:
643 case AArch64::FMINv4f16:
644 case AArch64::FMINv8f16:
645 case AArch64::FMINv2f32:
646 case AArch64::FMINv4f32:
647 case AArch64::FMINv2f64:
648 return true;
649 }
650 return false;
651}
652
653// FMIN + FMAX.
654static bool isFMinFMaxPair(const MachineInstr *FirstMI,
655 const MachineInstr &SecondMI) {
656 if (!isFMinFMax(SecondMI.getOpcode()))
657 return false;
658
659 // Assume the 1st instr to be a wildcard if it is unspecified.
660 if (FirstMI == nullptr)
661 return true;
662
663 if (!isFMinFMax(FirstMI->getOpcode()))
664 return false;
665
666 return mayHaveWAWDependency(*FirstMI, SecondMI);
667}
668
669/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
670/// together. Given SecondMI, when FirstMI is unspecified, then check if
671/// SecondMI may be part of a fused pair at all.
673 const TargetSubtargetInfo &TSI,
674 const MachineInstr *FirstMI,
675 const MachineInstr &SecondMI,
676 const SDep *Dep) {
677 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
679
680 // All checking functions assume that the 1st instr is a wildcard if it is
681 // unspecified.
682
683 // FuseAppleSMECompute does not require a specific dependency kind
684 if (ST.hasFuseAppleSMECompute() &&
685 isAppleSMEComputePair(FirstMI, SecondMI, TII, TRI)) {
686 ++NumFusedAppleSMECompute;
687 return true;
688 }
689
690 // All the other fusions require RAW dependency
691 if (isNonDataDep(Dep))
692 return false;
693
694 if (ST.hasCmpBccFusion() || ST.hasArithmeticBccFusion()) {
695 bool CmpOnly = !ST.hasArithmeticBccFusion();
696 if (isArithmeticBccPair(FirstMI, SecondMI, CmpOnly)) {
697 ++NumFusedArithmeticBcc;
698 return true;
699 }
700 }
701 if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI)) {
702 ++NumFusedArithmeticCbz;
703 return true;
704 }
705 if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI)) {
706 ++NumFusedAES;
707 return true;
708 }
709 if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI)) {
710 ++NumFusedCryptoEOR;
711 return true;
712 }
713 if (ST.hasFuseAdrpAdd() && isAdrpAddPair(FirstMI, SecondMI)) {
714 ++NumFusedAdrpAdd;
715 return true;
716 }
717 if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI)) {
718 ++NumFusedLiterals;
719 return true;
720 }
721 if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI)) {
722 ++NumFusedAddress;
723 return true;
724 }
725 if (ST.hasFuseCmpCSel() && isCmpCSelPair(FirstMI, SecondMI)) {
726 ++NumFusedCmpCSel;
727 return true;
728 }
729 if (ST.hasFuseFCmpFCSel() && isFCmpFCSelPair(FirstMI, SecondMI)) {
730 ++NumFusedFCmpFCSel;
731 return true;
732 }
733 if (ST.hasFuseCmpCSet() && isCmpCSetPair(FirstMI, SecondMI)) {
734 ++NumFusedCmpCSet;
735 return true;
736 }
737 if (ST.hasFuseArithmeticLogic() && isArithmeticLogicPair(FirstMI, SecondMI)) {
738 ++NumFusedArithmeticLogic;
739 return true;
740 }
741 if (ST.hasFuseAddSub2RegAndConstOne() &&
742 isAddSub2RegAndConstOnePair(FirstMI, SecondMI)) {
743 ++NumFusedAddSub2RegAndConstOne;
744 return true;
745 }
746 if (ST.hasFuseFMinFMax() && isFMinFMaxPair(FirstMI, SecondMI)) {
747 ++NumFusedFMinFMax;
748 return true;
749 }
750
751 return false;
752}
753
754std::unique_ptr<ScheduleDAGMutation>
static bool isFusableAppleSMEComputeOp(const MachineInstr &MI, const TargetInstrInfo &TII, const TargetRegisterInfo *TRI)
static bool isFCmpFCSelPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Floating-point compare and floating-point conditional select.
static bool isFMinFMaxPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isAddSub2RegAndConstOnePair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isCmpCSelPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Compare and conditional select.
static bool isArithmeticBccPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI, bool CmpOnly)
CMN, CMP, TST followed by Bcc.
static bool isAddressLdStPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Fuse address generation and loads or stores.
static bool isArithmeticCbzPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
ALU operations followed by CBZ/CBNZ.
static bool isAESPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
AES crypto encoding or decoding.
static bool isCmpCSetPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Compare and cset.
static bool isAdrpAddPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool readsRegInClass(const MachineInstr &MI, const TargetRegisterInfo *TRI, const TargetRegisterClass &Class)
static bool mayHaveWAWDependency(const MachineInstr &FirstMI, const MachineInstr &SecondMI)
static bool definesRegInClass(const MachineInstr &MI, const TargetRegisterInfo *TRI, const TargetRegisterClass &Class)
static bool isArithmeticLogicPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isFMinFMax(unsigned Opcode)
static bool isCryptoEORPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
AESE/AESD/PMULL + EOR.
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *Dep)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
static bool isAppleSMEComputePair(const MachineInstr *FirstMI, const MachineInstr &SecondMI, const TargetInstrInfo &TII, const TargetRegisterInfo *TRI)
static bool isLiteralsPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Literal generation.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Register Reg
Register const TargetRegisterInfo * TRI
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool definesRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr fully defines the specified register.
const MachineOperand & getOperand(unsigned i) const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
Scheduling dependency.
Definition ScheduleDAG.h:52
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::unique_ptr< ScheduleDAGMutation > createMacroFusionDAGMutation(ArrayRef< MacroFusionPredTy > Predicates, bool BranchOnly=false)
Create a DAG scheduling mutation to pair instructions back to back for instructions that benefit acco...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
std::unique_ptr< ScheduleDAGMutation > createAArch64MacroFusionDAGMutation()
Note that you have to add: DAG.addMutation(createAArch64MacroFusionDAGMutation()); to AArch64TargetMa...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *Dep)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
LLVM_ABI bool isNonDataDep(const SDep *Dep)
Returns true if Dep is a non-null non-data dependency.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58