1 //===- PPCRegisterBankInfo.cpp --------------------------------------------===// 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 /// \file 9 /// This file implements the targeting of the RegisterBankInfo class for 10 /// PowerPC. 11 //===----------------------------------------------------------------------===// 12 13 #include "PPCRegisterBankInfo.h" 14 #include "PPCRegisterInfo.h" 15 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 16 #include "llvm/CodeGen/GlobalISel/Utils.h" 17 #include "llvm/CodeGen/MachineFunction.h" 18 #include "llvm/CodeGen/MachineRegisterInfo.h" 19 #include "llvm/Support/Debug.h" 20 21 #define DEBUG_TYPE "ppc-reg-bank-info" 22 23 #define GET_TARGET_REGBANK_IMPL 24 #include "PPCGenRegisterBank.inc" 25 26 // This file will be TableGen'ed at some point. 27 #include "PPCGenRegisterBankInfo.def" 28 29 using namespace llvm; 30 31 PPCRegisterBankInfo::PPCRegisterBankInfo(const TargetRegisterInfo &TRI) {} 32 33 const RegisterBank & 34 PPCRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, 35 LLT Ty) const { 36 switch (RC.getID()) { 37 case PPC::G8RCRegClassID: 38 case PPC::G8RC_NOX0RegClassID: 39 case PPC::G8RC_and_G8RC_NOX0RegClassID: 40 case PPC::GPRCRegClassID: 41 case PPC::GPRC_NOR0RegClassID: 42 case PPC::GPRC_and_GPRC_NOR0RegClassID: 43 return getRegBank(PPC::GPRRegBankID); 44 case PPC::VSFRCRegClassID: 45 case PPC::SPILLTOVSRRC_and_VSFRCRegClassID: 46 case PPC::SPILLTOVSRRC_and_VFRCRegClassID: 47 case PPC::SPILLTOVSRRC_and_F4RCRegClassID: 48 case PPC::F8RCRegClassID: 49 case PPC::VFRCRegClassID: 50 case PPC::VSSRCRegClassID: 51 case PPC::F4RCRegClassID: 52 return getRegBank(PPC::FPRRegBankID); 53 case PPC::VSRCRegClassID: 54 case PPC::VRRCRegClassID: 55 case PPC::VRRC_with_sub_64_in_SPILLTOVSRRCRegClassID: 56 case PPC::VSRC_with_sub_64_in_SPILLTOVSRRCRegClassID: 57 case PPC::SPILLTOVSRRCRegClassID: 58 case PPC::VSLRCRegClassID: 59 case PPC::VSLRC_with_sub_64_in_SPILLTOVSRRCRegClassID: 60 return getRegBank(PPC::VECRegBankID); 61 case PPC::CRRCRegClassID: 62 case PPC::CRBITRCRegClassID: 63 return getRegBank(PPC::CRRegBankID); 64 default: 65 llvm_unreachable("Unexpected register class"); 66 } 67 } 68 69 const RegisterBankInfo::InstructionMapping & 70 PPCRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { 71 const unsigned Opc = MI.getOpcode(); 72 73 // Try the default logic for non-generic instructions that are either copies 74 // or already have some operands assigned to banks. 75 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) { 76 const RegisterBankInfo::InstructionMapping &Mapping = 77 getInstrMappingImpl(MI); 78 if (Mapping.isValid()) 79 return Mapping; 80 } 81 82 const MachineFunction &MF = *MI.getParent()->getParent(); 83 const MachineRegisterInfo &MRI = MF.getRegInfo(); 84 const TargetSubtargetInfo &STI = MF.getSubtarget(); 85 const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 86 87 unsigned NumOperands = MI.getNumOperands(); 88 const ValueMapping *OperandsMapping = nullptr; 89 unsigned Cost = 1; 90 unsigned MappingID = DefaultMappingID; 91 92 switch (Opc) { 93 // Arithmetic ops. 94 case TargetOpcode::G_ADD: 95 case TargetOpcode::G_SUB: 96 // Bitwise ops. 97 case TargetOpcode::G_AND: 98 case TargetOpcode::G_OR: 99 case TargetOpcode::G_XOR: 100 // Extension ops. 101 case TargetOpcode::G_SEXT: 102 case TargetOpcode::G_ZEXT: 103 case TargetOpcode::G_ANYEXT: { 104 assert(NumOperands <= 3 && 105 "This code is for instructions with 3 or less operands"); 106 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 107 unsigned Size = Ty.getSizeInBits(); 108 switch (Size) { 109 case 128: 110 OperandsMapping = getValueMapping(PMI_VEC128); 111 break; 112 default: 113 OperandsMapping = getValueMapping(PMI_GPR64); 114 break; 115 } 116 break; 117 } 118 case TargetOpcode::G_FADD: 119 case TargetOpcode::G_FSUB: 120 case TargetOpcode::G_FMUL: 121 case TargetOpcode::G_FDIV: { 122 Register SrcReg = MI.getOperand(1).getReg(); 123 unsigned Size = getSizeInBits(SrcReg, MRI, TRI); 124 125 assert((Size == 32 || Size == 64 || Size == 128) && 126 "Unsupported floating point types!\n"); 127 switch (Size) { 128 case 32: 129 OperandsMapping = getValueMapping(PMI_FPR32); 130 break; 131 case 64: 132 OperandsMapping = getValueMapping(PMI_FPR64); 133 break; 134 case 128: 135 OperandsMapping = getValueMapping(PMI_VEC128); 136 break; 137 } 138 break; 139 } 140 case TargetOpcode::G_FCMP: { 141 unsigned CmpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits(); 142 143 OperandsMapping = getOperandsMapping( 144 {getValueMapping(PMI_CR), nullptr, 145 getValueMapping(CmpSize == 32 ? PMI_FPR32 : PMI_FPR64), 146 getValueMapping(CmpSize == 32 ? PMI_FPR32 : PMI_FPR64)}); 147 break; 148 } 149 case TargetOpcode::G_CONSTANT: 150 OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); 151 break; 152 case TargetOpcode::G_CONSTANT_POOL: 153 OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); 154 break; 155 case TargetOpcode::G_FPTOUI: 156 case TargetOpcode::G_FPTOSI: { 157 Register SrcReg = MI.getOperand(1).getReg(); 158 unsigned Size = getSizeInBits(SrcReg, MRI, TRI); 159 160 OperandsMapping = getOperandsMapping( 161 {getValueMapping(PMI_GPR64), 162 getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64)}); 163 break; 164 } 165 case TargetOpcode::G_UITOFP: 166 case TargetOpcode::G_SITOFP: { 167 Register SrcReg = MI.getOperand(0).getReg(); 168 unsigned Size = getSizeInBits(SrcReg, MRI, TRI); 169 170 OperandsMapping = 171 getOperandsMapping({getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64), 172 getValueMapping(PMI_GPR64)}); 173 break; 174 } 175 case TargetOpcode::G_LOAD: { 176 unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 177 // Check if that load feeds fp instructions. 178 if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()), 179 [&](const MachineInstr &UseMI) { 180 // If we have at least one direct use in a FP instruction, 181 // assume this was a floating point load in the IR. If it was 182 // not, we would have had a bitcast before reaching that 183 // instruction. 184 // 185 // Int->FP conversion operations are also captured in 186 // onlyDefinesFP(). 187 return onlyUsesFP(UseMI, MRI, TRI); 188 })) 189 OperandsMapping = getOperandsMapping( 190 {getValueMapping(Size == 64 ? PMI_FPR64 : PMI_FPR32), 191 getValueMapping(PMI_GPR64)}); 192 else 193 OperandsMapping = getOperandsMapping( 194 {getValueMapping(Size == 64 ? PMI_GPR64 : PMI_GPR32), 195 getValueMapping(PMI_GPR64)}); 196 break; 197 } 198 case TargetOpcode::G_STORE: { 199 // Check if the store is fed by fp instructions. 200 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg()); 201 unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); 202 if (onlyDefinesFP(*DefMI, MRI, TRI)) 203 OperandsMapping = getOperandsMapping( 204 {getValueMapping(Size == 64 ? PMI_FPR64 : PMI_FPR32), 205 getValueMapping(PMI_GPR64)}); 206 else 207 OperandsMapping = getOperandsMapping( 208 {getValueMapping(Size == 64 ? PMI_GPR64 : PMI_GPR32), 209 getValueMapping(PMI_GPR64)}); 210 break; 211 } 212 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: { 213 // FIXME: We have to check every operand in this MI and compute value 214 // mapping accordingly. 215 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 216 OperandsMapping = getOperandsMapping(OpdsMapping); 217 break; 218 } 219 case TargetOpcode::G_BITCAST: { 220 LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); 221 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 222 unsigned DstSize = DstTy.getSizeInBits(); 223 224 bool DstIsGPR = !DstTy.isVector(); 225 bool SrcIsGPR = !SrcTy.isVector(); 226 // TODO: Currently, only vector and GPR register banks are handled. 227 // This needs to be extended to handle floating point register 228 // banks in the future. 229 const RegisterBank &DstRB = DstIsGPR ? PPC::GPRRegBank : PPC::VECRegBank; 230 const RegisterBank &SrcRB = SrcIsGPR ? PPC::GPRRegBank : PPC::VECRegBank; 231 232 return getInstructionMapping( 233 MappingID, Cost, getCopyMapping(DstRB.getID(), SrcRB.getID(), DstSize), 234 NumOperands); 235 } 236 default: 237 return getInvalidInstructionMapping(); 238 } 239 240 return getInstructionMapping(MappingID, Cost, OperandsMapping, NumOperands); 241 } 242 243 /// \returns true if a given intrinsic \p ID only uses and defines FPRs. 244 static bool isFPIntrinsic(unsigned ID) { 245 // TODO: Add more intrinsics. 246 return false; 247 } 248 249 /// FIXME: this is copied from target AArch64. Needs some code refactor here to 250 /// put this function in class RegisterBankInfo. 251 bool PPCRegisterBankInfo::hasFPConstraints(const MachineInstr &MI, 252 const MachineRegisterInfo &MRI, 253 const TargetRegisterInfo &TRI, 254 unsigned Depth) const { 255 unsigned Op = MI.getOpcode(); 256 257 if (auto *GI = dyn_cast<GIntrinsic>(&MI)) { 258 if (isFPIntrinsic(GI->getIntrinsicID())) 259 return true; 260 } 261 262 // Do we have an explicit floating point instruction? 263 if (isPreISelGenericFloatingPointOpcode(Op)) 264 return true; 265 266 // No. Check if we have a copy-like instruction. If we do, then we could 267 // still be fed by floating point instructions. 268 if (Op != TargetOpcode::COPY && !MI.isPHI() && 269 !isPreISelGenericOptimizationHint(Op)) 270 return false; 271 272 // Check if we already know the register bank. 273 auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI); 274 if (RB == &PPC::FPRRegBank) 275 return true; 276 if (RB == &PPC::GPRRegBank) 277 return false; 278 279 // We don't know anything. 280 // 281 // If we have a phi, we may be able to infer that it will be assigned a FPR 282 // based off of its inputs. 283 if (!MI.isPHI() || Depth > MaxFPRSearchDepth) 284 return false; 285 286 return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) { 287 return Op.isReg() && 288 onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1); 289 }); 290 } 291 292 /// FIXME: this is copied from target AArch64. Needs some code refactor here to 293 /// put this function in class RegisterBankInfo. 294 bool PPCRegisterBankInfo::onlyUsesFP(const MachineInstr &MI, 295 const MachineRegisterInfo &MRI, 296 const TargetRegisterInfo &TRI, 297 unsigned Depth) const { 298 switch (MI.getOpcode()) { 299 case TargetOpcode::G_FPTOSI: 300 case TargetOpcode::G_FPTOUI: 301 case TargetOpcode::G_FCMP: 302 case TargetOpcode::G_LROUND: 303 case TargetOpcode::G_LLROUND: 304 return true; 305 default: 306 break; 307 } 308 return hasFPConstraints(MI, MRI, TRI, Depth); 309 } 310 311 /// FIXME: this is copied from target AArch64. Needs some code refactor here to 312 /// put this function in class RegisterBankInfo. 313 bool PPCRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI, 314 const MachineRegisterInfo &MRI, 315 const TargetRegisterInfo &TRI, 316 unsigned Depth) const { 317 switch (MI.getOpcode()) { 318 case TargetOpcode::G_SITOFP: 319 case TargetOpcode::G_UITOFP: 320 return true; 321 default: 322 break; 323 } 324 return hasFPConstraints(MI, MRI, TRI, Depth); 325 } 326 327 RegisterBankInfo::InstructionMappings 328 PPCRegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const { 329 // TODO Implement. 330 return RegisterBankInfo::getInstrAlternativeMappings(MI); 331 } 332