15f757f3fSDimitry Andric //===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric /// \file 95f757f3fSDimitry Andric /// This file implements the targeting of the RegisterBankInfo class for X86. 105f757f3fSDimitry Andric /// \todo This should be generated by TableGen. 115f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 125f757f3fSDimitry Andric 135f757f3fSDimitry Andric #include "X86RegisterBankInfo.h" 145f757f3fSDimitry Andric #include "X86InstrInfo.h" 15*0fca6ea1SDimitry Andric #include "X86Subtarget.h" 16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 185f757f3fSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 195f757f3fSDimitry Andric #include "llvm/CodeGen/RegisterBank.h" 205f757f3fSDimitry Andric #include "llvm/CodeGen/RegisterBankInfo.h" 215f757f3fSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 22*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicsX86.h" 235f757f3fSDimitry Andric 245f757f3fSDimitry Andric #define GET_TARGET_REGBANK_IMPL 255f757f3fSDimitry Andric #include "X86GenRegisterBank.inc" 265f757f3fSDimitry Andric 275f757f3fSDimitry Andric using namespace llvm; 285f757f3fSDimitry Andric // This file will be TableGen'ed at some point. 295f757f3fSDimitry Andric #define GET_TARGET_REGBANK_INFO_IMPL 305f757f3fSDimitry Andric #include "X86GenRegisterBankInfo.def" 315f757f3fSDimitry Andric 325f757f3fSDimitry Andric X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI) { 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric // validate RegBank initialization. 355f757f3fSDimitry Andric const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID); 365f757f3fSDimitry Andric (void)RBGPR; 375f757f3fSDimitry Andric assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization."); 385f757f3fSDimitry Andric 395f757f3fSDimitry Andric // The GPR register bank is fully defined by all the registers in 405f757f3fSDimitry Andric // GR64 + its subclasses. 415f757f3fSDimitry Andric assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) && 425f757f3fSDimitry Andric "Subclass not added?"); 435f757f3fSDimitry Andric assert(getMaximumSize(RBGPR.getID()) == 64 && 445f757f3fSDimitry Andric "GPRs should hold up to 64-bit"); 455f757f3fSDimitry Andric } 465f757f3fSDimitry Andric 475f757f3fSDimitry Andric const RegisterBank & 485f757f3fSDimitry Andric X86RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, 495f757f3fSDimitry Andric LLT) const { 505f757f3fSDimitry Andric 515f757f3fSDimitry Andric if (X86::GR8RegClass.hasSubClassEq(&RC) || 525f757f3fSDimitry Andric X86::GR16RegClass.hasSubClassEq(&RC) || 535f757f3fSDimitry Andric X86::GR32RegClass.hasSubClassEq(&RC) || 545f757f3fSDimitry Andric X86::GR64RegClass.hasSubClassEq(&RC) || 555f757f3fSDimitry Andric X86::LOW32_ADDR_ACCESSRegClass.hasSubClassEq(&RC) || 565f757f3fSDimitry Andric X86::LOW32_ADDR_ACCESS_RBPRegClass.hasSubClassEq(&RC)) 575f757f3fSDimitry Andric return getRegBank(X86::GPRRegBankID); 585f757f3fSDimitry Andric 595f757f3fSDimitry Andric if (X86::FR32XRegClass.hasSubClassEq(&RC) || 605f757f3fSDimitry Andric X86::FR64XRegClass.hasSubClassEq(&RC) || 615f757f3fSDimitry Andric X86::VR128XRegClass.hasSubClassEq(&RC) || 625f757f3fSDimitry Andric X86::VR256XRegClass.hasSubClassEq(&RC) || 635f757f3fSDimitry Andric X86::VR512RegClass.hasSubClassEq(&RC)) 645f757f3fSDimitry Andric return getRegBank(X86::VECRRegBankID); 655f757f3fSDimitry Andric 66*0fca6ea1SDimitry Andric if (X86::RFP80RegClass.hasSubClassEq(&RC) || 67*0fca6ea1SDimitry Andric X86::RFP32RegClass.hasSubClassEq(&RC) || 68*0fca6ea1SDimitry Andric X86::RFP64RegClass.hasSubClassEq(&RC)) 69*0fca6ea1SDimitry Andric return getRegBank(X86::PSRRegBankID); 70*0fca6ea1SDimitry Andric 715f757f3fSDimitry Andric llvm_unreachable("Unsupported register kind yet."); 725f757f3fSDimitry Andric } 735f757f3fSDimitry Andric 74*0fca6ea1SDimitry Andric // \returns true if a given intrinsic only uses and defines FPRs. 75*0fca6ea1SDimitry Andric static bool isFPIntrinsic(const MachineRegisterInfo &MRI, 76*0fca6ea1SDimitry Andric const MachineInstr &MI) { 77*0fca6ea1SDimitry Andric // TODO: Add more intrinsics. 78*0fca6ea1SDimitry Andric switch (cast<GIntrinsic>(MI).getIntrinsicID()) { 79*0fca6ea1SDimitry Andric default: 80*0fca6ea1SDimitry Andric return false; 81*0fca6ea1SDimitry Andric // SSE1 82*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_rcp_ss: 83*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_rcp_ps: 84*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_rsqrt_ss: 85*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_rsqrt_ps: 86*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_min_ss: 87*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_min_ps: 88*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_max_ss: 89*0fca6ea1SDimitry Andric case Intrinsic::x86_sse_max_ps: 90*0fca6ea1SDimitry Andric return true; 91*0fca6ea1SDimitry Andric } 92*0fca6ea1SDimitry Andric return false; 93*0fca6ea1SDimitry Andric } 94*0fca6ea1SDimitry Andric 95*0fca6ea1SDimitry Andric bool X86RegisterBankInfo::hasFPConstraints(const MachineInstr &MI, 96*0fca6ea1SDimitry Andric const MachineRegisterInfo &MRI, 97*0fca6ea1SDimitry Andric const TargetRegisterInfo &TRI, 98*0fca6ea1SDimitry Andric unsigned Depth) const { 99*0fca6ea1SDimitry Andric unsigned Op = MI.getOpcode(); 100*0fca6ea1SDimitry Andric if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MRI, MI)) 101*0fca6ea1SDimitry Andric return true; 102*0fca6ea1SDimitry Andric 103*0fca6ea1SDimitry Andric // Do we have an explicit floating point instruction? 104*0fca6ea1SDimitry Andric if (isPreISelGenericFloatingPointOpcode(Op)) 105*0fca6ea1SDimitry Andric return true; 106*0fca6ea1SDimitry Andric 107*0fca6ea1SDimitry Andric // No. Check if we have a copy-like instruction. If we do, then we could 108*0fca6ea1SDimitry Andric // still be fed by floating point instructions. 109*0fca6ea1SDimitry Andric if (Op != TargetOpcode::COPY && !MI.isPHI() && 110*0fca6ea1SDimitry Andric !isPreISelGenericOptimizationHint(Op)) 111*0fca6ea1SDimitry Andric return false; 112*0fca6ea1SDimitry Andric 113*0fca6ea1SDimitry Andric // Check if we already know the register bank. 114*0fca6ea1SDimitry Andric auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI); 115*0fca6ea1SDimitry Andric if (RB == &getRegBank(X86::PSRRegBankID)) 116*0fca6ea1SDimitry Andric return true; 117*0fca6ea1SDimitry Andric if (RB == &getRegBank(X86::GPRRegBankID)) 118*0fca6ea1SDimitry Andric return false; 119*0fca6ea1SDimitry Andric 120*0fca6ea1SDimitry Andric // We don't know anything. 121*0fca6ea1SDimitry Andric // 122*0fca6ea1SDimitry Andric // If we have a phi, we may be able to infer that it will be assigned a fp 123*0fca6ea1SDimitry Andric // type based off of its inputs. 124*0fca6ea1SDimitry Andric if (!MI.isPHI() || Depth > MaxFPRSearchDepth) 125*0fca6ea1SDimitry Andric return false; 126*0fca6ea1SDimitry Andric 127*0fca6ea1SDimitry Andric return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) { 128*0fca6ea1SDimitry Andric return Op.isReg() && 129*0fca6ea1SDimitry Andric onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1); 130*0fca6ea1SDimitry Andric }); 131*0fca6ea1SDimitry Andric } 132*0fca6ea1SDimitry Andric 133*0fca6ea1SDimitry Andric bool X86RegisterBankInfo::onlyUsesFP(const MachineInstr &MI, 134*0fca6ea1SDimitry Andric const MachineRegisterInfo &MRI, 135*0fca6ea1SDimitry Andric const TargetRegisterInfo &TRI, 136*0fca6ea1SDimitry Andric unsigned Depth) const { 137*0fca6ea1SDimitry Andric switch (MI.getOpcode()) { 138*0fca6ea1SDimitry Andric case TargetOpcode::G_FPTOSI: 139*0fca6ea1SDimitry Andric case TargetOpcode::G_FPTOUI: 140*0fca6ea1SDimitry Andric case TargetOpcode::G_FCMP: 141*0fca6ea1SDimitry Andric case TargetOpcode::G_LROUND: 142*0fca6ea1SDimitry Andric case TargetOpcode::G_LLROUND: 143*0fca6ea1SDimitry Andric case TargetOpcode::G_INTRINSIC_TRUNC: 144*0fca6ea1SDimitry Andric case TargetOpcode::G_INTRINSIC_ROUND: 145*0fca6ea1SDimitry Andric return true; 146*0fca6ea1SDimitry Andric default: 147*0fca6ea1SDimitry Andric break; 148*0fca6ea1SDimitry Andric } 149*0fca6ea1SDimitry Andric return hasFPConstraints(MI, MRI, TRI, Depth); 150*0fca6ea1SDimitry Andric } 151*0fca6ea1SDimitry Andric 152*0fca6ea1SDimitry Andric bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI, 153*0fca6ea1SDimitry Andric const MachineRegisterInfo &MRI, 154*0fca6ea1SDimitry Andric const TargetRegisterInfo &TRI, 155*0fca6ea1SDimitry Andric unsigned Depth) const { 156*0fca6ea1SDimitry Andric switch (MI.getOpcode()) { 157*0fca6ea1SDimitry Andric case TargetOpcode::G_SITOFP: 158*0fca6ea1SDimitry Andric case TargetOpcode::G_UITOFP: 159*0fca6ea1SDimitry Andric return true; 160*0fca6ea1SDimitry Andric default: 161*0fca6ea1SDimitry Andric break; 162*0fca6ea1SDimitry Andric } 163*0fca6ea1SDimitry Andric return hasFPConstraints(MI, MRI, TRI, Depth); 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric 1665f757f3fSDimitry Andric X86GenRegisterBankInfo::PartialMappingIdx 167*0fca6ea1SDimitry Andric X86GenRegisterBankInfo::getPartialMappingIdx(const MachineInstr &MI, 168*0fca6ea1SDimitry Andric const LLT &Ty, bool isFP) { 169*0fca6ea1SDimitry Andric const MachineFunction *MF = MI.getMF(); 170*0fca6ea1SDimitry Andric const X86Subtarget *ST = &MF->getSubtarget<X86Subtarget>(); 171*0fca6ea1SDimitry Andric bool HasSSE1 = ST->hasSSE1(); 172*0fca6ea1SDimitry Andric bool HasSSE2 = ST->hasSSE2(); 173*0fca6ea1SDimitry Andric // 80 bits is only generated for X87 floating points. 174*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() == 80) 175*0fca6ea1SDimitry Andric isFP = true; 1765f757f3fSDimitry Andric if ((Ty.isScalar() && !isFP) || Ty.isPointer()) { 1775f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 1785f757f3fSDimitry Andric case 1: 1795f757f3fSDimitry Andric case 8: 1805f757f3fSDimitry Andric return PMI_GPR8; 1815f757f3fSDimitry Andric case 16: 1825f757f3fSDimitry Andric return PMI_GPR16; 1835f757f3fSDimitry Andric case 32: 1845f757f3fSDimitry Andric return PMI_GPR32; 1855f757f3fSDimitry Andric case 64: 1865f757f3fSDimitry Andric return PMI_GPR64; 1875f757f3fSDimitry Andric case 128: 1885f757f3fSDimitry Andric return PMI_VEC128; 1895f757f3fSDimitry Andric break; 1905f757f3fSDimitry Andric default: 1915f757f3fSDimitry Andric llvm_unreachable("Unsupported register size."); 1925f757f3fSDimitry Andric } 1935f757f3fSDimitry Andric } else if (Ty.isScalar()) { 1945f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 1955f757f3fSDimitry Andric case 32: 196*0fca6ea1SDimitry Andric return HasSSE1 ? PMI_FP32 : PMI_PSR32; 1975f757f3fSDimitry Andric case 64: 198*0fca6ea1SDimitry Andric return HasSSE2 ? PMI_FP64 : PMI_PSR64; 1995f757f3fSDimitry Andric case 128: 2005f757f3fSDimitry Andric return PMI_VEC128; 201*0fca6ea1SDimitry Andric case 80: 202*0fca6ea1SDimitry Andric return PMI_PSR80; 2035f757f3fSDimitry Andric default: 2045f757f3fSDimitry Andric llvm_unreachable("Unsupported register size."); 2055f757f3fSDimitry Andric } 2065f757f3fSDimitry Andric } else { 2075f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 2085f757f3fSDimitry Andric case 128: 2095f757f3fSDimitry Andric return PMI_VEC128; 2105f757f3fSDimitry Andric case 256: 2115f757f3fSDimitry Andric return PMI_VEC256; 2125f757f3fSDimitry Andric case 512: 2135f757f3fSDimitry Andric return PMI_VEC512; 2145f757f3fSDimitry Andric default: 2155f757f3fSDimitry Andric llvm_unreachable("Unsupported register size."); 2165f757f3fSDimitry Andric } 2175f757f3fSDimitry Andric } 2185f757f3fSDimitry Andric 2195f757f3fSDimitry Andric return PMI_None; 2205f757f3fSDimitry Andric } 2215f757f3fSDimitry Andric 2225f757f3fSDimitry Andric void X86RegisterBankInfo::getInstrPartialMappingIdxs( 2235f757f3fSDimitry Andric const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP, 2245f757f3fSDimitry Andric SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) { 2255f757f3fSDimitry Andric 2265f757f3fSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 2275f757f3fSDimitry Andric for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 2285f757f3fSDimitry Andric auto &MO = MI.getOperand(Idx); 2295f757f3fSDimitry Andric if (!MO.isReg() || !MO.getReg()) 2305f757f3fSDimitry Andric OpRegBankIdx[Idx] = PMI_None; 2315f757f3fSDimitry Andric else 232*0fca6ea1SDimitry Andric OpRegBankIdx[Idx] = 233*0fca6ea1SDimitry Andric getPartialMappingIdx(MI, MRI.getType(MO.getReg()), isFP); 2345f757f3fSDimitry Andric } 2355f757f3fSDimitry Andric } 2365f757f3fSDimitry Andric 2375f757f3fSDimitry Andric bool X86RegisterBankInfo::getInstrValueMapping( 2385f757f3fSDimitry Andric const MachineInstr &MI, 2395f757f3fSDimitry Andric const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx, 2405f757f3fSDimitry Andric SmallVectorImpl<const ValueMapping *> &OpdsMapping) { 2415f757f3fSDimitry Andric 2425f757f3fSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 2435f757f3fSDimitry Andric for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 2445f757f3fSDimitry Andric if (!MI.getOperand(Idx).isReg()) 2455f757f3fSDimitry Andric continue; 2465f757f3fSDimitry Andric if (!MI.getOperand(Idx).getReg()) 2475f757f3fSDimitry Andric continue; 2485f757f3fSDimitry Andric 2495f757f3fSDimitry Andric auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1); 2505f757f3fSDimitry Andric if (!Mapping->isValid()) 2515f757f3fSDimitry Andric return false; 2525f757f3fSDimitry Andric 2535f757f3fSDimitry Andric OpdsMapping[Idx] = Mapping; 2545f757f3fSDimitry Andric } 2555f757f3fSDimitry Andric return true; 2565f757f3fSDimitry Andric } 2575f757f3fSDimitry Andric 2585f757f3fSDimitry Andric const RegisterBankInfo::InstructionMapping & 2595f757f3fSDimitry Andric X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI, 2605f757f3fSDimitry Andric bool isFP) const { 2615f757f3fSDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 2625f757f3fSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 2635f757f3fSDimitry Andric 2645f757f3fSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 2655f757f3fSDimitry Andric LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 2665f757f3fSDimitry Andric 2675f757f3fSDimitry Andric if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) || 2685f757f3fSDimitry Andric (Ty != MRI.getType(MI.getOperand(2).getReg()))) 2695f757f3fSDimitry Andric llvm_unreachable("Unsupported operand mapping yet."); 2705f757f3fSDimitry Andric 271*0fca6ea1SDimitry Andric auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, isFP), 3); 2725f757f3fSDimitry Andric return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands); 2735f757f3fSDimitry Andric } 2745f757f3fSDimitry Andric 2755f757f3fSDimitry Andric const RegisterBankInfo::InstructionMapping & 2765f757f3fSDimitry Andric X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { 2775f757f3fSDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 278*0fca6ea1SDimitry Andric const TargetSubtargetInfo &STI = MF.getSubtarget(); 279*0fca6ea1SDimitry Andric const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 2805f757f3fSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 2815f757f3fSDimitry Andric unsigned Opc = MI.getOpcode(); 2825f757f3fSDimitry Andric 283*0fca6ea1SDimitry Andric // Try the default logic for non-generic instructions that are either 284*0fca6ea1SDimitry Andric // copies or already have some operands assigned to banks. 2855f757f3fSDimitry Andric if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) { 2865f757f3fSDimitry Andric const InstructionMapping &Mapping = getInstrMappingImpl(MI); 2875f757f3fSDimitry Andric if (Mapping.isValid()) 2885f757f3fSDimitry Andric return Mapping; 2895f757f3fSDimitry Andric } 2905f757f3fSDimitry Andric 2915f757f3fSDimitry Andric switch (Opc) { 2925f757f3fSDimitry Andric case TargetOpcode::G_ADD: 2935f757f3fSDimitry Andric case TargetOpcode::G_SUB: 2945f757f3fSDimitry Andric case TargetOpcode::G_MUL: 2955f757f3fSDimitry Andric return getSameOperandsMapping(MI, false); 2965f757f3fSDimitry Andric case TargetOpcode::G_FADD: 2975f757f3fSDimitry Andric case TargetOpcode::G_FSUB: 2985f757f3fSDimitry Andric case TargetOpcode::G_FMUL: 2995f757f3fSDimitry Andric case TargetOpcode::G_FDIV: 3005f757f3fSDimitry Andric return getSameOperandsMapping(MI, true); 3015f757f3fSDimitry Andric case TargetOpcode::G_SHL: 3025f757f3fSDimitry Andric case TargetOpcode::G_LSHR: 3035f757f3fSDimitry Andric case TargetOpcode::G_ASHR: { 3045f757f3fSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 3055f757f3fSDimitry Andric LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 3065f757f3fSDimitry Andric 307*0fca6ea1SDimitry Andric auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, false), 3); 3085f757f3fSDimitry Andric return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands); 3095f757f3fSDimitry Andric } 3105f757f3fSDimitry Andric default: 3115f757f3fSDimitry Andric break; 3125f757f3fSDimitry Andric } 3135f757f3fSDimitry Andric 3145f757f3fSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 3155f757f3fSDimitry Andric SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); 3165f757f3fSDimitry Andric 3175f757f3fSDimitry Andric switch (Opc) { 3185f757f3fSDimitry Andric case TargetOpcode::G_FPEXT: 3195f757f3fSDimitry Andric case TargetOpcode::G_FPTRUNC: 3205f757f3fSDimitry Andric case TargetOpcode::G_FCONSTANT: 321*0fca6ea1SDimitry Andric // Instruction having only floating-point operands (all scalars in 322*0fca6ea1SDimitry Andric // VECRReg) 323*0fca6ea1SDimitry Andric getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx); 3245f757f3fSDimitry Andric break; 3255f757f3fSDimitry Andric case TargetOpcode::G_SITOFP: 3265f757f3fSDimitry Andric case TargetOpcode::G_FPTOSI: { 327*0fca6ea1SDimitry Andric // Some of the floating-point instructions have mixed GPR and FP 328*0fca6ea1SDimitry Andric // operands: fine-tune the computed mapping. 3295f757f3fSDimitry Andric auto &Op0 = MI.getOperand(0); 3305f757f3fSDimitry Andric auto &Op1 = MI.getOperand(1); 3315f757f3fSDimitry Andric const LLT Ty0 = MRI.getType(Op0.getReg()); 3325f757f3fSDimitry Andric const LLT Ty1 = MRI.getType(Op1.getReg()); 3335f757f3fSDimitry Andric 3345f757f3fSDimitry Andric bool FirstArgIsFP = Opc == TargetOpcode::G_SITOFP; 3355f757f3fSDimitry Andric bool SecondArgIsFP = Opc == TargetOpcode::G_FPTOSI; 336*0fca6ea1SDimitry Andric OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ FirstArgIsFP); 337*0fca6ea1SDimitry Andric OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ SecondArgIsFP); 3385f757f3fSDimitry Andric break; 3395f757f3fSDimitry Andric } 3405f757f3fSDimitry Andric case TargetOpcode::G_FCMP: { 3415f757f3fSDimitry Andric LLT Ty1 = MRI.getType(MI.getOperand(2).getReg()); 3425f757f3fSDimitry Andric LLT Ty2 = MRI.getType(MI.getOperand(3).getReg()); 3435f757f3fSDimitry Andric (void)Ty2; 3445f757f3fSDimitry Andric assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() && 3455f757f3fSDimitry Andric "Mismatched operand sizes for G_FCMP"); 3465f757f3fSDimitry Andric 3475f757f3fSDimitry Andric unsigned Size = Ty1.getSizeInBits(); 3485f757f3fSDimitry Andric (void)Size; 3495f757f3fSDimitry Andric assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP"); 3505f757f3fSDimitry Andric 351*0fca6ea1SDimitry Andric auto FpRegBank = getPartialMappingIdx(MI, Ty1, /* isFP= */ true); 3525f757f3fSDimitry Andric OpRegBankIdx = {PMI_GPR8, 3535f757f3fSDimitry Andric /* Predicate */ PMI_None, FpRegBank, FpRegBank}; 3545f757f3fSDimitry Andric break; 3555f757f3fSDimitry Andric } 3565f757f3fSDimitry Andric case TargetOpcode::G_TRUNC: 3575f757f3fSDimitry Andric case TargetOpcode::G_ANYEXT: { 3585f757f3fSDimitry Andric auto &Op0 = MI.getOperand(0); 3595f757f3fSDimitry Andric auto &Op1 = MI.getOperand(1); 3605f757f3fSDimitry Andric const LLT Ty0 = MRI.getType(Op0.getReg()); 3615f757f3fSDimitry Andric const LLT Ty1 = MRI.getType(Op1.getReg()); 3625f757f3fSDimitry Andric 3635f757f3fSDimitry Andric bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) && 3645f757f3fSDimitry Andric Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC; 3655f757f3fSDimitry Andric bool isFPAnyExt = 3665f757f3fSDimitry Andric Ty0.getSizeInBits() == 128 && 3675f757f3fSDimitry Andric (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) && 3685f757f3fSDimitry Andric Opc == TargetOpcode::G_ANYEXT; 3695f757f3fSDimitry Andric 370*0fca6ea1SDimitry Andric getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt, 3715f757f3fSDimitry Andric OpRegBankIdx); 372*0fca6ea1SDimitry Andric break; 373*0fca6ea1SDimitry Andric } 374*0fca6ea1SDimitry Andric case TargetOpcode::G_LOAD: { 375*0fca6ea1SDimitry Andric // Check if that load feeds fp instructions. 376*0fca6ea1SDimitry Andric // In that case, we want the default mapping to be on FPR 377*0fca6ea1SDimitry Andric // instead of blind map every scalar to GPR. 378*0fca6ea1SDimitry Andric bool IsFP = any_of(MRI.use_nodbg_instructions(cast<GLoad>(MI).getDstReg()), 379*0fca6ea1SDimitry Andric [&](const MachineInstr &UseMI) { 380*0fca6ea1SDimitry Andric // If we have at least one direct use in a FP 381*0fca6ea1SDimitry Andric // instruction, assume this was a floating point load 382*0fca6ea1SDimitry Andric // in the IR. If it was not, we would have had a 383*0fca6ea1SDimitry Andric // bitcast before reaching that instruction. 384*0fca6ea1SDimitry Andric return onlyUsesFP(UseMI, MRI, TRI); 385*0fca6ea1SDimitry Andric }); 386*0fca6ea1SDimitry Andric getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx); 387*0fca6ea1SDimitry Andric break; 388*0fca6ea1SDimitry Andric } 389*0fca6ea1SDimitry Andric case TargetOpcode::G_STORE: { 390*0fca6ea1SDimitry Andric // Check if that store is fed by fp instructions. 391*0fca6ea1SDimitry Andric Register VReg = cast<GStore>(MI).getValueReg(); 392*0fca6ea1SDimitry Andric if (!VReg) 393*0fca6ea1SDimitry Andric break; 394*0fca6ea1SDimitry Andric MachineInstr *DefMI = MRI.getVRegDef(VReg); 395*0fca6ea1SDimitry Andric bool IsFP = onlyDefinesFP(*DefMI, MRI, TRI); 396*0fca6ea1SDimitry Andric getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx); 397*0fca6ea1SDimitry Andric break; 398*0fca6ea1SDimitry Andric } 3995f757f3fSDimitry Andric default: 400*0fca6ea1SDimitry Andric // Track the bank of each register, use NotFP mapping (all scalars in 401*0fca6ea1SDimitry Andric // GPRs) 402*0fca6ea1SDimitry Andric getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx); 4035f757f3fSDimitry Andric break; 4045f757f3fSDimitry Andric } 4055f757f3fSDimitry Andric 4065f757f3fSDimitry Andric // Finally construct the computed mapping. 4075f757f3fSDimitry Andric SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 4085f757f3fSDimitry Andric if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping)) 4095f757f3fSDimitry Andric return getInvalidInstructionMapping(); 4105f757f3fSDimitry Andric 4115f757f3fSDimitry Andric return getInstructionMapping(DefaultMappingID, /* Cost */ 1, 4125f757f3fSDimitry Andric getOperandsMapping(OpdsMapping), NumOperands); 4135f757f3fSDimitry Andric } 4145f757f3fSDimitry Andric 4155f757f3fSDimitry Andric void X86RegisterBankInfo::applyMappingImpl( 4165f757f3fSDimitry Andric MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const { 4175f757f3fSDimitry Andric return applyDefaultMapping(OpdMapper); 4185f757f3fSDimitry Andric } 4195f757f3fSDimitry Andric 4205f757f3fSDimitry Andric RegisterBankInfo::InstructionMappings 4215f757f3fSDimitry Andric X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const { 4225f757f3fSDimitry Andric 4235f757f3fSDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 4245f757f3fSDimitry Andric const TargetSubtargetInfo &STI = MF.getSubtarget(); 4255f757f3fSDimitry Andric const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 4265f757f3fSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 4275f757f3fSDimitry Andric 4285f757f3fSDimitry Andric switch (MI.getOpcode()) { 4295f757f3fSDimitry Andric case TargetOpcode::G_LOAD: 4305f757f3fSDimitry Andric case TargetOpcode::G_STORE: 4315f757f3fSDimitry Andric case TargetOpcode::G_IMPLICIT_DEF: { 432*0fca6ea1SDimitry Andric // we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80 4335f757f3fSDimitry Andric unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 434*0fca6ea1SDimitry Andric if (Size != 32 && Size != 64 && Size != 80) 4355f757f3fSDimitry Andric break; 4365f757f3fSDimitry Andric 4375f757f3fSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 4385f757f3fSDimitry Andric 4395f757f3fSDimitry Andric // Track the bank of each register, use FP mapping (all scalars in VEC) 4405f757f3fSDimitry Andric SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); 441*0fca6ea1SDimitry Andric getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx); 4425f757f3fSDimitry Andric 4435f757f3fSDimitry Andric // Finally construct the computed mapping. 4445f757f3fSDimitry Andric SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 4455f757f3fSDimitry Andric if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping)) 4465f757f3fSDimitry Andric break; 4475f757f3fSDimitry Andric 4485f757f3fSDimitry Andric const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping( 4495f757f3fSDimitry Andric /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands); 4505f757f3fSDimitry Andric InstructionMappings AltMappings; 4515f757f3fSDimitry Andric AltMappings.push_back(&Mapping); 4525f757f3fSDimitry Andric return AltMappings; 4535f757f3fSDimitry Andric } 4545f757f3fSDimitry Andric default: 4555f757f3fSDimitry Andric break; 4565f757f3fSDimitry Andric } 4575f757f3fSDimitry Andric return RegisterBankInfo::getInstrAlternativeMappings(MI); 4585f757f3fSDimitry Andric } 459