448 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8/// \file9/// 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_IMPL25#include "X86GenRegisterBank.inc"26 27using namespace llvm;28// This file will be TableGen'ed at some point.29#define GET_TARGET_REGBANK_INFO_IMPL30#include "X86GenRegisterBankInfo.def"31 32X86RegisterBankInfo::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 in40 // 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.48static 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 // SSE155 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 68bool 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 could81 // 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 fp96 // 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 106bool 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 X86::G_FIST:115 case TargetOpcode::G_LROUND:116 case TargetOpcode::G_LLROUND:117 case TargetOpcode::G_INTRINSIC_TRUNC:118 case TargetOpcode::G_INTRINSIC_ROUND:119 return true;120 default:121 break;122 }123 return hasFPConstraints(MI, MRI, TRI, Depth);124}125 126bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,127 const MachineRegisterInfo &MRI,128 const TargetRegisterInfo &TRI,129 unsigned Depth) const {130 switch (MI.getOpcode()) {131 case TargetOpcode::G_SITOFP:132 case TargetOpcode::G_UITOFP:133 case X86::G_FILD:134 return true;135 default:136 break;137 }138 return hasFPConstraints(MI, MRI, TRI, Depth);139}140 141X86GenRegisterBankInfo::PartialMappingIdx142X86GenRegisterBankInfo::getPartialMappingIdx(const MachineInstr &MI,143 const LLT &Ty, bool isFP) {144 const MachineFunction *MF = MI.getMF();145 const X86Subtarget *ST = &MF->getSubtarget<X86Subtarget>();146 bool HasSSE1 = ST->hasSSE1();147 bool HasSSE2 = ST->hasSSE2();148 // 80 bits is only generated for X87 floating points.149 if (Ty.getSizeInBits() == 80)150 isFP = true;151 if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {152 switch (Ty.getSizeInBits()) {153 case 1:154 case 8:155 return PMI_GPR8;156 case 16:157 return PMI_GPR16;158 case 32:159 return PMI_GPR32;160 case 64:161 return PMI_GPR64;162 case 128:163 return PMI_VEC128;164 break;165 default:166 llvm_unreachable("Unsupported register size.");167 }168 } else if (Ty.isScalar()) {169 switch (Ty.getSizeInBits()) {170 case 32:171 return HasSSE1 ? PMI_FP32 : PMI_PSR32;172 case 64:173 return HasSSE2 ? PMI_FP64 : PMI_PSR64;174 case 128:175 return PMI_VEC128;176 case 80:177 return PMI_PSR80;178 default:179 llvm_unreachable("Unsupported register size.");180 }181 } else {182 switch (Ty.getSizeInBits()) {183 case 128:184 return PMI_VEC128;185 case 256:186 return PMI_VEC256;187 case 512:188 return PMI_VEC512;189 default:190 llvm_unreachable("Unsupported register size.");191 }192 }193 194 return PMI_None;195}196 197void X86RegisterBankInfo::getInstrPartialMappingIdxs(198 const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,199 SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {200 201 unsigned NumOperands = MI.getNumOperands();202 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {203 auto &MO = MI.getOperand(Idx);204 if (!MO.isReg() || !MO.getReg())205 OpRegBankIdx[Idx] = PMI_None;206 else207 OpRegBankIdx[Idx] =208 getPartialMappingIdx(MI, MRI.getType(MO.getReg()), isFP);209 }210}211 212bool X86RegisterBankInfo::getInstrValueMapping(213 const MachineInstr &MI,214 const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,215 SmallVectorImpl<const ValueMapping *> &OpdsMapping) {216 217 unsigned NumOperands = MI.getNumOperands();218 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {219 if (!MI.getOperand(Idx).isReg())220 continue;221 if (!MI.getOperand(Idx).getReg())222 continue;223 224 auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);225 if (!Mapping->isValid())226 return false;227 228 OpdsMapping[Idx] = Mapping;229 }230 return true;231}232 233const RegisterBankInfo::InstructionMapping &234X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,235 bool isFP) const {236 const MachineFunction &MF = *MI.getParent()->getParent();237 const MachineRegisterInfo &MRI = MF.getRegInfo();238 239 unsigned NumOperands = MI.getNumOperands();240 LLT Ty = MRI.getType(MI.getOperand(0).getReg());241 242 if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||243 (Ty != MRI.getType(MI.getOperand(2).getReg())))244 llvm_unreachable("Unsupported operand mapping yet.");245 246 auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, isFP), 3);247 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);248}249 250const RegisterBankInfo::InstructionMapping &251X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {252 const MachineFunction &MF = *MI.getParent()->getParent();253 const TargetSubtargetInfo &STI = MF.getSubtarget();254 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();255 const MachineRegisterInfo &MRI = MF.getRegInfo();256 unsigned Opc = MI.getOpcode();257 258 // Try the default logic for non-generic instructions that are either259 // copies or already have some operands assigned to banks.260 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {261 const InstructionMapping &Mapping = getInstrMappingImpl(MI);262 if (Mapping.isValid())263 return Mapping;264 }265 266 switch (Opc) {267 case TargetOpcode::G_ADD:268 case TargetOpcode::G_SUB:269 case TargetOpcode::G_MUL:270 return getSameOperandsMapping(MI, false);271 case TargetOpcode::G_FADD:272 case TargetOpcode::G_FSUB:273 case TargetOpcode::G_FMUL:274 case TargetOpcode::G_FDIV:275 return getSameOperandsMapping(MI, true);276 case TargetOpcode::G_SHL:277 case TargetOpcode::G_LSHR:278 case TargetOpcode::G_ASHR: {279 unsigned NumOperands = MI.getNumOperands();280 LLT Ty = MRI.getType(MI.getOperand(0).getReg());281 282 auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, false), 3);283 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);284 }285 default:286 break;287 }288 289 unsigned NumOperands = MI.getNumOperands();290 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);291 292 switch (Opc) {293 case TargetOpcode::G_FSQRT:294 case TargetOpcode::G_FPEXT:295 case TargetOpcode::G_FPTRUNC:296 case TargetOpcode::G_FCONSTANT:297 // Instruction having only floating-point operands (all scalars in298 // VECRReg)299 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);300 break;301 case X86::G_FIST:302 case X86::G_FILD: {303 auto &Op0 = MI.getOperand(0);304 auto &Op1 = MI.getOperand(1);305 const LLT Ty0 = MRI.getType(Op0.getReg());306 const LLT Ty1 = MRI.getType(Op1.getReg());307 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ true);308 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ false);309 break;310 }311 case TargetOpcode::G_SITOFP:312 case TargetOpcode::G_FPTOSI:313 case TargetOpcode::G_UITOFP:314 case TargetOpcode::G_FPTOUI: {315 // Some of the floating-point instructions have mixed GPR and FP316 // operands: fine-tune the computed mapping.317 auto &Op0 = MI.getOperand(0);318 auto &Op1 = MI.getOperand(1);319 const LLT Ty0 = MRI.getType(Op0.getReg());320 const LLT Ty1 = MRI.getType(Op1.getReg());321 322 bool FirstArgIsFP =323 Opc == TargetOpcode::G_SITOFP || Opc == TargetOpcode::G_UITOFP;324 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ FirstArgIsFP);325 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ !FirstArgIsFP);326 break;327 }328 case TargetOpcode::G_FCMP: {329 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());330 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());331 (void)Ty2;332 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&333 "Mismatched operand sizes for G_FCMP");334 335 unsigned Size = Ty1.getSizeInBits();336 (void)Size;337 assert((Size == 32 || Size == 64 || Size == 80) &&338 "Unsupported size for G_FCMP");339 auto FpRegBank = getPartialMappingIdx(MI, Ty1, /* isFP= */ true);340 OpRegBankIdx = {PMI_GPR8,341 /* Predicate */ PMI_None, FpRegBank, FpRegBank};342 break;343 }344 case TargetOpcode::G_FABS:345 case TargetOpcode::G_TRUNC:346 case TargetOpcode::G_ANYEXT: {347 auto &Op0 = MI.getOperand(0);348 auto &Op1 = MI.getOperand(1);349 const LLT Ty0 = MRI.getType(Op0.getReg());350 const LLT Ty1 = MRI.getType(Op1.getReg());351 352 bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&353 Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;354 bool isFPAnyExt =355 Ty0.getSizeInBits() == 128 &&356 (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&357 Opc == TargetOpcode::G_ANYEXT;358 bool isFAbs = (Opc == TargetOpcode::G_FABS);359 getInstrPartialMappingIdxs(360 MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt || isFAbs, OpRegBankIdx);361 break;362 }363 case TargetOpcode::G_LOAD: {364 // Check if that load feeds fp instructions.365 // In that case, we want the default mapping to be on FPR366 // instead of blind map every scalar to GPR.367 bool IsFP = any_of(MRI.use_nodbg_instructions(cast<GLoad>(MI).getDstReg()),368 [&](const MachineInstr &UseMI) {369 // If we have at least one direct use in a FP370 // instruction, assume this was a floating point load371 // in the IR. If it was not, we would have had a372 // bitcast before reaching that instruction.373 return onlyUsesFP(UseMI, MRI, TRI);374 });375 getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);376 break;377 }378 case TargetOpcode::G_STORE: {379 // Check if that store is fed by fp instructions.380 Register VReg = cast<GStore>(MI).getValueReg();381 if (!VReg)382 break;383 MachineInstr *DefMI = MRI.getVRegDef(VReg);384 bool IsFP = onlyDefinesFP(*DefMI, MRI, TRI);385 getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);386 break;387 }388 default:389 // Track the bank of each register, use NotFP mapping (all scalars in390 // GPRs)391 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx);392 break;393 }394 395 // Finally construct the computed mapping.396 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);397 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))398 return getInvalidInstructionMapping();399 400 return getInstructionMapping(DefaultMappingID, /* Cost */ 1,401 getOperandsMapping(OpdsMapping), NumOperands);402}403 404void X86RegisterBankInfo::applyMappingImpl(405 MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {406 return applyDefaultMapping(OpdMapper);407}408 409RegisterBankInfo::InstructionMappings410X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {411 412 const MachineFunction &MF = *MI.getParent()->getParent();413 const TargetSubtargetInfo &STI = MF.getSubtarget();414 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();415 const MachineRegisterInfo &MRI = MF.getRegInfo();416 417 switch (MI.getOpcode()) {418 case TargetOpcode::G_LOAD:419 case TargetOpcode::G_STORE:420 case TargetOpcode::G_IMPLICIT_DEF: {421 // we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80422 unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);423 if (Size != 32 && Size != 64 && Size != 80)424 break;425 426 unsigned NumOperands = MI.getNumOperands();427 428 // Track the bank of each register, use FP mapping (all scalars in VEC)429 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);430 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);431 432 // Finally construct the computed mapping.433 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);434 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))435 break;436 437 const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(438 /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);439 InstructionMappings AltMappings;440 AltMappings.push_back(&Mapping);441 return AltMappings;442 }443 default:444 break;445 }446 return RegisterBankInfo::getInstrAlternativeMappings(MI);447}448