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