Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp
96383 views
//===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8/// This file implements the targeting of the RegisterBankInfo class for X86.9/// \todo This should be generated by TableGen.10//===----------------------------------------------------------------------===//1112#include "X86RegisterBankInfo.h"13#include "X86InstrInfo.h"14#include "X86Subtarget.h"15#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"16#include "llvm/CodeGen/GlobalISel/Utils.h"17#include "llvm/CodeGen/MachineRegisterInfo.h"18#include "llvm/CodeGen/RegisterBank.h"19#include "llvm/CodeGen/RegisterBankInfo.h"20#include "llvm/CodeGen/TargetRegisterInfo.h"21#include "llvm/IR/IntrinsicsX86.h"2223#define GET_TARGET_REGBANK_IMPL24#include "X86GenRegisterBank.inc"2526using namespace llvm;27// This file will be TableGen'ed at some point.28#define GET_TARGET_REGBANK_INFO_IMPL29#include "X86GenRegisterBankInfo.def"3031X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI) {3233// validate RegBank initialization.34const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID);35(void)RBGPR;36assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization.");3738// The GPR register bank is fully defined by all the registers in39// GR64 + its subclasses.40assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) &&41"Subclass not added?");42assert(getMaximumSize(RBGPR.getID()) == 64 &&43"GPRs should hold up to 64-bit");44}4546const RegisterBank &47X86RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,48LLT) const {4950if (X86::GR8RegClass.hasSubClassEq(&RC) ||51X86::GR16RegClass.hasSubClassEq(&RC) ||52X86::GR32RegClass.hasSubClassEq(&RC) ||53X86::GR64RegClass.hasSubClassEq(&RC) ||54X86::LOW32_ADDR_ACCESSRegClass.hasSubClassEq(&RC) ||55X86::LOW32_ADDR_ACCESS_RBPRegClass.hasSubClassEq(&RC))56return getRegBank(X86::GPRRegBankID);5758if (X86::FR32XRegClass.hasSubClassEq(&RC) ||59X86::FR64XRegClass.hasSubClassEq(&RC) ||60X86::VR128XRegClass.hasSubClassEq(&RC) ||61X86::VR256XRegClass.hasSubClassEq(&RC) ||62X86::VR512RegClass.hasSubClassEq(&RC))63return getRegBank(X86::VECRRegBankID);6465if (X86::RFP80RegClass.hasSubClassEq(&RC) ||66X86::RFP32RegClass.hasSubClassEq(&RC) ||67X86::RFP64RegClass.hasSubClassEq(&RC))68return getRegBank(X86::PSRRegBankID);6970llvm_unreachable("Unsupported register kind yet.");71}7273// \returns true if a given intrinsic only uses and defines FPRs.74static bool isFPIntrinsic(const MachineRegisterInfo &MRI,75const MachineInstr &MI) {76// TODO: Add more intrinsics.77switch (cast<GIntrinsic>(MI).getIntrinsicID()) {78default:79return false;80// SSE181case Intrinsic::x86_sse_rcp_ss:82case Intrinsic::x86_sse_rcp_ps:83case Intrinsic::x86_sse_rsqrt_ss:84case Intrinsic::x86_sse_rsqrt_ps:85case Intrinsic::x86_sse_min_ss:86case Intrinsic::x86_sse_min_ps:87case Intrinsic::x86_sse_max_ss:88case Intrinsic::x86_sse_max_ps:89return true;90}91return false;92}9394bool X86RegisterBankInfo::hasFPConstraints(const MachineInstr &MI,95const MachineRegisterInfo &MRI,96const TargetRegisterInfo &TRI,97unsigned Depth) const {98unsigned Op = MI.getOpcode();99if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MRI, MI))100return true;101102// Do we have an explicit floating point instruction?103if (isPreISelGenericFloatingPointOpcode(Op))104return true;105106// No. Check if we have a copy-like instruction. If we do, then we could107// still be fed by floating point instructions.108if (Op != TargetOpcode::COPY && !MI.isPHI() &&109!isPreISelGenericOptimizationHint(Op))110return false;111112// Check if we already know the register bank.113auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI);114if (RB == &getRegBank(X86::PSRRegBankID))115return true;116if (RB == &getRegBank(X86::GPRRegBankID))117return false;118119// We don't know anything.120//121// If we have a phi, we may be able to infer that it will be assigned a fp122// type based off of its inputs.123if (!MI.isPHI() || Depth > MaxFPRSearchDepth)124return false;125126return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) {127return Op.isReg() &&128onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1);129});130}131132bool X86RegisterBankInfo::onlyUsesFP(const MachineInstr &MI,133const MachineRegisterInfo &MRI,134const TargetRegisterInfo &TRI,135unsigned Depth) const {136switch (MI.getOpcode()) {137case TargetOpcode::G_FPTOSI:138case TargetOpcode::G_FPTOUI:139case TargetOpcode::G_FCMP:140case TargetOpcode::G_LROUND:141case TargetOpcode::G_LLROUND:142case TargetOpcode::G_INTRINSIC_TRUNC:143case TargetOpcode::G_INTRINSIC_ROUND:144return true;145default:146break;147}148return hasFPConstraints(MI, MRI, TRI, Depth);149}150151bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,152const MachineRegisterInfo &MRI,153const TargetRegisterInfo &TRI,154unsigned Depth) const {155switch (MI.getOpcode()) {156case TargetOpcode::G_SITOFP:157case TargetOpcode::G_UITOFP:158return true;159default:160break;161}162return hasFPConstraints(MI, MRI, TRI, Depth);163}164165X86GenRegisterBankInfo::PartialMappingIdx166X86GenRegisterBankInfo::getPartialMappingIdx(const MachineInstr &MI,167const LLT &Ty, bool isFP) {168const MachineFunction *MF = MI.getMF();169const X86Subtarget *ST = &MF->getSubtarget<X86Subtarget>();170bool HasSSE1 = ST->hasSSE1();171bool HasSSE2 = ST->hasSSE2();172// 80 bits is only generated for X87 floating points.173if (Ty.getSizeInBits() == 80)174isFP = true;175if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {176switch (Ty.getSizeInBits()) {177case 1:178case 8:179return PMI_GPR8;180case 16:181return PMI_GPR16;182case 32:183return PMI_GPR32;184case 64:185return PMI_GPR64;186case 128:187return PMI_VEC128;188break;189default:190llvm_unreachable("Unsupported register size.");191}192} else if (Ty.isScalar()) {193switch (Ty.getSizeInBits()) {194case 32:195return HasSSE1 ? PMI_FP32 : PMI_PSR32;196case 64:197return HasSSE2 ? PMI_FP64 : PMI_PSR64;198case 128:199return PMI_VEC128;200case 80:201return PMI_PSR80;202default:203llvm_unreachable("Unsupported register size.");204}205} else {206switch (Ty.getSizeInBits()) {207case 128:208return PMI_VEC128;209case 256:210return PMI_VEC256;211case 512:212return PMI_VEC512;213default:214llvm_unreachable("Unsupported register size.");215}216}217218return PMI_None;219}220221void X86RegisterBankInfo::getInstrPartialMappingIdxs(222const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,223SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {224225unsigned NumOperands = MI.getNumOperands();226for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {227auto &MO = MI.getOperand(Idx);228if (!MO.isReg() || !MO.getReg())229OpRegBankIdx[Idx] = PMI_None;230else231OpRegBankIdx[Idx] =232getPartialMappingIdx(MI, MRI.getType(MO.getReg()), isFP);233}234}235236bool X86RegisterBankInfo::getInstrValueMapping(237const MachineInstr &MI,238const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,239SmallVectorImpl<const ValueMapping *> &OpdsMapping) {240241unsigned NumOperands = MI.getNumOperands();242for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {243if (!MI.getOperand(Idx).isReg())244continue;245if (!MI.getOperand(Idx).getReg())246continue;247248auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);249if (!Mapping->isValid())250return false;251252OpdsMapping[Idx] = Mapping;253}254return true;255}256257const RegisterBankInfo::InstructionMapping &258X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,259bool isFP) const {260const MachineFunction &MF = *MI.getParent()->getParent();261const MachineRegisterInfo &MRI = MF.getRegInfo();262263unsigned NumOperands = MI.getNumOperands();264LLT Ty = MRI.getType(MI.getOperand(0).getReg());265266if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||267(Ty != MRI.getType(MI.getOperand(2).getReg())))268llvm_unreachable("Unsupported operand mapping yet.");269270auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, isFP), 3);271return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);272}273274const RegisterBankInfo::InstructionMapping &275X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {276const MachineFunction &MF = *MI.getParent()->getParent();277const TargetSubtargetInfo &STI = MF.getSubtarget();278const TargetRegisterInfo &TRI = *STI.getRegisterInfo();279const MachineRegisterInfo &MRI = MF.getRegInfo();280unsigned Opc = MI.getOpcode();281282// Try the default logic for non-generic instructions that are either283// copies or already have some operands assigned to banks.284if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {285const InstructionMapping &Mapping = getInstrMappingImpl(MI);286if (Mapping.isValid())287return Mapping;288}289290switch (Opc) {291case TargetOpcode::G_ADD:292case TargetOpcode::G_SUB:293case TargetOpcode::G_MUL:294return getSameOperandsMapping(MI, false);295case TargetOpcode::G_FADD:296case TargetOpcode::G_FSUB:297case TargetOpcode::G_FMUL:298case TargetOpcode::G_FDIV:299return getSameOperandsMapping(MI, true);300case TargetOpcode::G_SHL:301case TargetOpcode::G_LSHR:302case TargetOpcode::G_ASHR: {303unsigned NumOperands = MI.getNumOperands();304LLT Ty = MRI.getType(MI.getOperand(0).getReg());305306auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, false), 3);307return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);308}309default:310break;311}312313unsigned NumOperands = MI.getNumOperands();314SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);315316switch (Opc) {317case TargetOpcode::G_FPEXT:318case TargetOpcode::G_FPTRUNC:319case TargetOpcode::G_FCONSTANT:320// Instruction having only floating-point operands (all scalars in321// VECRReg)322getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);323break;324case TargetOpcode::G_SITOFP:325case TargetOpcode::G_FPTOSI: {326// Some of the floating-point instructions have mixed GPR and FP327// operands: fine-tune the computed mapping.328auto &Op0 = MI.getOperand(0);329auto &Op1 = MI.getOperand(1);330const LLT Ty0 = MRI.getType(Op0.getReg());331const LLT Ty1 = MRI.getType(Op1.getReg());332333bool FirstArgIsFP = Opc == TargetOpcode::G_SITOFP;334bool SecondArgIsFP = Opc == TargetOpcode::G_FPTOSI;335OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ FirstArgIsFP);336OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ SecondArgIsFP);337break;338}339case TargetOpcode::G_FCMP: {340LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());341LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());342(void)Ty2;343assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&344"Mismatched operand sizes for G_FCMP");345346unsigned Size = Ty1.getSizeInBits();347(void)Size;348assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");349350auto FpRegBank = getPartialMappingIdx(MI, Ty1, /* isFP= */ true);351OpRegBankIdx = {PMI_GPR8,352/* Predicate */ PMI_None, FpRegBank, FpRegBank};353break;354}355case TargetOpcode::G_TRUNC:356case TargetOpcode::G_ANYEXT: {357auto &Op0 = MI.getOperand(0);358auto &Op1 = MI.getOperand(1);359const LLT Ty0 = MRI.getType(Op0.getReg());360const LLT Ty1 = MRI.getType(Op1.getReg());361362bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&363Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;364bool isFPAnyExt =365Ty0.getSizeInBits() == 128 &&366(Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&367Opc == TargetOpcode::G_ANYEXT;368369getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt,370OpRegBankIdx);371break;372}373case TargetOpcode::G_LOAD: {374// Check if that load feeds fp instructions.375// In that case, we want the default mapping to be on FPR376// instead of blind map every scalar to GPR.377bool IsFP = any_of(MRI.use_nodbg_instructions(cast<GLoad>(MI).getDstReg()),378[&](const MachineInstr &UseMI) {379// If we have at least one direct use in a FP380// instruction, assume this was a floating point load381// in the IR. If it was not, we would have had a382// bitcast before reaching that instruction.383return onlyUsesFP(UseMI, MRI, TRI);384});385getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);386break;387}388case TargetOpcode::G_STORE: {389// Check if that store is fed by fp instructions.390Register VReg = cast<GStore>(MI).getValueReg();391if (!VReg)392break;393MachineInstr *DefMI = MRI.getVRegDef(VReg);394bool IsFP = onlyDefinesFP(*DefMI, MRI, TRI);395getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);396break;397}398default:399// Track the bank of each register, use NotFP mapping (all scalars in400// GPRs)401getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx);402break;403}404405// Finally construct the computed mapping.406SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);407if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))408return getInvalidInstructionMapping();409410return getInstructionMapping(DefaultMappingID, /* Cost */ 1,411getOperandsMapping(OpdsMapping), NumOperands);412}413414void X86RegisterBankInfo::applyMappingImpl(415MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {416return applyDefaultMapping(OpdMapper);417}418419RegisterBankInfo::InstructionMappings420X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {421422const MachineFunction &MF = *MI.getParent()->getParent();423const TargetSubtargetInfo &STI = MF.getSubtarget();424const TargetRegisterInfo &TRI = *STI.getRegisterInfo();425const MachineRegisterInfo &MRI = MF.getRegInfo();426427switch (MI.getOpcode()) {428case TargetOpcode::G_LOAD:429case TargetOpcode::G_STORE:430case TargetOpcode::G_IMPLICIT_DEF: {431// we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80432unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);433if (Size != 32 && Size != 64 && Size != 80)434break;435436unsigned NumOperands = MI.getNumOperands();437438// Track the bank of each register, use FP mapping (all scalars in VEC)439SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);440getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);441442// Finally construct the computed mapping.443SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);444if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))445break;446447const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(448/*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);449InstructionMappings AltMappings;450AltMappings.push_back(&Mapping);451return AltMappings;452}453default:454break;455}456return RegisterBankInfo::getInstrAlternativeMappings(MI);457}458459460