20#define DEBUG_TYPE "aarch64-macro-fusion"
24STATISTIC(NumFusedArithmeticBcc,
"Number of arithmetic-Bcc fusions");
25STATISTIC(NumFusedArithmeticCbz,
"Number of arithmetic-Cbz 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");
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");
47 if (FirstMI ==
nullptr)
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:
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:
83 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
92 if (SecondMI.
getOpcode() != AArch64::CBZW &&
103 if (FirstMI ==
nullptr)
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:
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:
147 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
162 return DestFirst == DestSecond;
169 unsigned SecondOpcode = SecondMI.
getOpcode();
170 switch (SecondOpcode) {
172 case AArch64::AESMCrr:
173 case AArch64::AESMCrrTied:
174 if (FirstMI ==
nullptr)
176 if (FirstMI->
getOpcode() != AArch64::AESErr)
178 return SecondOpcode == AArch64::AESMCrrTied ||
181 case AArch64::AESIMCrr:
182 case AArch64::AESIMCrrTied:
183 if (FirstMI ==
nullptr)
185 if (FirstMI->
getOpcode() != AArch64::AESDrr)
187 return SecondOpcode == AArch64::AESIMCrrTied ||
197 if (SecondMI.
getOpcode() != AArch64::EORv16i8)
201 if (FirstMI ==
nullptr)
205 case AArch64::AESErr:
206 case AArch64::AESDrr:
207 case AArch64::PMULLv16i8:
208 case AArch64::PMULLv8i8:
209 case AArch64::PMULLv1i64:
210 case AArch64::PMULLv2i64:
220 if ((FirstMI ==
nullptr || FirstMI->
getOpcode() == AArch64::ADRP) &&
230 case AArch64::STRBBui:
231 case AArch64::STRBui:
232 case AArch64::STRDui:
233 case AArch64::STRHHui:
234 case AArch64::STRHui:
235 case AArch64::STRQui:
236 case AArch64::STRSui:
237 case AArch64::STRWui:
238 case AArch64::STRXui:
239 case AArch64::LDRBBui:
240 case AArch64::LDRBui:
241 case AArch64::LDRDui:
242 case AArch64::LDRHHui:
243 case AArch64::LDRHui:
244 case AArch64::LDRQui:
245 case AArch64::LDRSui:
246 case AArch64::LDRWui:
247 case AArch64::LDRXui:
248 case AArch64::LDRSBWui:
249 case AArch64::LDRSBXui:
250 case AArch64::LDRSHWui:
251 case AArch64::LDRSHXui:
252 case AArch64::LDRSWui:
254 if (FirstMI ==
nullptr)
272 if (SecondMI.
getOpcode() == AArch64::CSELWr) {
274 if (FirstMI ==
nullptr)
279 case AArch64::SUBSWrs:
280 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
281 case AArch64::SUBSWrx:
282 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
283 case AArch64::SUBSWrr:
284 case AArch64::SUBSWri:
290 if (SecondMI.
getOpcode() == AArch64::CSELXr) {
292 if (FirstMI ==
nullptr)
297 case AArch64::SUBSXrs:
298 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
299 case AArch64::SUBSXrx:
300 case AArch64::SUBSXrx64:
301 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
302 case AArch64::SUBSXrr:
303 case AArch64::SUBSXri:
315 case AArch64::FCSELSrrr:
316 case AArch64::FCSELDrrr:
317 case AArch64::FCSELHrrr:
324 if (FirstMI ==
nullptr)
328 case AArch64::FCMPSrr:
329 case AArch64::FCMPDrr:
330 case AArch64::FCMPESrr:
331 case AArch64::FCMPEDrr:
332 case AArch64::FCMPHrr:
333 case AArch64::FCMPEHrr:
343 if ((SecondMI.
getOpcode() == AArch64::CSINCWr &&
346 (SecondMI.
getOpcode() == AArch64::CSINCXr &&
350 if (FirstMI ==
nullptr)
356 case AArch64::SUBSWrs:
357 case AArch64::SUBSXrs:
358 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
359 case AArch64::SUBSWrx:
360 case AArch64::SUBSXrx:
361 case AArch64::SUBSXrx64:
362 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
363 case AArch64::SUBSWri:
364 case AArch64::SUBSWrr:
365 case AArch64::SUBSXri:
366 case AArch64::SUBSXrr:
377 if (AArch64InstrInfo::hasShiftedReg(SecondMI))
382 case AArch64::ADDWrr:
383 case AArch64::ADDXrr:
384 case AArch64::SUBWrr:
385 case AArch64::SUBXrr:
386 case AArch64::ADDWrs:
387 case AArch64::ADDXrs:
388 case AArch64::SUBWrs:
389 case AArch64::SUBXrs:
391 case AArch64::ANDWrr:
392 case AArch64::ANDXrr:
393 case AArch64::BICWrr:
394 case AArch64::BICXrr:
395 case AArch64::EONWrr:
396 case AArch64::EONXrr:
397 case AArch64::EORWrr:
398 case AArch64::EORXrr:
399 case AArch64::ORNWrr:
400 case AArch64::ORNXrr:
401 case AArch64::ORRWrr:
402 case AArch64::ORRXrr:
403 case AArch64::ANDWrs:
404 case AArch64::ANDXrs:
405 case AArch64::BICWrs:
406 case AArch64::BICXrs:
407 case AArch64::EONWrs:
408 case AArch64::EONXrs:
409 case AArch64::EORWrs:
410 case AArch64::EORXrs:
411 case AArch64::ORNWrs:
412 case AArch64::ORNXrs:
413 case AArch64::ORRWrs:
414 case AArch64::ORRXrs:
416 if (FirstMI ==
nullptr)
421 case AArch64::ADDWrr:
422 case AArch64::ADDXrr:
423 case AArch64::ADDSWrr:
424 case AArch64::ADDSXrr:
425 case AArch64::SUBWrr:
426 case AArch64::SUBXrr:
427 case AArch64::SUBSWrr:
428 case AArch64::SUBSXrr:
430 case AArch64::ADDWrs:
431 case AArch64::ADDXrs:
432 case AArch64::ADDSWrs:
433 case AArch64::ADDSXrs:
434 case AArch64::SUBWrs:
435 case AArch64::SUBXrs:
436 case AArch64::SUBSWrs:
437 case AArch64::SUBSXrs:
438 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
443 case AArch64::ADDSWrr:
444 case AArch64::ADDSXrr:
445 case AArch64::SUBSWrr:
446 case AArch64::SUBSXrr:
447 case AArch64::ADDSWrs:
448 case AArch64::ADDSXrs:
449 case AArch64::SUBSWrs:
450 case AArch64::SUBSXrs:
452 if (FirstMI ==
nullptr)
457 case AArch64::ADDWrr:
458 case AArch64::ADDXrr:
459 case AArch64::SUBWrr:
460 case AArch64::SUBXrr:
462 case AArch64::ADDWrs:
463 case AArch64::ADDXrs:
464 case AArch64::SUBWrs:
465 case AArch64::SUBXrs:
466 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
477 bool NeedsSubtract =
false;
481 case AArch64::SUBWri:
482 case AArch64::SUBXri:
483 NeedsSubtract =
true;
485 case AArch64::ADDWri:
486 case AArch64::ADDXri:
499 if (FirstMI ==
nullptr) {
504 case AArch64::SUBWrs:
505 case AArch64::SUBXrs:
506 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
509 case AArch64::SUBWrr:
510 case AArch64::SUBXrr:
516 case AArch64::ADDWrs:
517 case AArch64::ADDXrs:
518 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
521 case AArch64::ADDWrr:
522 case AArch64::ADDXrr:
523 if (!NeedsSubtract) {
539 return Class.hasSubClassEq(
MRI.getRegClass(
Reg));
540 return Class.contains(
Reg.asMCReg());
550 return llvm::any_of(Classes, [&](const TargetRegisterClass *Class) {
551 return isRegInClass(MO, *Class, MRI);
563 return llvm::any_of(Classes, [&](const TargetRegisterClass *Class) {
564 return isRegInClass(MO, *Class, MRI);
572 const bool ReadOrWriteZA =
MI.readsRegister(AArch64::ZA,
TRI) ||
573 MI.definesRegister(AArch64::ZA,
TRI);
576 if (!ReadOrWriteZA &&
578 &AArch64::ZPR3RegClass, &AArch64::ZPR4RegClass}))
582 if (
MI.mayLoad() ||
MI.mayStore())
590 const bool WriteGPR =
596 if (
MI.readsRegister(AArch64::NZCV,
TRI) ||
597 MI.definesRegister(AArch64::NZCV,
TRI))
604 if (ReadGPR && !ReadOrWriteZA)
617 if (FirstMI ==
nullptr)
628 case AArch64::FMAXHrr:
629 case AArch64::FMAXSrr:
630 case AArch64::FMAXDrr:
631 case AArch64::FMINHrr:
632 case AArch64::FMINSrr:
633 case AArch64::FMINDrr:
635 case AArch64::FMAXv4f16:
636 case AArch64::FMAXv8f16:
637 case AArch64::FMAXv2f32:
638 case AArch64::FMAXv4f32:
639 case AArch64::FMAXv2f64:
640 case AArch64::FMINv4f16:
641 case AArch64::FMINv8f16:
642 case AArch64::FMINv2f32:
643 case AArch64::FMINv4f32:
644 case AArch64::FMINv2f64:
657 if (FirstMI ==
nullptr)
681 if (ST.hasFuseAppleSMECompute() &&
683 ++NumFusedAppleSMECompute;
691 if (ST.hasCmpBccFusion() || ST.hasArithmeticBccFusion()) {
692 bool CmpOnly = !ST.hasArithmeticBccFusion();
694 ++NumFusedArithmeticBcc;
699 ++NumFusedArithmeticCbz;
702 if (ST.hasFuseAES() &&
isAESPair(FirstMI, SecondMI)) {
710 if (ST.hasFuseAdrpAdd() &&
isAdrpAddPair(FirstMI, SecondMI)) {
714 if (ST.hasFuseLiterals() && ST.fusesMOVImmPair(FirstMI, SecondMI)) {
722 if (ST.hasFuseCmpCSel() &&
isCmpCSelPair(FirstMI, SecondMI)) {
730 if (ST.hasFuseCmpCSet() &&
isCmpCSetPair(FirstMI, SecondMI)) {
735 ++NumFusedArithmeticLogic;
738 if (ST.hasFuseAddSub2RegAndConstOne() &&
740 ++NumFusedAddSub2RegAndConstOne;
751std::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 isRegInClass(const MachineOperand &RegMO, const TargetRegisterClass &Class, const MachineRegisterInfo &MRI)
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 definesRegInClass(const MachineInstr &MI, const ArrayRef< const TargetRegisterClass * > Classes)
static bool isAdrpAddPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool mayHaveWAWDependency(const MachineInstr &FirstMI, const MachineInstr &SecondMI)
static bool isArithmeticLogicPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isFMinFMax(unsigned Opcode)
static bool readsRegInClass(const MachineInstr &MI, const ArrayRef< const TargetRegisterClass * > Classes)
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)
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
MachineRegisterInfo & MRI
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
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
MachineOperand class - Representation of each machine instruction operand.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
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.
std::unique_ptr< ScheduleDAGMutation > createAArch64MacroFusionDAGMutation()
Note that you have to add: DAG.addMutation(createAArch64MacroFusionDAGMutation()); to AArch64TargetMa...
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