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