1 //===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==// 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 X86. 10 /// \todo This should be generated by TableGen. 11 //===----------------------------------------------------------------------===// 12 13 #include "X86RegisterBankInfo.h" 14 #include "X86InstrInfo.h" 15 #include "X86Subtarget.h" 16 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 17 #include "llvm/CodeGen/GlobalISel/Utils.h" 18 #include "llvm/CodeGen/MachineRegisterInfo.h" 19 #include "llvm/CodeGen/RegisterBank.h" 20 #include "llvm/CodeGen/RegisterBankInfo.h" 21 #include "llvm/CodeGen/TargetRegisterInfo.h" 22 #include "llvm/IR/IntrinsicsX86.h" 23 24 #define GET_TARGET_REGBANK_IMPL 25 #include "X86GenRegisterBank.inc" 26 27 using namespace llvm; 28 // This file will be TableGen'ed at some point. 29 #define GET_TARGET_REGBANK_INFO_IMPL 30 #include "X86GenRegisterBankInfo.def" 31 32 X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI) { 33 34 // validate RegBank initialization. 35 const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID); 36 (void)RBGPR; 37 assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization."); 38 39 // The GPR register bank is fully defined by all the registers in 40 // GR64 + its subclasses. 41 assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) && 42 "Subclass not added?"); 43 assert(getMaximumSize(RBGPR.getID()) == 64 && 44 "GPRs should hold up to 64-bit"); 45 } 46 47 // \returns true if a given intrinsic only uses and defines FPRs. 48 static bool isFPIntrinsic(const MachineRegisterInfo &MRI, 49 const MachineInstr &MI) { 50 // TODO: Add more intrinsics. 51 switch (cast<GIntrinsic>(MI).getIntrinsicID()) { 52 default: 53 return false; 54 // SSE1 55 case Intrinsic::x86_sse_rcp_ss: 56 case Intrinsic::x86_sse_rcp_ps: 57 case Intrinsic::x86_sse_rsqrt_ss: 58 case Intrinsic::x86_sse_rsqrt_ps: 59 case Intrinsic::x86_sse_min_ss: 60 case Intrinsic::x86_sse_min_ps: 61 case Intrinsic::x86_sse_max_ss: 62 case Intrinsic::x86_sse_max_ps: 63 return true; 64 } 65 return false; 66 } 67 68 bool X86RegisterBankInfo::hasFPConstraints(const MachineInstr &MI, 69 const MachineRegisterInfo &MRI, 70 const TargetRegisterInfo &TRI, 71 unsigned Depth) const { 72 unsigned Op = MI.getOpcode(); 73 if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MRI, MI)) 74 return true; 75 76 // Do we have an explicit floating point instruction? 77 if (isPreISelGenericFloatingPointOpcode(Op)) 78 return true; 79 80 // No. Check if we have a copy-like instruction. If we do, then we could 81 // still be fed by floating point instructions. 82 if (Op != TargetOpcode::COPY && !MI.isPHI() && 83 !isPreISelGenericOptimizationHint(Op)) 84 return false; 85 86 // Check if we already know the register bank. 87 auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI); 88 if (RB == &getRegBank(X86::PSRRegBankID)) 89 return true; 90 if (RB == &getRegBank(X86::GPRRegBankID)) 91 return false; 92 93 // We don't know anything. 94 // 95 // If we have a phi, we may be able to infer that it will be assigned a fp 96 // type based off of its inputs. 97 if (!MI.isPHI() || Depth > MaxFPRSearchDepth) 98 return false; 99 100 return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) { 101 return Op.isReg() && 102 onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1); 103 }); 104 } 105 106 bool X86RegisterBankInfo::onlyUsesFP(const MachineInstr &MI, 107 const MachineRegisterInfo &MRI, 108 const TargetRegisterInfo &TRI, 109 unsigned Depth) const { 110 switch (MI.getOpcode()) { 111 case TargetOpcode::G_FPTOSI: 112 case TargetOpcode::G_FPTOUI: 113 case TargetOpcode::G_FCMP: 114 case TargetOpcode::G_LROUND: 115 case TargetOpcode::G_LLROUND: 116 case TargetOpcode::G_INTRINSIC_TRUNC: 117 case TargetOpcode::G_INTRINSIC_ROUND: 118 return true; 119 default: 120 break; 121 } 122 return hasFPConstraints(MI, MRI, TRI, Depth); 123 } 124 125 bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI, 126 const MachineRegisterInfo &MRI, 127 const TargetRegisterInfo &TRI, 128 unsigned Depth) const { 129 switch (MI.getOpcode()) { 130 case TargetOpcode::G_SITOFP: 131 case TargetOpcode::G_UITOFP: 132 return true; 133 default: 134 break; 135 } 136 return hasFPConstraints(MI, MRI, TRI, Depth); 137 } 138 139 X86GenRegisterBankInfo::PartialMappingIdx 140 X86GenRegisterBankInfo::getPartialMappingIdx(const MachineInstr &MI, 141 const LLT &Ty, bool isFP) { 142 const MachineFunction *MF = MI.getMF(); 143 const X86Subtarget *ST = &MF->getSubtarget<X86Subtarget>(); 144 bool HasSSE1 = ST->hasSSE1(); 145 bool HasSSE2 = ST->hasSSE2(); 146 // 80 bits is only generated for X87 floating points. 147 if (Ty.getSizeInBits() == 80) 148 isFP = true; 149 if ((Ty.isScalar() && !isFP) || Ty.isPointer()) { 150 switch (Ty.getSizeInBits()) { 151 case 1: 152 case 8: 153 return PMI_GPR8; 154 case 16: 155 return PMI_GPR16; 156 case 32: 157 return PMI_GPR32; 158 case 64: 159 return PMI_GPR64; 160 case 128: 161 return PMI_VEC128; 162 break; 163 default: 164 llvm_unreachable("Unsupported register size."); 165 } 166 } else if (Ty.isScalar()) { 167 switch (Ty.getSizeInBits()) { 168 case 32: 169 return HasSSE1 ? PMI_FP32 : PMI_PSR32; 170 case 64: 171 return HasSSE2 ? PMI_FP64 : PMI_PSR64; 172 case 128: 173 return PMI_VEC128; 174 case 80: 175 return PMI_PSR80; 176 default: 177 llvm_unreachable("Unsupported register size."); 178 } 179 } else { 180 switch (Ty.getSizeInBits()) { 181 case 128: 182 return PMI_VEC128; 183 case 256: 184 return PMI_VEC256; 185 case 512: 186 return PMI_VEC512; 187 default: 188 llvm_unreachable("Unsupported register size."); 189 } 190 } 191 192 return PMI_None; 193 } 194 195 void X86RegisterBankInfo::getInstrPartialMappingIdxs( 196 const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP, 197 SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) { 198 199 unsigned NumOperands = MI.getNumOperands(); 200 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 201 auto &MO = MI.getOperand(Idx); 202 if (!MO.isReg() || !MO.getReg()) 203 OpRegBankIdx[Idx] = PMI_None; 204 else 205 OpRegBankIdx[Idx] = 206 getPartialMappingIdx(MI, MRI.getType(MO.getReg()), isFP); 207 } 208 } 209 210 bool X86RegisterBankInfo::getInstrValueMapping( 211 const MachineInstr &MI, 212 const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx, 213 SmallVectorImpl<const ValueMapping *> &OpdsMapping) { 214 215 unsigned NumOperands = MI.getNumOperands(); 216 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 217 if (!MI.getOperand(Idx).isReg()) 218 continue; 219 if (!MI.getOperand(Idx).getReg()) 220 continue; 221 222 auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1); 223 if (!Mapping->isValid()) 224 return false; 225 226 OpdsMapping[Idx] = Mapping; 227 } 228 return true; 229 } 230 231 const RegisterBankInfo::InstructionMapping & 232 X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI, 233 bool isFP) const { 234 const MachineFunction &MF = *MI.getParent()->getParent(); 235 const MachineRegisterInfo &MRI = MF.getRegInfo(); 236 237 unsigned NumOperands = MI.getNumOperands(); 238 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 239 240 if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) || 241 (Ty != MRI.getType(MI.getOperand(2).getReg()))) 242 llvm_unreachable("Unsupported operand mapping yet."); 243 244 auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, isFP), 3); 245 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands); 246 } 247 248 const RegisterBankInfo::InstructionMapping & 249 X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { 250 const MachineFunction &MF = *MI.getParent()->getParent(); 251 const TargetSubtargetInfo &STI = MF.getSubtarget(); 252 const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 253 const MachineRegisterInfo &MRI = MF.getRegInfo(); 254 unsigned Opc = MI.getOpcode(); 255 256 // Try the default logic for non-generic instructions that are either 257 // copies or already have some operands assigned to banks. 258 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) { 259 const InstructionMapping &Mapping = getInstrMappingImpl(MI); 260 if (Mapping.isValid()) 261 return Mapping; 262 } 263 264 switch (Opc) { 265 case TargetOpcode::G_ADD: 266 case TargetOpcode::G_SUB: 267 case TargetOpcode::G_MUL: 268 return getSameOperandsMapping(MI, false); 269 case TargetOpcode::G_FADD: 270 case TargetOpcode::G_FSUB: 271 case TargetOpcode::G_FMUL: 272 case TargetOpcode::G_FDIV: 273 return getSameOperandsMapping(MI, true); 274 case TargetOpcode::G_SHL: 275 case TargetOpcode::G_LSHR: 276 case TargetOpcode::G_ASHR: { 277 unsigned NumOperands = MI.getNumOperands(); 278 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 279 280 auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, false), 3); 281 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands); 282 } 283 default: 284 break; 285 } 286 287 unsigned NumOperands = MI.getNumOperands(); 288 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); 289 290 switch (Opc) { 291 case TargetOpcode::G_FPEXT: 292 case TargetOpcode::G_FPTRUNC: 293 case TargetOpcode::G_FCONSTANT: 294 // Instruction having only floating-point operands (all scalars in 295 // VECRReg) 296 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx); 297 break; 298 case TargetOpcode::G_SITOFP: 299 case TargetOpcode::G_FPTOSI: 300 case TargetOpcode::G_UITOFP: 301 case TargetOpcode::G_FPTOUI: { 302 // Some of the floating-point instructions have mixed GPR and FP 303 // operands: fine-tune the computed mapping. 304 auto &Op0 = MI.getOperand(0); 305 auto &Op1 = MI.getOperand(1); 306 const LLT Ty0 = MRI.getType(Op0.getReg()); 307 const LLT Ty1 = MRI.getType(Op1.getReg()); 308 309 bool FirstArgIsFP = 310 Opc == TargetOpcode::G_SITOFP || Opc == TargetOpcode::G_UITOFP; 311 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ FirstArgIsFP); 312 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ !FirstArgIsFP); 313 break; 314 } 315 case TargetOpcode::G_FCMP: { 316 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg()); 317 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg()); 318 (void)Ty2; 319 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() && 320 "Mismatched operand sizes for G_FCMP"); 321 322 unsigned Size = Ty1.getSizeInBits(); 323 (void)Size; 324 assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP"); 325 326 auto FpRegBank = getPartialMappingIdx(MI, Ty1, /* isFP= */ true); 327 OpRegBankIdx = {PMI_GPR8, 328 /* Predicate */ PMI_None, FpRegBank, FpRegBank}; 329 break; 330 } 331 case TargetOpcode::G_TRUNC: 332 case TargetOpcode::G_ANYEXT: { 333 auto &Op0 = MI.getOperand(0); 334 auto &Op1 = MI.getOperand(1); 335 const LLT Ty0 = MRI.getType(Op0.getReg()); 336 const LLT Ty1 = MRI.getType(Op1.getReg()); 337 338 bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) && 339 Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC; 340 bool isFPAnyExt = 341 Ty0.getSizeInBits() == 128 && 342 (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) && 343 Opc == TargetOpcode::G_ANYEXT; 344 345 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt, 346 OpRegBankIdx); 347 break; 348 } 349 case TargetOpcode::G_LOAD: { 350 // Check if that load feeds fp instructions. 351 // In that case, we want the default mapping to be on FPR 352 // instead of blind map every scalar to GPR. 353 bool IsFP = any_of(MRI.use_nodbg_instructions(cast<GLoad>(MI).getDstReg()), 354 [&](const MachineInstr &UseMI) { 355 // If we have at least one direct use in a FP 356 // instruction, assume this was a floating point load 357 // in the IR. If it was not, we would have had a 358 // bitcast before reaching that instruction. 359 return onlyUsesFP(UseMI, MRI, TRI); 360 }); 361 getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx); 362 break; 363 } 364 case TargetOpcode::G_STORE: { 365 // Check if that store is fed by fp instructions. 366 Register VReg = cast<GStore>(MI).getValueReg(); 367 if (!VReg) 368 break; 369 MachineInstr *DefMI = MRI.getVRegDef(VReg); 370 bool IsFP = onlyDefinesFP(*DefMI, MRI, TRI); 371 getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx); 372 break; 373 } 374 default: 375 // Track the bank of each register, use NotFP mapping (all scalars in 376 // GPRs) 377 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx); 378 break; 379 } 380 381 // Finally construct the computed mapping. 382 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 383 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping)) 384 return getInvalidInstructionMapping(); 385 386 return getInstructionMapping(DefaultMappingID, /* Cost */ 1, 387 getOperandsMapping(OpdsMapping), NumOperands); 388 } 389 390 void X86RegisterBankInfo::applyMappingImpl( 391 MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const { 392 return applyDefaultMapping(OpdMapper); 393 } 394 395 RegisterBankInfo::InstructionMappings 396 X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const { 397 398 const MachineFunction &MF = *MI.getParent()->getParent(); 399 const TargetSubtargetInfo &STI = MF.getSubtarget(); 400 const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 401 const MachineRegisterInfo &MRI = MF.getRegInfo(); 402 403 switch (MI.getOpcode()) { 404 case TargetOpcode::G_LOAD: 405 case TargetOpcode::G_STORE: 406 case TargetOpcode::G_IMPLICIT_DEF: { 407 // we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80 408 unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 409 if (Size != 32 && Size != 64 && Size != 80) 410 break; 411 412 unsigned NumOperands = MI.getNumOperands(); 413 414 // Track the bank of each register, use FP mapping (all scalars in VEC) 415 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); 416 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx); 417 418 // Finally construct the computed mapping. 419 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 420 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping)) 421 break; 422 423 const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping( 424 /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands); 425 InstructionMappings AltMappings; 426 AltMappings.push_back(&Mapping); 427 return AltMappings; 428 } 429 default: 430 break; 431 } 432 return RegisterBankInfo::getInstrAlternativeMappings(MI); 433 } 434