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 "AArch64Subtarget.h" 16 #include "llvm/CodeGen/MacroFusion.h" 17 #include "llvm/CodeGen/TargetInstrInfo.h" 18 19 using namespace llvm; 20 21 namespace { 22 23 // Fuse CMN, CMP, TST followed by Bcc. 24 static bool isArithmeticBccPair(const MachineInstr *FirstMI, 25 const MachineInstr &SecondMI) { 26 if (SecondMI.getOpcode() == AArch64::Bcc) { 27 // Assume the 1st instr to be a wildcard if it is unspecified. 28 if (!FirstMI) 29 return true; 30 31 switch (FirstMI->getOpcode()) { 32 case AArch64::ADDSWri: 33 case AArch64::ADDSWrr: 34 case AArch64::ADDSXri: 35 case AArch64::ADDSXrr: 36 case AArch64::ANDSWri: 37 case AArch64::ANDSWrr: 38 case AArch64::ANDSXri: 39 case AArch64::ANDSXrr: 40 case AArch64::SUBSWri: 41 case AArch64::SUBSWrr: 42 case AArch64::SUBSXri: 43 case AArch64::SUBSXrr: 44 case AArch64::BICSWrr: 45 case AArch64::BICSXrr: 46 return true; 47 case AArch64::ADDSWrs: 48 case AArch64::ADDSXrs: 49 case AArch64::ANDSWrs: 50 case AArch64::ANDSXrs: 51 case AArch64::SUBSWrs: 52 case AArch64::SUBSXrs: 53 case AArch64::BICSWrs: 54 case AArch64::BICSXrs: 55 // Shift value can be 0 making these behave like the "rr" variant... 56 return (!AArch64InstrInfo::hasShiftedReg(*FirstMI)); 57 } 58 } 59 return false; 60 } 61 62 // Fuse ALU operations followed by CBZ/CBNZ. 63 static bool isArithmeticCbzPair(const MachineInstr *FirstMI, 64 const MachineInstr &SecondMI) { 65 unsigned SecondOpcode = SecondMI.getOpcode(); 66 67 if (SecondOpcode == AArch64::CBNZW || SecondOpcode == AArch64::CBNZX || 68 SecondOpcode == AArch64::CBZW || SecondOpcode == AArch64::CBZX) { 69 // Assume the 1st instr to be a wildcard if it is unspecified. 70 if (!FirstMI) 71 return true; 72 73 switch (FirstMI->getOpcode()) { 74 case AArch64::ADDWri: 75 case AArch64::ADDWrr: 76 case AArch64::ADDXri: 77 case AArch64::ADDXrr: 78 case AArch64::ANDWri: 79 case AArch64::ANDWrr: 80 case AArch64::ANDXri: 81 case AArch64::ANDXrr: 82 case AArch64::EORWri: 83 case AArch64::EORWrr: 84 case AArch64::EORXri: 85 case AArch64::EORXrr: 86 case AArch64::ORRWri: 87 case AArch64::ORRWrr: 88 case AArch64::ORRXri: 89 case AArch64::ORRXrr: 90 case AArch64::SUBWri: 91 case AArch64::SUBWrr: 92 case AArch64::SUBXri: 93 case AArch64::SUBXrr: 94 return true; 95 case AArch64::ADDWrs: 96 case AArch64::ADDXrs: 97 case AArch64::ANDWrs: 98 case AArch64::ANDXrs: 99 case AArch64::SUBWrs: 100 case AArch64::SUBXrs: 101 case AArch64::BICWrs: 102 case AArch64::BICXrs: 103 // Shift value can be 0 making these behave like the "rr" variant... 104 return (!AArch64InstrInfo::hasShiftedReg(*FirstMI)); 105 } 106 } 107 return false; 108 } 109 110 // Fuse AES crypto encoding or decoding. 111 static bool isAESPair(const MachineInstr *FirstMI, 112 const MachineInstr &SecondMI) { 113 // Assume the 1st instr to be a wildcard if it is unspecified. 114 unsigned FirstOpcode = 115 FirstMI ? FirstMI->getOpcode() 116 : static_cast<unsigned>(AArch64::INSTRUCTION_LIST_END); 117 unsigned SecondOpcode = SecondMI.getOpcode(); 118 119 // AES encode. 120 if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END || 121 FirstOpcode == AArch64::AESErr) && 122 (SecondOpcode == AArch64::AESMCrr || 123 SecondOpcode == AArch64::AESMCrrTied)) 124 return true; 125 // AES decode. 126 else if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END || 127 FirstOpcode == AArch64::AESDrr) && 128 (SecondOpcode == AArch64::AESIMCrr || 129 SecondOpcode == AArch64::AESIMCrrTied)) 130 return true; 131 132 return false; 133 } 134 135 // Fuse literal generation. 136 static bool isLiteralsPair(const MachineInstr *FirstMI, 137 const MachineInstr &SecondMI) { 138 // Assume the 1st instr to be a wildcard if it is unspecified. 139 unsigned FirstOpcode = 140 FirstMI ? FirstMI->getOpcode() 141 : static_cast<unsigned>(AArch64::INSTRUCTION_LIST_END); 142 unsigned SecondOpcode = SecondMI.getOpcode(); 143 144 // PC relative address. 145 if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END || 146 FirstOpcode == AArch64::ADRP) && 147 SecondOpcode == AArch64::ADDXri) 148 return true; 149 // 32 bit immediate. 150 else if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END || 151 FirstOpcode == AArch64::MOVZWi) && 152 (SecondOpcode == AArch64::MOVKWi && 153 SecondMI.getOperand(3).getImm() == 16)) 154 return true; 155 // Lower half of 64 bit immediate. 156 else if((FirstOpcode == AArch64::INSTRUCTION_LIST_END || 157 FirstOpcode == AArch64::MOVZXi) && 158 (SecondOpcode == AArch64::MOVKXi && 159 SecondMI.getOperand(3).getImm() == 16)) 160 return true; 161 // Upper half of 64 bit immediate. 162 else if ((FirstOpcode == AArch64::INSTRUCTION_LIST_END || 163 (FirstOpcode == AArch64::MOVKXi && 164 FirstMI->getOperand(3).getImm() == 32)) && 165 (SecondOpcode == AArch64::MOVKXi && 166 SecondMI.getOperand(3).getImm() == 48)) 167 return true; 168 169 return false; 170 } 171 172 // Fuse address generation and loads or stores. 173 static bool isAddressLdStPair(const MachineInstr *FirstMI, 174 const MachineInstr &SecondMI) { 175 unsigned SecondOpcode = SecondMI.getOpcode(); 176 177 switch (SecondOpcode) { 178 case AArch64::STRBBui: 179 case AArch64::STRBui: 180 case AArch64::STRDui: 181 case AArch64::STRHHui: 182 case AArch64::STRHui: 183 case AArch64::STRQui: 184 case AArch64::STRSui: 185 case AArch64::STRWui: 186 case AArch64::STRXui: 187 case AArch64::LDRBBui: 188 case AArch64::LDRBui: 189 case AArch64::LDRDui: 190 case AArch64::LDRHHui: 191 case AArch64::LDRHui: 192 case AArch64::LDRQui: 193 case AArch64::LDRSui: 194 case AArch64::LDRWui: 195 case AArch64::LDRXui: 196 case AArch64::LDRSBWui: 197 case AArch64::LDRSBXui: 198 case AArch64::LDRSHWui: 199 case AArch64::LDRSHXui: 200 case AArch64::LDRSWui: 201 // Assume the 1st instr to be a wildcard if it is unspecified. 202 if (!FirstMI) 203 return true; 204 205 switch (FirstMI->getOpcode()) { 206 case AArch64::ADR: 207 return (SecondMI.getOperand(2).getImm() == 0); 208 case AArch64::ADRP: 209 return true; 210 } 211 } 212 return false; 213 } 214 215 // Fuse compare and conditional select. 216 static bool isCCSelectPair(const MachineInstr *FirstMI, 217 const MachineInstr &SecondMI) { 218 unsigned SecondOpcode = SecondMI.getOpcode(); 219 220 // 32 bits 221 if (SecondOpcode == AArch64::CSELWr) { 222 // Assume the 1st instr to be a wildcard if it is unspecified. 223 if (!FirstMI) 224 return true; 225 226 if (FirstMI->definesRegister(AArch64::WZR)) 227 switch (FirstMI->getOpcode()) { 228 case AArch64::SUBSWrs: 229 return (!AArch64InstrInfo::hasShiftedReg(*FirstMI)); 230 case AArch64::SUBSWrx: 231 return (!AArch64InstrInfo::hasExtendedReg(*FirstMI)); 232 case AArch64::SUBSWrr: 233 case AArch64::SUBSWri: 234 return true; 235 } 236 } 237 // 64 bits 238 else if (SecondOpcode == AArch64::CSELXr) { 239 // Assume the 1st instr to be a wildcard if it is unspecified. 240 if (!FirstMI) 241 return true; 242 243 if (FirstMI->definesRegister(AArch64::XZR)) 244 switch (FirstMI->getOpcode()) { 245 case AArch64::SUBSXrs: 246 return (!AArch64InstrInfo::hasShiftedReg(*FirstMI)); 247 case AArch64::SUBSXrx: 248 case AArch64::SUBSXrx64: 249 return (!AArch64InstrInfo::hasExtendedReg(*FirstMI)); 250 case AArch64::SUBSXrr: 251 case AArch64::SUBSXri: 252 return true; 253 } 254 } 255 return false; 256 } 257 258 /// Check if the instr pair, FirstMI and SecondMI, should be fused 259 /// together. Given SecondMI, when FirstMI is unspecified, then check if 260 /// SecondMI may be part of a fused pair at all. 261 static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, 262 const TargetSubtargetInfo &TSI, 263 const MachineInstr *FirstMI, 264 const MachineInstr &SecondMI) { 265 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI); 266 267 if (ST.hasArithmeticBccFusion() && isArithmeticBccPair(FirstMI, SecondMI)) 268 return true; 269 if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI)) 270 return true; 271 if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI)) 272 return true; 273 if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI)) 274 return true; 275 if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI)) 276 return true; 277 if (ST.hasFuseCCSelect() && isCCSelectPair(FirstMI, SecondMI)) 278 return true; 279 280 return false; 281 } 282 283 } // end namespace 284 285 286 namespace llvm { 287 288 std::unique_ptr<ScheduleDAGMutation> createAArch64MacroFusionDAGMutation () { 289 return createMacroFusionDAGMutation(shouldScheduleAdjacent); 290 } 291 292 } // end namespace llvm 293