1 //===- AArch64MacroFusion.cpp - AArch64 Macro Fusion ----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 /// \file This file contains the AArch64 implementation of the DAG scheduling 11 /// mutation to pair instructions back to back. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "AArch64MacroFusion.h" 16 #include "AArch64Subtarget.h" 17 #include "llvm/CodeGen/MacroFusion.h" 18 #include "llvm/CodeGen/TargetInstrInfo.h" 19 20 using namespace llvm; 21 22 namespace { 23 24 /// \brief Check if the instr pair, FirstMI and SecondMI, should be fused 25 /// together. Given SecondMI, when FirstMI is unspecified, then check if 26 /// SecondMI may be part of a fused pair at all. 27 static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, 28 const TargetSubtargetInfo &TSI, 29 const MachineInstr *FirstMI, 30 const MachineInstr &SecondMI) { 31 const AArch64InstrInfo &II = static_cast<const AArch64InstrInfo&>(TII); 32 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI); 33 34 // Assume wildcards for unspecified instrs. 35 unsigned FirstOpcode = 36 FirstMI ? FirstMI->getOpcode() 37 : static_cast<unsigned>(AArch64::INSTRUCTION_LIST_END); 38 unsigned SecondOpcode = SecondMI.getOpcode(); 39 40 if (ST.hasArithmeticBccFusion()) 41 // Fuse CMN, CMP, TST followed by Bcc. 42 if (SecondOpcode == AArch64::Bcc) 43 switch (FirstOpcode) { 44 default: 45 return false; 46 case AArch64::ADDSWri: 47 case AArch64::ADDSWrr: 48 case AArch64::ADDSXri: 49 case AArch64::ADDSXrr: 50 case AArch64::ANDSWri: 51 case AArch64::ANDSWrr: 52 case AArch64::ANDSXri: 53 case AArch64::ANDSXrr: 54 case AArch64::SUBSWri: 55 case AArch64::SUBSWrr: 56 case AArch64::SUBSXri: 57 case AArch64::SUBSXrr: 58 case AArch64::BICSWrr: 59 case AArch64::BICSXrr: 60 return true; 61 case AArch64::ADDSWrs: 62 case AArch64::ADDSXrs: 63 case AArch64::ANDSWrs: 64 case AArch64::ANDSXrs: 65 case AArch64::SUBSWrs: 66 case AArch64::SUBSXrs: 67 case AArch64::BICSWrs: 68 case AArch64::BICSXrs: 69 // Shift value can be 0 making these behave like the "rr" variant... 70 return !II.hasShiftedReg(*FirstMI); 71 case AArch64::INSTRUCTION_LIST_END: 72 return true; 73 } 74 75 if (ST.hasArithmeticCbzFusion()) 76 // Fuse ALU operations followed by CBZ/CBNZ. 77 if (SecondOpcode == AArch64::CBNZW || SecondOpcode == AArch64::CBNZX || 78 SecondOpcode == AArch64::CBZW || SecondOpcode == AArch64::CBZX) 79 switch (FirstOpcode) { 80 default: 81 return false; 82 case AArch64::ADDWri: 83 case AArch64::ADDWrr: 84 case AArch64::ADDXri: 85 case AArch64::ADDXrr: 86 case AArch64::ANDWri: 87 case AArch64::ANDWrr: 88 case AArch64::ANDXri: 89 case AArch64::ANDXrr: 90 case AArch64::EORWri: 91 case AArch64::EORWrr: 92 case AArch64::EORXri: 93 case AArch64::EORXrr: 94 case AArch64::ORRWri: 95 case AArch64::ORRWrr: 96 case AArch64::ORRXri: 97 case AArch64::ORRXrr: 98 case AArch64::SUBWri: 99 case AArch64::SUBWrr: 100 case AArch64::SUBXri: 101 case AArch64::SUBXrr: 102 return true; 103 case AArch64::ADDWrs: 104 case AArch64::ADDXrs: 105 case AArch64::ANDWrs: 106 case AArch64::ANDXrs: 107 case AArch64::SUBWrs: 108 case AArch64::SUBXrs: 109 case AArch64::BICWrs: 110 case AArch64::BICXrs: 111 // Shift value can be 0 making these behave like the "rr" variant... 112 return !II.hasShiftedReg(*FirstMI); 113 case AArch64::INSTRUCTION_LIST_END: 114 return true; 115 } 116 117 if (ST.hasFuseAES()) 118 // Fuse AES crypto operations. 119 switch(SecondOpcode) { 120 // AES encode. 121 case AArch64::AESMCrr: 122 case AArch64::AESMCrrTied: 123 return FirstOpcode == AArch64::AESErr || 124 FirstOpcode == AArch64::INSTRUCTION_LIST_END; 125 // AES decode. 126 case AArch64::AESIMCrr: 127 case AArch64::AESIMCrrTied: 128 return FirstOpcode == AArch64::AESDrr || 129 FirstOpcode == AArch64::INSTRUCTION_LIST_END; 130 } 131 132 if (ST.hasFuseLiterals()) 133 // Fuse literal generation operations. 134 switch (SecondOpcode) { 135 // PC relative address. 136 case AArch64::ADDXri: 137 return FirstOpcode == AArch64::ADRP || 138 FirstOpcode == AArch64::INSTRUCTION_LIST_END; 139 // 32 bit immediate. 140 case AArch64::MOVKWi: 141 return (FirstOpcode == AArch64::MOVZWi && 142 SecondMI.getOperand(3).getImm() == 16) || 143 FirstOpcode == AArch64::INSTRUCTION_LIST_END; 144 // Lower and upper half of 64 bit immediate. 145 case AArch64::MOVKXi: 146 return FirstOpcode == AArch64::INSTRUCTION_LIST_END || 147 (FirstOpcode == AArch64::MOVZXi && 148 SecondMI.getOperand(3).getImm() == 16) || 149 (FirstOpcode == AArch64::MOVKXi && 150 FirstMI->getOperand(3).getImm() == 32 && 151 SecondMI.getOperand(3).getImm() == 48); 152 } 153 154 return false; 155 } 156 157 } // end namespace 158 159 160 namespace llvm { 161 162 std::unique_ptr<ScheduleDAGMutation> createAArch64MacroFusionDAGMutation () { 163 return createMacroFusionDAGMutation(shouldScheduleAdjacent); 164 } 165 166 } // end namespace llvm 167