blob: a6321f5951b8e087fc66f04a8cd16ab51351012c [file] [log] [blame]
//===-- SIRegisterInfo.h - SI Register Info Interface ----------*- 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
/// Interface definition for SIRegisterInfo
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_AMDGPU_SIREGISTERINFO_H
#define LLVM_LIB_TARGET_AMDGPU_SIREGISTERINFO_H
#define GET_REGINFO_HEADER
#include "AMDGPUGenRegisterInfo.inc"
#include "SIDefines.h"
namespace llvm {
class GCNSubtarget;
class LiveIntervals;
class LivePhysRegs;
class RegisterBank;
struct SGPRSpillBuilder;
class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
private:
const GCNSubtarget &ST;
bool SpillSGPRToVGPR;
bool isWave32;
BitVector RegPressureIgnoredUnits;
/// Sub reg indexes for getRegSplitParts.
/// First index represents subreg size from 1 to 16 DWORDs.
/// The inner vector is sorted by bit offset.
/// Provided a register can be fully split with given subregs,
/// all elements of the inner vector combined give a full lane mask.
static std::array<std::vector<int16_t>, 16> RegSplitParts;
// Table representing sub reg of given width and offset.
// First index is subreg size: 32, 64, 96, 128, 160, 192, 224, 256, 512.
// Second index is 32 different dword offsets.
static std::array<std::array<uint16_t, 32>, 9> SubRegFromChannelTable;
void reserveRegisterTuples(BitVector &, MCRegister Reg) const;
public:
SIRegisterInfo(const GCNSubtarget &ST);
/// \returns the sub reg enum value for the given \p Channel
/// (e.g. getSubRegFromChannel(0) -> AMDGPU::sub0)
static unsigned getSubRegFromChannel(unsigned Channel, unsigned NumRegs = 1);
bool spillSGPRToVGPR() const {
return SpillSGPRToVGPR;
}
/// Return the end register initially reserved for the scratch buffer in case
/// spilling is needed.
MCRegister reservedPrivateSegmentBufferReg(const MachineFunction &MF) const;
BitVector getReservedRegs(const MachineFunction &MF) const override;
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
const MCPhysReg *getCalleeSavedRegsViaCopy(const MachineFunction *MF) const;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const override;
const uint32_t *getNoPreservedMask() const override;
// Stack access is very expensive. CSRs are also the high registers, and we
// want to minimize the number of used registers.
unsigned getCSRFirstUseCost() const override {
return 100;
}
const TargetRegisterClass *
getLargestLegalSuperClass(const TargetRegisterClass *RC,
const MachineFunction &MF) const override;
Register getFrameRegister(const MachineFunction &MF) const override;
bool hasBasePointer(const MachineFunction &MF) const;
Register getBaseRegister() const;
bool shouldRealignStack(const MachineFunction &MF) const override;
bool requiresRegisterScavenging(const MachineFunction &Fn) const override;
bool requiresFrameIndexScavenging(const MachineFunction &MF) const override;
bool requiresFrameIndexReplacementScavenging(
const MachineFunction &MF) const override;
bool requiresVirtualBaseRegisters(const MachineFunction &Fn) const override;
int64_t getScratchInstrOffset(const MachineInstr *MI) const;
int64_t getFrameIndexInstrOffset(const MachineInstr *MI,
int Idx) const override;
bool needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const override;
Register materializeFrameBaseRegister(MachineBasicBlock *MBB, int FrameIdx,
int64_t Offset) const override;
void resolveFrameIndex(MachineInstr &MI, Register BaseReg,
int64_t Offset) const override;
bool isFrameOffsetLegal(const MachineInstr *MI, Register BaseReg,
int64_t Offset) const override;
const TargetRegisterClass *getPointerRegClass(
const MachineFunction &MF, unsigned Kind = 0) const override;
/// Returns a legal register class to copy a register in the specified class
/// to or from. If it is possible to copy the register directly without using
/// a cross register class copy, return the specified RC. Returns NULL if it
/// is not possible to copy between two registers of the specified class.
const TargetRegisterClass *
getCrossCopyRegClass(const TargetRegisterClass *RC) const override;
void buildVGPRSpillLoadStore(SGPRSpillBuilder &SB, int Index, int Offset,
bool IsLoad, bool IsKill = true) const;
/// If \p OnlyToVGPR is true, this will only succeed if this
bool spillSGPR(MachineBasicBlock::iterator MI,
int FI, RegScavenger *RS,
LiveIntervals *LIS = nullptr,
bool OnlyToVGPR = false) const;
bool restoreSGPR(MachineBasicBlock::iterator MI,
int FI, RegScavenger *RS,
LiveIntervals *LIS = nullptr,
bool OnlyToVGPR = false) const;
bool spillEmergencySGPR(MachineBasicBlock::iterator MI,
MachineBasicBlock &RestoreMBB, Register SGPR,
RegScavenger *RS) const;
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
unsigned FIOperandNum,
RegScavenger *RS) const override;
bool eliminateSGPRToVGPRSpillFrameIndex(MachineBasicBlock::iterator MI,
int FI, RegScavenger *RS,
LiveIntervals *LIS = nullptr) const;
StringRef getRegAsmName(MCRegister Reg) const override;
// Pseudo regs are not allowed
unsigned getHWRegIndex(MCRegister Reg) const {
return getEncodingValue(Reg) & 0xff;
}
LLVM_READONLY
const TargetRegisterClass *getVGPRClassForBitWidth(unsigned BitWidth) const;
LLVM_READONLY
const TargetRegisterClass *getAGPRClassForBitWidth(unsigned BitWidth) const;
LLVM_READONLY
const TargetRegisterClass *
getVectorSuperClassForBitWidth(unsigned BitWidth) const;
LLVM_READONLY
static const TargetRegisterClass *getSGPRClassForBitWidth(unsigned BitWidth);
/// Return the 'base' register class for this register.
/// e.g. SGPR0 => SReg_32, VGPR => VGPR_32 SGPR0_SGPR1 -> SReg_32, etc.
const TargetRegisterClass *getPhysRegClass(MCRegister Reg) const;
/// \returns true if this class contains only SGPR registers
static bool isSGPRClass(const TargetRegisterClass *RC) {
return !hasVGPRs(RC) && !hasAGPRs(RC);
}
/// \returns true if this class ID contains only SGPR registers
bool isSGPRClassID(unsigned RCID) const {
return isSGPRClass(getRegClass(RCID));
}
bool isSGPRReg(const MachineRegisterInfo &MRI, Register Reg) const;
/// \returns true if this class contains only VGPR registers
static bool isVGPRClass(const TargetRegisterClass *RC) {
return hasVGPRs(RC) && !hasAGPRs(RC);
}
/// \returns true if this class contains only AGPR registers
static bool isAGPRClass(const TargetRegisterClass *RC) {
return hasAGPRs(RC) && !hasVGPRs(RC);
}
/// \returns true only if this class contains both VGPR and AGPR registers
bool isVectorSuperClass(const TargetRegisterClass *RC) const {
return hasVGPRs(RC) && hasAGPRs(RC);
}
/// \returns true if this class contains VGPR registers.
static bool hasVGPRs(const TargetRegisterClass *RC) {
return RC->TSFlags & SIRCFlags::HasVGPR;
}
/// \returns true if this class contains AGPR registers.
static bool hasAGPRs(const TargetRegisterClass *RC) {
return RC->TSFlags & SIRCFlags::HasAGPR;
}
/// \returns true if this class contains any vector registers.
static bool hasVectorRegisters(const TargetRegisterClass *RC) {
return hasVGPRs(RC) || hasAGPRs(RC);
}
/// \returns A VGPR reg class with the same width as \p SRC
const TargetRegisterClass *
getEquivalentVGPRClass(const TargetRegisterClass *SRC) const;
/// \returns An AGPR reg class with the same width as \p SRC
const TargetRegisterClass *
getEquivalentAGPRClass(const TargetRegisterClass *SRC) const;
/// \returns A SGPR reg class with the same width as \p SRC
const TargetRegisterClass *
getEquivalentSGPRClass(const TargetRegisterClass *VRC) const;
/// \returns The canonical register class that is used for a sub-register of
/// \p RC for the given \p SubIdx. If \p SubIdx equals NoSubRegister, \p RC
/// will be returned.
const TargetRegisterClass *getSubRegClass(const TargetRegisterClass *RC,
unsigned SubIdx) const;
/// Returns a register class which is compatible with \p SuperRC, such that a
/// subregister exists with class \p SubRC with subregister index \p
/// SubIdx. If this is impossible (e.g., an unaligned subregister index within
/// a register tuple), return null.
const TargetRegisterClass *
getCompatibleSubRegClass(const TargetRegisterClass *SuperRC,
const TargetRegisterClass *SubRC,
unsigned SubIdx) const;
bool shouldRewriteCopySrc(const TargetRegisterClass *DefRC,
unsigned DefSubReg,
const TargetRegisterClass *SrcRC,
unsigned SrcSubReg) const override;
/// \returns True if operands defined with this operand type can accept
/// a literal constant (i.e. any 32-bit immediate).
bool opCanUseLiteralConstant(unsigned OpType) const;
/// \returns True if operands defined with this operand type can accept
/// an inline constant. i.e. An integer value in the range (-16, 64) or
/// -4.0f, -2.0f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 2.0f, 4.0f.
bool opCanUseInlineConstant(unsigned OpType) const;
MCRegister findUnusedRegister(const MachineRegisterInfo &MRI,
const TargetRegisterClass *RC,
const MachineFunction &MF,
bool ReserveHighestVGPR = false) const;
const TargetRegisterClass *getRegClassForReg(const MachineRegisterInfo &MRI,
Register Reg) const;
bool isVGPR(const MachineRegisterInfo &MRI, Register Reg) const;
bool isAGPR(const MachineRegisterInfo &MRI, Register Reg) const;
bool isVectorRegister(const MachineRegisterInfo &MRI, Register Reg) const {
return isVGPR(MRI, Reg) || isAGPR(MRI, Reg);
}
bool isConstantPhysReg(MCRegister PhysReg) const override;
bool isDivergentRegClass(const TargetRegisterClass *RC) const override {
return !isSGPRClass(RC);
}
ArrayRef<int16_t> getRegSplitParts(const TargetRegisterClass *RC,
unsigned EltSize) const;
bool shouldCoalesce(MachineInstr *MI,
const TargetRegisterClass *SrcRC,
unsigned SubReg,
const TargetRegisterClass *DstRC,
unsigned DstSubReg,
const TargetRegisterClass *NewRC,
LiveIntervals &LIS) const override;
unsigned getRegPressureLimit(const TargetRegisterClass *RC,
MachineFunction &MF) const override;
unsigned getRegPressureSetLimit(const MachineFunction &MF,
unsigned Idx) const override;
const int *getRegUnitPressureSets(unsigned RegUnit) const override;
MCRegister getReturnAddressReg(const MachineFunction &MF) const;
const TargetRegisterClass *
getRegClassForSizeOnBank(unsigned Size,
const RegisterBank &Bank,
const MachineRegisterInfo &MRI) const;
const TargetRegisterClass *
getRegClassForTypeOnBank(LLT Ty,
const RegisterBank &Bank,
const MachineRegisterInfo &MRI) const {
return getRegClassForSizeOnBank(Ty.getSizeInBits(), Bank, MRI);
}
const TargetRegisterClass *
getConstrainedRegClassForOperand(const MachineOperand &MO,
const MachineRegisterInfo &MRI) const override;
const TargetRegisterClass *getBoolRC() const {
return isWave32 ? &AMDGPU::SReg_32RegClass
: &AMDGPU::SReg_64RegClass;
}
const TargetRegisterClass *getWaveMaskRegClass() const {
return isWave32 ? &AMDGPU::SReg_32_XM0_XEXECRegClass
: &AMDGPU::SReg_64_XEXECRegClass;
}
// Return the appropriate register class to use for 64-bit VGPRs for the
// subtarget.
const TargetRegisterClass *getVGPR64Class() const;
MCRegister getVCC() const;
const TargetRegisterClass *getRegClass(unsigned RCID) const;
// Find reaching register definition
MachineInstr *findReachingDef(Register Reg, unsigned SubReg,
MachineInstr &Use,
MachineRegisterInfo &MRI,
LiveIntervals *LIS) const;
const uint32_t *getAllVGPRRegMask() const;
const uint32_t *getAllAGPRRegMask() const;
const uint32_t *getAllVectorRegMask() const;
const uint32_t *getAllAllocatableSRegMask() const;
// \returns number of 32 bit registers covered by a \p LM
static unsigned getNumCoveredRegs(LaneBitmask LM) {
// The assumption is that every lo16 subreg is an even bit and every hi16
// is an adjacent odd bit or vice versa.
uint64_t Mask = LM.getAsInteger();
uint64_t Even = Mask & 0xAAAAAAAAAAAAAAAAULL;
Mask = (Even >> 1) | Mask;
uint64_t Odd = Mask & 0x5555555555555555ULL;
return countPopulation(Odd);
}
// \returns a DWORD offset of a \p SubReg
unsigned getChannelFromSubReg(unsigned SubReg) const {
return SubReg ? (getSubRegIdxOffset(SubReg) + 31) / 32 : 0;
}
// \returns a DWORD size of a \p SubReg
unsigned getNumChannelsFromSubReg(unsigned SubReg) const {
return getNumCoveredRegs(getSubRegIndexLaneMask(SubReg));
}
// For a given 16 bit \p Reg \returns a 32 bit register holding it.
// \returns \p Reg otherwise.
MCPhysReg get32BitRegister(MCPhysReg Reg) const;
// Returns true if a given register class is properly aligned for
// the subtarget.
bool isProperlyAlignedRC(const TargetRegisterClass &RC) const;
/// Return all SGPR128 which satisfy the waves per execution unit requirement
/// of the subtarget.
ArrayRef<MCPhysReg> getAllSGPR128(const MachineFunction &MF) const;
/// Return all SGPR64 which satisfy the waves per execution unit requirement
/// of the subtarget.
ArrayRef<MCPhysReg> getAllSGPR64(const MachineFunction &MF) const;
/// Return all SGPR32 which satisfy the waves per execution unit requirement
/// of the subtarget.
ArrayRef<MCPhysReg> getAllSGPR32(const MachineFunction &MF) const;
// Insert spill or restore instructions.
// When lowering spill pseudos, the RegScavenger should be set.
// For creating spill instructions during frame lowering, where no scavenger
// is available, LiveRegs can be used.
void buildSpillLoadStore(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, const DebugLoc &DL,
unsigned LoadStoreOp, int Index, Register ValueReg,
bool ValueIsKill, MCRegister ScratchOffsetReg,
int64_t InstrOffset, MachineMemOperand *MMO,
RegScavenger *RS,
LivePhysRegs *LiveRegs = nullptr) const;
};
} // End namespace llvm
#endif