blob: 9c076d2d67694ac653f3bd0ee7e730e1569af2fb [file] [log] [blame]
//===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the RegisterBankInfo class for X86.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//
#include "X86RegisterBankInfo.h"
#include "X86InstrInfo.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#define GET_TARGET_REGBANK_IMPL
#include "X86GenRegisterBank.inc"
using namespace llvm;
// This file will be TableGen'ed at some point.
#define GET_TARGET_REGBANK_INFO_IMPL
#include "X86GenRegisterBankInfo.def"
X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI)
: X86GenRegisterBankInfo() {
// validate RegBank initialization.
const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID);
(void)RBGPR;
assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization.");
// The GPR register bank is fully defined by all the registers in
// GR64 + its subclasses.
assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) &&
"Subclass not added?");
assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit");
}
const RegisterBank &
X86RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
LLT) const {
if (X86::GR8RegClass.hasSubClassEq(&RC) ||
X86::GR16RegClass.hasSubClassEq(&RC) ||
X86::GR32RegClass.hasSubClassEq(&RC) ||
X86::GR64RegClass.hasSubClassEq(&RC) ||
X86::LOW32_ADDR_ACCESSRegClass.hasSubClassEq(&RC) ||
X86::LOW32_ADDR_ACCESS_RBPRegClass.hasSubClassEq(&RC))
return getRegBank(X86::GPRRegBankID);
if (X86::FR32XRegClass.hasSubClassEq(&RC) ||
X86::FR64XRegClass.hasSubClassEq(&RC) ||
X86::VR128XRegClass.hasSubClassEq(&RC) ||
X86::VR256XRegClass.hasSubClassEq(&RC) ||
X86::VR512RegClass.hasSubClassEq(&RC))
return getRegBank(X86::VECRRegBankID);
llvm_unreachable("Unsupported register kind yet.");
}
X86GenRegisterBankInfo::PartialMappingIdx
X86GenRegisterBankInfo::getPartialMappingIdx(const LLT &Ty, bool isFP) {
if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {
switch (Ty.getSizeInBits()) {
case 1:
case 8:
return PMI_GPR8;
case 16:
return PMI_GPR16;
case 32:
return PMI_GPR32;
case 64:
return PMI_GPR64;
case 128:
return PMI_VEC128;
break;
default:
llvm_unreachable("Unsupported register size.");
}
} else if (Ty.isScalar()) {
switch (Ty.getSizeInBits()) {
case 32:
return PMI_FP32;
case 64:
return PMI_FP64;
case 128:
return PMI_VEC128;
default:
llvm_unreachable("Unsupported register size.");
}
} else {
switch (Ty.getSizeInBits()) {
case 128:
return PMI_VEC128;
case 256:
return PMI_VEC256;
case 512:
return PMI_VEC512;
default:
llvm_unreachable("Unsupported register size.");
}
}
return PMI_None;
}
void X86RegisterBankInfo::getInstrPartialMappingIdxs(
const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,
SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {
unsigned NumOperands = MI.getNumOperands();
for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
auto &MO = MI.getOperand(Idx);
if (!MO.isReg())
OpRegBankIdx[Idx] = PMI_None;
else
OpRegBankIdx[Idx] = getPartialMappingIdx(MRI.getType(MO.getReg()), isFP);
}
}
bool X86RegisterBankInfo::getInstrValueMapping(
const MachineInstr &MI,
const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
SmallVectorImpl<const ValueMapping *> &OpdsMapping) {
unsigned NumOperands = MI.getNumOperands();
for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
if (!MI.getOperand(Idx).isReg())
continue;
auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);
if (!Mapping->isValid())
return false;
OpdsMapping[Idx] = Mapping;
}
return true;
}
const RegisterBankInfo::InstructionMapping &
X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,
bool isFP) const {
const MachineFunction &MF = *MI.getParent()->getParent();
const MachineRegisterInfo &MRI = MF.getRegInfo();
unsigned NumOperands = MI.getNumOperands();
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||
(Ty != MRI.getType(MI.getOperand(2).getReg())))
llvm_unreachable("Unsupported operand mapping yet.");
auto Mapping = getValueMapping(getPartialMappingIdx(Ty, isFP), 3);
return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
}
const RegisterBankInfo::InstructionMapping &
X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
const MachineFunction &MF = *MI.getParent()->getParent();
const MachineRegisterInfo &MRI = MF.getRegInfo();
unsigned Opc = MI.getOpcode();
// Try the default logic for non-generic instructions that are either copies
// or already have some operands assigned to banks.
if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
const InstructionMapping &Mapping = getInstrMappingImpl(MI);
if (Mapping.isValid())
return Mapping;
}
switch (Opc) {
case TargetOpcode::G_ADD:
case TargetOpcode::G_SUB:
case TargetOpcode::G_MUL:
return getSameOperandsMapping(MI, false);
case TargetOpcode::G_FADD:
case TargetOpcode::G_FSUB:
case TargetOpcode::G_FMUL:
case TargetOpcode::G_FDIV:
return getSameOperandsMapping(MI, true);
case TargetOpcode::G_SHL:
case TargetOpcode::G_LSHR:
case TargetOpcode::G_ASHR: {
unsigned NumOperands = MI.getNumOperands();
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
auto Mapping = getValueMapping(getPartialMappingIdx(Ty, false), 3);
return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
}
default:
break;
}
unsigned NumOperands = MI.getNumOperands();
SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
switch (Opc) {
case TargetOpcode::G_FPEXT:
case TargetOpcode::G_FPTRUNC:
case TargetOpcode::G_FCONSTANT:
// Instruction having only floating-point operands (all scalars in VECRReg)
getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx);
break;
case TargetOpcode::G_SITOFP:
case TargetOpcode::G_FPTOSI: {
// Some of the floating-point instructions have mixed GPR and FP operands:
// fine-tune the computed mapping.
auto &Op0 = MI.getOperand(0);
auto &Op1 = MI.getOperand(1);
const LLT Ty0 = MRI.getType(Op0.getReg());
const LLT Ty1 = MRI.getType(Op1.getReg());
bool FirstArgIsFP = Opc == TargetOpcode::G_SITOFP;
bool SecondArgIsFP = Opc == TargetOpcode::G_FPTOSI;
OpRegBankIdx[0] = getPartialMappingIdx(Ty0, /* isFP */ FirstArgIsFP);
OpRegBankIdx[1] = getPartialMappingIdx(Ty1, /* isFP */ SecondArgIsFP);
break;
}
case TargetOpcode::G_FCMP: {
LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
(void)Ty2;
assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
"Mismatched operand sizes for G_FCMP");
unsigned Size = Ty1.getSizeInBits();
(void)Size;
assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
auto FpRegBank = getPartialMappingIdx(Ty1, /* isFP */ true);
OpRegBankIdx = {PMI_GPR8,
/* Predicate */ PMI_None, FpRegBank, FpRegBank};
break;
}
case TargetOpcode::G_TRUNC:
case TargetOpcode::G_ANYEXT: {
auto &Op0 = MI.getOperand(0);
auto &Op1 = MI.getOperand(1);
const LLT Ty0 = MRI.getType(Op0.getReg());
const LLT Ty1 = MRI.getType(Op1.getReg());
bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&
Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;
bool isFPAnyExt =
Ty0.getSizeInBits() == 128 &&
(Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&
Opc == TargetOpcode::G_ANYEXT;
getInstrPartialMappingIdxs(MI, MRI, /* isFP */ isFPTrunc || isFPAnyExt,
OpRegBankIdx);
} break;
default:
// Track the bank of each register, use NotFP mapping (all scalars in GPRs)
getInstrPartialMappingIdxs(MI, MRI, /* isFP */ false, OpRegBankIdx);
break;
}
// Finally construct the computed mapping.
SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
return getInvalidInstructionMapping();
return getInstructionMapping(DefaultMappingID, /* Cost */ 1,
getOperandsMapping(OpdsMapping), NumOperands);
}
void X86RegisterBankInfo::applyMappingImpl(
const OperandsMapper &OpdMapper) const {
return applyDefaultMapping(OpdMapper);
}
RegisterBankInfo::InstructionMappings
X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
const MachineFunction &MF = *MI.getParent()->getParent();
const TargetSubtargetInfo &STI = MF.getSubtarget();
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
const MachineRegisterInfo &MRI = MF.getRegInfo();
switch (MI.getOpcode()) {
case TargetOpcode::G_LOAD:
case TargetOpcode::G_STORE:
case TargetOpcode::G_IMPLICIT_DEF: {
// we going to try to map 32/64 bit to PMI_FP32/PMI_FP64
unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
if (Size != 32 && Size != 64)
break;
unsigned NumOperands = MI.getNumOperands();
// Track the bank of each register, use FP mapping (all scalars in VEC)
SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx);
// Finally construct the computed mapping.
SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
break;
const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(
/*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);
InstructionMappings AltMappings;
AltMappings.push_back(&Mapping);
return AltMappings;
}
default:
break;
}
return RegisterBankInfo::getInstrAlternativeMappings(MI);
}