summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp')
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp2116
1 files changed, 1593 insertions, 523 deletions
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
index 1bb01dc8fa11..dfaf97bfb08e 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp
@@ -8,10 +8,69 @@
/// \file
/// This file implements the targeting of the RegisterBankInfo class for
/// AMDGPU.
-/// \todo This should be generated by TableGen.
+///
+/// \par
+///
+/// AMDGPU has unique register bank constraints that require special high level
+/// strategies to deal with. There are two main true physical register banks
+/// VGPR (vector), and SGPR (scalar). Additionally the VCC register bank is a
+/// sort of pseudo-register bank needed to represent SGPRs used in a vector
+/// boolean context. There is also the AGPR bank, which is a special purpose
+/// physical register bank present on some subtargets.
+///
+/// Copying from VGPR to SGPR is generally illegal, unless the value is known to
+/// be uniform. It is generally not valid to legalize operands by inserting
+/// copies as on other targets. Operations which require uniform, SGPR operands
+/// generally require scalarization by repeatedly executing the instruction,
+/// activating each set of lanes using a unique set of input values. This is
+/// referred to as a waterfall loop.
+///
+/// \par Booleans
+///
+/// Booleans (s1 values) requires special consideration. A vector compare result
+/// is naturally a bitmask with one bit per lane, in a 32 or 64-bit
+/// register. These are represented with the VCC bank. During selection, we need
+/// to be able to unambiguously go back from a register class to a register
+/// bank. To distinguish whether an SGPR should use the SGPR or VCC register
+/// bank, we need to know the use context type. An SGPR s1 value always means a
+/// VCC bank value, otherwise it will be the SGPR bank. A scalar compare sets
+/// SCC, which is a 1-bit unaddressable register. This will need to be copied to
+/// a 32-bit virtual register. Taken together, this means we need to adjust the
+/// type of boolean operations to be regbank legal. All SALU booleans need to be
+/// widened to 32-bits, and all VALU booleans need to be s1 values.
+///
+/// A noteworthy exception to the s1-means-vcc rule is for legalization artifact
+/// casts. G_TRUNC s1 results, and G_SEXT/G_ZEXT/G_ANYEXT sources are never vcc
+/// bank. A non-boolean source (such as a truncate from a 1-bit load from
+/// memory) will require a copy to the VCC bank which will require clearing the
+/// high bits and inserting a compare.
+///
+/// \par Constant bus restriction
+///
+/// VALU instructions have a limitation known as the constant bus
+/// restriction. Most VALU instructions can use SGPR operands, but may read at
+/// most 1 SGPR or constant literal value (this to 2 in gfx10 for most
+/// instructions). This is one unique SGPR, so the same SGPR may be used for
+/// multiple operands. From a register bank perspective, any combination of
+/// operands should be legal as an SGPR, but this is contextually dependent on
+/// the SGPR operands all being the same register. There is therefore optimal to
+/// choose the SGPR with the most uses to minimize the number of copies.
+///
+/// We avoid trying to solve this problem in RegBankSelect. Any VALU G_*
+/// operation should have its source operands all mapped to VGPRs (except for
+/// VCC), inserting copies from any SGPR operands. This the most trival legal
+/// mapping. Anything beyond the simplest 1:1 instruction selection would be too
+/// complicated to solve here. Every optimization pattern or instruction
+/// selected to multiple outputs would have to enforce this rule, and there
+/// would be additional complexity in tracking this rule for every G_*
+/// operation. By forcing all inputs to VGPRs, it also simplifies the task of
+/// picking the optimal operand combination from a post-isel optimization pass.
+///
//===----------------------------------------------------------------------===//
#include "AMDGPURegisterBankInfo.h"
+
+#include "AMDGPUGlobalISelUtils.h"
#include "AMDGPUInstrInfo.h"
#include "AMDGPUSubtarget.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
@@ -19,8 +78,8 @@
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
-#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
@@ -101,8 +160,9 @@ public:
if (!Op.isReg())
continue;
+ // We may see physical registers if building a real MI
Register Reg = Op.getReg();
- if (MRI.getRegClassOrRegBank(Reg))
+ if (Reg.isPhysical() || MRI.getRegClassOrRegBank(Reg))
continue;
const RegisterBank *RB = NewBank;
@@ -138,15 +198,16 @@ AMDGPURegisterBankInfo::AMDGPURegisterBankInfo(const GCNSubtarget &ST)
TII(Subtarget.getInstrInfo()) {
// HACK: Until this is fully tablegen'd.
- static bool AlreadyInit = false;
- if (AlreadyInit)
- return;
+ static llvm::once_flag InitializeRegisterBankFlag;
- AlreadyInit = true;
+ static auto InitializeRegisterBankOnce = [this]() {
+ assert(&getRegBank(AMDGPU::SGPRRegBankID) == &AMDGPU::SGPRRegBank &&
+ &getRegBank(AMDGPU::VGPRRegBankID) == &AMDGPU::VGPRRegBank &&
+ &getRegBank(AMDGPU::AGPRRegBankID) == &AMDGPU::AGPRRegBank);
+ (void)this;
+ };
- assert(&getRegBank(AMDGPU::SGPRRegBankID) == &AMDGPU::SGPRRegBank &&
- &getRegBank(AMDGPU::VGPRRegBankID) == &AMDGPU::VGPRRegBank &&
- &getRegBank(AMDGPU::AGPRRegBankID) == &AMDGPU::AGPRRegBank);
+ llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce);
}
static bool isVectorRegisterBank(const RegisterBank &Bank) {
@@ -159,7 +220,7 @@ unsigned AMDGPURegisterBankInfo::copyCost(const RegisterBank &Dst,
unsigned Size) const {
// TODO: Should there be a UniformVGPRRegBank which can use readfirstlane?
if (Dst.getID() == AMDGPU::SGPRRegBankID &&
- isVectorRegisterBank(Src)) {
+ (isVectorRegisterBank(Src) || Src.getID() == AMDGPU::VCCRegBankID)) {
return std::numeric_limits<unsigned>::max();
}
@@ -177,9 +238,6 @@ unsigned AMDGPURegisterBankInfo::copyCost(const RegisterBank &Dst,
Src.getID() == AMDGPU::VCCRegBankID))
return std::numeric_limits<unsigned>::max();
- if (Src.getID() == AMDGPU::VCCRegBankID)
- return std::numeric_limits<unsigned>::max();
-
// There is no direct copy between AGPRs.
if (Dst.getID() == AMDGPU::AGPRRegBankID &&
Src.getID() == AMDGPU::AGPRRegBankID)
@@ -317,22 +375,6 @@ AMDGPURegisterBankInfo::getInstrAlternativeMappingsIntrinsicWSideEffects(
const MachineInstr &MI, const MachineRegisterInfo &MRI) const {
switch (MI.getIntrinsicID()) {
- case Intrinsic::amdgcn_buffer_load: {
- static const OpRegBankEntry<3> Table[4] = {
- // Perfectly legal.
- { { AMDGPU::SGPRRegBankID, AMDGPU::VGPRRegBankID, AMDGPU::SGPRRegBankID }, 1 },
- { { AMDGPU::SGPRRegBankID, AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID }, 1 },
-
- // Waterfall loop needed for rsrc. In the worst case this will execute
- // approximately an extra 10 * wavesize + 2 instructions.
- { { AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID, AMDGPU::SGPRRegBankID }, 1000 },
- { { AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID }, 1000 }
- };
-
- // rsrc, voffset, offset
- const std::array<unsigned, 3> RegSrcOpIdx = { { 2, 3, 4 } };
- return addMappingFromTable<3>(MI, MRI, RegSrcOpIdx, makeArrayRef(Table));
- }
case Intrinsic::amdgcn_s_buffer_load: {
static const OpRegBankEntry<2> Table[4] = {
// Perfectly legal.
@@ -402,15 +444,15 @@ static bool isScalarLoadLegal(const MachineInstr &MI) {
AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT;
// There are no extending SMRD/SMEM loads, and they require 4-byte alignment.
- return MMO->getSize() >= 4 && MMO->getAlignment() >= 4 &&
- // Can't do a scalar atomic load.
- !MMO->isAtomic() &&
- // Don't use scalar loads for volatile accesses to non-constant address
- // spaces.
- (IsConst || !MMO->isVolatile()) &&
- // Memory must be known constant, or not written before this load.
- (IsConst || MMO->isInvariant() || memOpHasNoClobbered(MMO)) &&
- AMDGPUInstrInfo::isUniformMMO(MMO);
+ return MMO->getSize() >= 4 && MMO->getAlign() >= Align(4) &&
+ // Can't do a scalar atomic load.
+ !MMO->isAtomic() &&
+ // Don't use scalar loads for volatile accesses to non-constant address
+ // spaces.
+ (IsConst || !MMO->isVolatile()) &&
+ // Memory must be known constant, or not written before this load.
+ (IsConst || MMO->isInvariant() || memOpHasNoClobbered(MMO)) &&
+ AMDGPUInstrInfo::isUniformMMO(MMO);
}
RegisterBankInfo::InstructionMappings
@@ -490,24 +532,6 @@ AMDGPURegisterBankInfo::getInstrAlternativeMappings(
AMDGPU::getValueMappingSGPR64Only(AMDGPU::VGPRRegBankID, Size)}),
3); // Num Operands
AltMappings.push_back(&VVMapping);
-
- const InstructionMapping &SVMapping = getInstructionMapping(
- 3, 3, getOperandsMapping(
- {AMDGPU::getValueMappingSGPR64Only(AMDGPU::VGPRRegBankID, Size),
- AMDGPU::getValueMappingSGPR64Only(AMDGPU::SGPRRegBankID, Size),
- AMDGPU::getValueMappingSGPR64Only(AMDGPU::VGPRRegBankID, Size)}),
- 3); // Num Operands
- AltMappings.push_back(&SVMapping);
-
- // SGPR in LHS is slightly preferrable, so make it VS more expensive than
- // SV.
- const InstructionMapping &VSMapping = getInstructionMapping(
- 3, 4, getOperandsMapping(
- {AMDGPU::getValueMappingSGPR64Only(AMDGPU::VGPRRegBankID, Size),
- AMDGPU::getValueMappingSGPR64Only(AMDGPU::VGPRRegBankID, Size),
- AMDGPU::getValueMappingSGPR64Only(AMDGPU::SGPRRegBankID, Size)}),
- 3); // Num Operands
- AltMappings.push_back(&VSMapping);
break;
}
case TargetOpcode::G_LOAD:
@@ -517,7 +541,6 @@ AMDGPURegisterBankInfo::getInstrAlternativeMappings(
LLT PtrTy = MRI.getType(MI.getOperand(1).getReg());
unsigned PtrSize = PtrTy.getSizeInBits();
unsigned AS = PtrTy.getAddressSpace();
- LLT LoadTy = MRI.getType(MI.getOperand(0).getReg());
if ((AS != AMDGPUAS::LOCAL_ADDRESS && AS != AMDGPUAS::REGION_ADDRESS &&
AS != AMDGPUAS::PRIVATE_ADDRESS) &&
@@ -531,9 +554,10 @@ AMDGPURegisterBankInfo::getInstrAlternativeMappings(
}
const InstructionMapping &VVMapping = getInstructionMapping(
- 2, 1, getOperandsMapping(
- {AMDGPU::getValueMappingLoadSGPROnly(AMDGPU::VGPRRegBankID, LoadTy),
- AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, PtrSize)}),
+ 2, 1,
+ getOperandsMapping(
+ {AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size),
+ AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, PtrSize)}),
2); // Num Operands
AltMappings.push_back(&VVMapping);
@@ -546,43 +570,6 @@ AMDGPURegisterBankInfo::getInstrAlternativeMappings(
return AltMappings;
}
- case TargetOpcode::G_ICMP: {
- // TODO: Should report 32-bit for scalar output type.
- unsigned Size = getSizeInBits(MI.getOperand(2).getReg(), MRI, *TRI);
- const InstructionMapping &SSMapping = getInstructionMapping(1, 1,
- getOperandsMapping({AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, 1),
- nullptr, // Predicate operand.
- AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size),
- AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size)}),
- 4); // Num Operands
- AltMappings.push_back(&SSMapping);
-
- const InstructionMapping &SVMapping = getInstructionMapping(2, 1,
- getOperandsMapping({AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, 1),
- nullptr, // Predicate operand.
- AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size),
- AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size)}),
- 4); // Num Operands
- AltMappings.push_back(&SVMapping);
-
- const InstructionMapping &VSMapping = getInstructionMapping(3, 1,
- getOperandsMapping({AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, 1),
- nullptr, // Predicate operand.
- AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size),
- AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size)}),
- 4); // Num Operands
- AltMappings.push_back(&VSMapping);
-
- const InstructionMapping &VVMapping = getInstructionMapping(4, 1,
- getOperandsMapping({AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, 1),
- nullptr, // Predicate operand.
- AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size),
- AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size)}),
- 4); // Num Operands
- AltMappings.push_back(&VVMapping);
-
- return AltMappings;
- }
case TargetOpcode::G_SELECT: {
unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, *TRI);
const InstructionMapping &SSMapping = getInstructionMapping(1, 1,
@@ -607,10 +594,8 @@ AMDGPURegisterBankInfo::getInstrAlternativeMappings(
case TargetOpcode::G_SMAX:
case TargetOpcode::G_UMIN:
case TargetOpcode::G_UMAX: {
- static const OpRegBankEntry<3> Table[4] = {
+ static const OpRegBankEntry<3> Table[2] = {
{ { AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID }, 1 },
- { { AMDGPU::VGPRRegBankID, AMDGPU::SGPRRegBankID, AMDGPU::VGPRRegBankID }, 1 },
- { { AMDGPU::VGPRRegBankID, AMDGPU::VGPRRegBankID, AMDGPU::SGPRRegBankID }, 1 },
// Scalar requires cmp+select, and extends if 16-bit.
// FIXME: Should there be separate costs for 32 and 16-bit
@@ -740,6 +725,10 @@ bool AMDGPURegisterBankInfo::executeInWaterfallLoop(
SmallVector<Register, 4> InitResultRegs;
SmallVector<Register, 4> PhiRegs;
+ // Track use registers which have already been expanded with a readfirstlane
+ // sequence. This may have multiple uses if moving a sequence.
+ DenseMap<Register, Register> WaterfalledRegMap;
+
MachineBasicBlock &MBB = B.getMBB();
MachineFunction *MF = &B.getMF();
@@ -755,6 +744,10 @@ bool AMDGPURegisterBankInfo::executeInWaterfallLoop(
const unsigned ExecReg = Subtarget.isWave32() ?
AMDGPU::EXEC_LO : AMDGPU::EXEC;
+#ifndef NDEBUG
+ const int OrigRangeSize = std::distance(Range.begin(), Range.end());
+#endif
+
for (MachineInstr &MI : Range) {
for (MachineOperand &Def : MI.defs()) {
LLT ResTy = MRI.getType(Def.getReg());
@@ -820,13 +813,14 @@ bool AMDGPURegisterBankInfo::executeInWaterfallLoop(
const DebugLoc &DL = B.getDL();
- // Figure out the iterator range after splicing the instructions.
- auto NewBegin = std::prev(LoopBB->end());
+ MachineInstr &FirstInst = *Range.begin();
// Move the instruction into the loop. Note we moved everything after
// Range.end() already into a new block, so Range.end() is no longer valid.
LoopBB->splice(LoopBB->end(), &MBB, Range.begin(), MBB.end());
+ // Figure out the iterator range after splicing the instructions.
+ MachineBasicBlock::iterator NewBegin = FirstInst.getIterator();
auto NewEnd = LoopBB->end();
MachineBasicBlock::iterator I = Range.begin();
@@ -834,158 +828,173 @@ bool AMDGPURegisterBankInfo::executeInWaterfallLoop(
Register CondReg;
+ assert(std::distance(NewBegin, NewEnd) == OrigRangeSize);
+
for (MachineInstr &MI : make_range(NewBegin, NewEnd)) {
for (MachineOperand &Op : MI.uses()) {
if (!Op.isReg() || Op.isDef())
continue;
- if (SGPROperandRegs.count(Op.getReg())) {
- LLT OpTy = MRI.getType(Op.getReg());
- unsigned OpSize = OpTy.getSizeInBits();
+ Register OldReg = Op.getReg();
+ if (!SGPROperandRegs.count(OldReg))
+ continue;
- // Can only do a readlane of 32-bit pieces.
- if (OpSize == 32) {
- // Avoid extra copies in the simple case of one 32-bit register.
- Register CurrentLaneOpReg
- = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
- MRI.setType(CurrentLaneOpReg, OpTy);
+ // See if we already processed this register in another instruction in the
+ // sequence.
+ auto OldVal = WaterfalledRegMap.find(OldReg);
+ if (OldVal != WaterfalledRegMap.end()) {
+ Op.setReg(OldVal->second);
+ continue;
+ }
- constrainGenericRegister(Op.getReg(), AMDGPU::VGPR_32RegClass, MRI);
- // Read the next variant <- also loop target.
- BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
- CurrentLaneOpReg)
- .addReg(Op.getReg());
+ LLT OpTy = MRI.getType(Op.getReg());
+ unsigned OpSize = OpTy.getSizeInBits();
- Register NewCondReg = MRI.createVirtualRegister(WaveRC);
- bool First = CondReg == AMDGPU::NoRegister;
- if (First)
- CondReg = NewCondReg;
+ // Can only do a readlane of 32-bit pieces.
+ if (OpSize == 32) {
+ // Avoid extra copies in the simple case of one 32-bit register.
+ Register CurrentLaneOpReg
+ = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+ MRI.setType(CurrentLaneOpReg, OpTy);
- // Compare the just read M0 value to all possible Idx values.
- B.buildInstr(AMDGPU::V_CMP_EQ_U32_e64)
- .addDef(NewCondReg)
- .addReg(CurrentLaneOpReg)
- .addReg(Op.getReg());
- Op.setReg(CurrentLaneOpReg);
+ constrainGenericRegister(Op.getReg(), AMDGPU::VGPR_32RegClass, MRI);
+ // Read the next variant <- also loop target.
+ BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
+ CurrentLaneOpReg)
+ .addReg(Op.getReg());
- if (!First) {
- Register AndReg = MRI.createVirtualRegister(WaveRC);
+ Register NewCondReg = MRI.createVirtualRegister(WaveRC);
+ bool First = CondReg == AMDGPU::NoRegister;
+ if (First)
+ CondReg = NewCondReg;
- // If there are multiple operands to consider, and the conditions.
- B.buildInstr(WaveAndOpc)
- .addDef(AndReg)
- .addReg(NewCondReg)
- .addReg(CondReg);
- CondReg = AndReg;
- }
- } else {
- LLT S32 = LLT::scalar(32);
- SmallVector<Register, 8> ReadlanePieces;
+ // Compare the just read M0 value to all possible Idx values.
+ B.buildInstr(AMDGPU::V_CMP_EQ_U32_e64)
+ .addDef(NewCondReg)
+ .addReg(CurrentLaneOpReg)
+ .addReg(Op.getReg());
+ Op.setReg(CurrentLaneOpReg);
- // The compares can be done as 64-bit, but the extract needs to be done
- // in 32-bit pieces.
+ if (!First) {
+ Register AndReg = MRI.createVirtualRegister(WaveRC);
+
+ // If there are multiple operands to consider, and the conditions.
+ B.buildInstr(WaveAndOpc)
+ .addDef(AndReg)
+ .addReg(NewCondReg)
+ .addReg(CondReg);
+ CondReg = AndReg;
+ }
+ } else {
+ LLT S32 = LLT::scalar(32);
+ SmallVector<Register, 8> ReadlanePieces;
- bool Is64 = OpSize % 64 == 0;
+ // The compares can be done as 64-bit, but the extract needs to be done
+ // in 32-bit pieces.
- LLT UnmergeTy = OpSize % 64 == 0 ? LLT::scalar(64) : LLT::scalar(32);
- unsigned CmpOp = OpSize % 64 == 0 ? AMDGPU::V_CMP_EQ_U64_e64
- : AMDGPU::V_CMP_EQ_U32_e64;
+ bool Is64 = OpSize % 64 == 0;
- // The compares can be done as 64-bit, but the extract needs to be done
- // in 32-bit pieces.
+ LLT UnmergeTy = OpSize % 64 == 0 ? LLT::scalar(64) : LLT::scalar(32);
+ unsigned CmpOp = OpSize % 64 == 0 ? AMDGPU::V_CMP_EQ_U64_e64
+ : AMDGPU::V_CMP_EQ_U32_e64;
- // Insert the unmerge before the loop.
+ // The compares can be done as 64-bit, but the extract needs to be done
+ // in 32-bit pieces.
- B.setMBB(MBB);
- auto Unmerge = B.buildUnmerge(UnmergeTy, Op.getReg());
- B.setInstr(*I);
+ // Insert the unmerge before the loop.
- unsigned NumPieces = Unmerge->getNumOperands() - 1;
- for (unsigned PieceIdx = 0; PieceIdx != NumPieces; ++PieceIdx) {
- Register UnmergePiece = Unmerge.getReg(PieceIdx);
+ B.setMBB(MBB);
+ auto Unmerge = B.buildUnmerge(UnmergeTy, Op.getReg());
+ B.setInstr(*I);
- Register CurrentLaneOpReg;
- if (Is64) {
- Register CurrentLaneOpRegLo = MRI.createGenericVirtualRegister(S32);
- Register CurrentLaneOpRegHi = MRI.createGenericVirtualRegister(S32);
+ unsigned NumPieces = Unmerge->getNumOperands() - 1;
+ for (unsigned PieceIdx = 0; PieceIdx != NumPieces; ++PieceIdx) {
+ Register UnmergePiece = Unmerge.getReg(PieceIdx);
- MRI.setRegClass(UnmergePiece, &AMDGPU::VReg_64RegClass);
- MRI.setRegClass(CurrentLaneOpRegLo, &AMDGPU::SReg_32_XM0RegClass);
- MRI.setRegClass(CurrentLaneOpRegHi, &AMDGPU::SReg_32_XM0RegClass);
+ Register CurrentLaneOpReg;
+ if (Is64) {
+ Register CurrentLaneOpRegLo = MRI.createGenericVirtualRegister(S32);
+ Register CurrentLaneOpRegHi = MRI.createGenericVirtualRegister(S32);
- // Read the next variant <- also loop target.
- BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
- CurrentLaneOpRegLo)
- .addReg(UnmergePiece, 0, AMDGPU::sub0);
+ MRI.setRegClass(UnmergePiece, &AMDGPU::VReg_64RegClass);
+ MRI.setRegClass(CurrentLaneOpRegLo, &AMDGPU::SReg_32_XM0RegClass);
+ MRI.setRegClass(CurrentLaneOpRegHi, &AMDGPU::SReg_32_XM0RegClass);
- // Read the next variant <- also loop target.
- BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
- CurrentLaneOpRegHi)
- .addReg(UnmergePiece, 0, AMDGPU::sub1);
+ // Read the next variant <- also loop target.
+ BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
+ CurrentLaneOpRegLo)
+ .addReg(UnmergePiece, 0, AMDGPU::sub0);
- CurrentLaneOpReg =
- B.buildMerge(LLT::scalar(64),
- {CurrentLaneOpRegLo, CurrentLaneOpRegHi})
- .getReg(0);
+ // Read the next variant <- also loop target.
+ BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
+ CurrentLaneOpRegHi)
+ .addReg(UnmergePiece, 0, AMDGPU::sub1);
- MRI.setRegClass(CurrentLaneOpReg, &AMDGPU::SReg_64_XEXECRegClass);
+ CurrentLaneOpReg =
+ B.buildMerge(LLT::scalar(64),
+ {CurrentLaneOpRegLo, CurrentLaneOpRegHi})
+ .getReg(0);
- if (OpTy.getScalarSizeInBits() == 64) {
- // If we need to produce a 64-bit element vector, so use the
- // merged pieces
- ReadlanePieces.push_back(CurrentLaneOpReg);
- } else {
- // 32-bit element type.
- ReadlanePieces.push_back(CurrentLaneOpRegLo);
- ReadlanePieces.push_back(CurrentLaneOpRegHi);
- }
- } else {
- CurrentLaneOpReg = MRI.createGenericVirtualRegister(S32);
- MRI.setRegClass(UnmergePiece, &AMDGPU::VGPR_32RegClass);
- MRI.setRegClass(CurrentLaneOpReg, &AMDGPU::SReg_32_XM0RegClass);
+ MRI.setRegClass(CurrentLaneOpReg, &AMDGPU::SReg_64_XEXECRegClass);
- // Read the next variant <- also loop target.
- BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
- CurrentLaneOpReg)
- .addReg(UnmergePiece);
+ if (OpTy.getScalarSizeInBits() == 64) {
+ // If we need to produce a 64-bit element vector, so use the
+ // merged pieces
ReadlanePieces.push_back(CurrentLaneOpReg);
+ } else {
+ // 32-bit element type.
+ ReadlanePieces.push_back(CurrentLaneOpRegLo);
+ ReadlanePieces.push_back(CurrentLaneOpRegHi);
}
+ } else {
+ CurrentLaneOpReg = MRI.createGenericVirtualRegister(S32);
+ MRI.setRegClass(UnmergePiece, &AMDGPU::VGPR_32RegClass);
+ MRI.setRegClass(CurrentLaneOpReg, &AMDGPU::SReg_32_XM0RegClass);
- Register NewCondReg = MRI.createVirtualRegister(WaveRC);
- bool First = CondReg == AMDGPU::NoRegister;
- if (First)
- CondReg = NewCondReg;
-
- B.buildInstr(CmpOp)
- .addDef(NewCondReg)
- .addReg(CurrentLaneOpReg)
+ // Read the next variant <- also loop target.
+ BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32),
+ CurrentLaneOpReg)
.addReg(UnmergePiece);
+ ReadlanePieces.push_back(CurrentLaneOpReg);
+ }
- if (!First) {
- Register AndReg = MRI.createVirtualRegister(WaveRC);
+ Register NewCondReg = MRI.createVirtualRegister(WaveRC);
+ bool First = CondReg == AMDGPU::NoRegister;
+ if (First)
+ CondReg = NewCondReg;
- // If there are multiple operands to consider, and the conditions.
- B.buildInstr(WaveAndOpc)
- .addDef(AndReg)
- .addReg(NewCondReg)
- .addReg(CondReg);
- CondReg = AndReg;
- }
- }
+ B.buildInstr(CmpOp)
+ .addDef(NewCondReg)
+ .addReg(CurrentLaneOpReg)
+ .addReg(UnmergePiece);
- // FIXME: Build merge seems to switch to CONCAT_VECTORS but not
- // BUILD_VECTOR
- if (OpTy.isVector()) {
- auto Merge = B.buildBuildVector(OpTy, ReadlanePieces);
- Op.setReg(Merge.getReg(0));
- } else {
- auto Merge = B.buildMerge(OpTy, ReadlanePieces);
- Op.setReg(Merge.getReg(0));
+ if (!First) {
+ Register AndReg = MRI.createVirtualRegister(WaveRC);
+
+ // If there are multiple operands to consider, and the conditions.
+ B.buildInstr(WaveAndOpc)
+ .addDef(AndReg)
+ .addReg(NewCondReg)
+ .addReg(CondReg);
+ CondReg = AndReg;
}
+ }
- MRI.setRegBank(Op.getReg(), AMDGPU::SGPRRegBank);
+ // FIXME: Build merge seems to switch to CONCAT_VECTORS but not
+ // BUILD_VECTOR
+ if (OpTy.isVector()) {
+ auto Merge = B.buildBuildVector(OpTy, ReadlanePieces);
+ Op.setReg(Merge.getReg(0));
+ } else {
+ auto Merge = B.buildMerge(OpTy, ReadlanePieces);
+ Op.setReg(Merge.getReg(0));
}
+
+ MRI.setRegBank(Op.getReg(), AMDGPU::SGPRRegBank);
}
+
+ // Make sure we don't re-process this register again.
+ WaterfalledRegMap.insert(std::make_pair(OldReg, Op.getReg()));
}
}
@@ -1093,53 +1102,89 @@ void AMDGPURegisterBankInfo::constrainOpWithReadfirstlane(
MI.getOperand(OpIdx).setReg(SGPR);
}
-// When regbankselect repairs registers, it will insert a repair instruction
-// which defines the repaired register. Then it calls applyMapping and expects
-// that the targets will either delete or rewrite the originally wrote to the
-// repaired registers. Beccause of this, we end up in a situation where
-// we have 2 instructions defining the same registers.
-static MachineInstr *getOtherVRegDef(const MachineRegisterInfo &MRI,
- Register Reg,
- const MachineInstr &MI) {
- // Is there some way we can assert that there are exactly 2 def instructions?
- for (MachineInstr &Other : MRI.def_instructions(Reg)) {
- if (&Other != &MI)
- return &Other;
- }
+/// Split \p Ty into 2 pieces. The first will have \p FirstSize bits, and the
+/// rest will be in the remainder.
+static std::pair<LLT, LLT> splitUnequalType(LLT Ty, unsigned FirstSize) {
+ unsigned TotalSize = Ty.getSizeInBits();
+ if (!Ty.isVector())
+ return {LLT::scalar(FirstSize), LLT::scalar(TotalSize - FirstSize)};
+
+ LLT EltTy = Ty.getElementType();
+ unsigned EltSize = EltTy.getSizeInBits();
+ assert(FirstSize % EltSize == 0);
- return nullptr;
+ unsigned FirstPartNumElts = FirstSize / EltSize;
+ unsigned RemainderElts = (TotalSize - FirstSize) / EltSize;
+
+ return {LLT::scalarOrVector(FirstPartNumElts, EltTy),
+ LLT::scalarOrVector(RemainderElts, EltTy)};
}
-bool AMDGPURegisterBankInfo::applyMappingWideLoad(MachineInstr &MI,
+static LLT widen96To128(LLT Ty) {
+ if (!Ty.isVector())
+ return LLT::scalar(128);
+
+ LLT EltTy = Ty.getElementType();
+ assert(128 % EltTy.getSizeInBits() == 0);
+ return LLT::vector(128 / EltTy.getSizeInBits(), EltTy);
+}
+
+bool AMDGPURegisterBankInfo::applyMappingLoad(MachineInstr &MI,
const AMDGPURegisterBankInfo::OperandsMapper &OpdMapper,
MachineRegisterInfo &MRI) const {
Register DstReg = MI.getOperand(0).getReg();
- const LLT LoadTy = MRI.getType(DstReg);
+ const LLT LoadTy = MRI.getType(DstReg);
unsigned LoadSize = LoadTy.getSizeInBits();
const unsigned MaxNonSmrdLoadSize = 128;
+
+ const RegisterBank *PtrBank =
+ OpdMapper.getInstrMapping().getOperandMapping(1).BreakDown[0].RegBank;
+ if (PtrBank == &AMDGPU::SGPRRegBank) {
+ // If the pointer is an SGPR, we ordinarily have nothing to do.
+ if (LoadSize != 96)
+ return false;
+
+ MachineMemOperand *MMO = *MI.memoperands_begin();
+ Register PtrReg = MI.getOperand(1).getReg();
+ // 96-bit loads are only available for vector loads. We need to split this
+ // into a 64-bit part, and 32 (unless we can widen to a 128-bit load).
+
+ MachineIRBuilder B(MI);
+ ApplyRegBankMapping O(*this, MRI, &AMDGPU::SGPRRegBank);
+ GISelObserverWrapper Observer(&O);
+ B.setChangeObserver(Observer);
+
+ if (MMO->getAlign() < Align(16)) {
+ LLT Part64, Part32;
+ std::tie(Part64, Part32) = splitUnequalType(LoadTy, 64);
+ auto Load0 = B.buildLoadFromOffset(Part64, PtrReg, *MMO, 0);
+ auto Load1 = B.buildLoadFromOffset(Part32, PtrReg, *MMO, 8);
+
+ auto Undef = B.buildUndef(LoadTy);
+ auto Ins0 = B.buildInsert(LoadTy, Undef, Load0, 0);
+ B.buildInsert(MI.getOperand(0), Ins0, Load1, 64);
+ } else {
+ LLT WiderTy = widen96To128(LoadTy);
+ auto WideLoad = B.buildLoadFromOffset(WiderTy, PtrReg, *MMO, 0);
+ B.buildExtract(MI.getOperand(0), WideLoad, 0);
+ }
+
+ MI.eraseFromParent();
+ return true;
+ }
+
// 128-bit loads are supported for all instruction types.
if (LoadSize <= MaxNonSmrdLoadSize)
return false;
- SmallVector<unsigned, 16> DefRegs(OpdMapper.getVRegs(0));
- SmallVector<unsigned, 1> SrcRegs(OpdMapper.getVRegs(1));
+ SmallVector<Register, 16> DefRegs(OpdMapper.getVRegs(0));
+ SmallVector<Register, 1> SrcRegs(OpdMapper.getVRegs(1));
- // If the pointer is an SGPR, we have nothing to do.
- if (SrcRegs.empty()) {
- const RegisterBank *PtrBank =
- OpdMapper.getInstrMapping().getOperandMapping(1).BreakDown[0].RegBank;
- if (PtrBank == &AMDGPU::SGPRRegBank)
- return false;
+ if (SrcRegs.empty())
SrcRegs.push_back(MI.getOperand(1).getReg());
- }
assert(LoadSize % MaxNonSmrdLoadSize == 0);
- // We want to get the repair instruction now, because it will help us
- // determine which instruction the legalizer inserts that will also
- // write to DstReg.
- MachineInstr *RepairInst = getOtherVRegDef(MRI, DstReg, MI);
-
// RegBankSelect only emits scalar types, so we need to reset the pointer
// operand to a pointer type.
Register BasePtrReg = SrcRegs[0];
@@ -1148,38 +1193,72 @@ bool AMDGPURegisterBankInfo::applyMappingWideLoad(MachineInstr &MI,
MachineIRBuilder B(MI);
- unsigned SplitElts =
- MaxNonSmrdLoadSize / LoadTy.getScalarType().getSizeInBits();
- const LLT LoadSplitTy = LLT::vector(SplitElts, LoadTy.getScalarType());
+ unsigned NumSplitParts = LoadTy.getSizeInBits() / MaxNonSmrdLoadSize;
+ const LLT LoadSplitTy = LoadTy.divide(NumSplitParts);
ApplyRegBankMapping O(*this, MRI, &AMDGPU::VGPRRegBank);
GISelObserverWrapper Observer(&O);
B.setChangeObserver(Observer);
LegalizerHelper Helper(B.getMF(), Observer, B);
- if (Helper.fewerElementsVector(MI, 0, LoadSplitTy) != LegalizerHelper::Legalized)
+
+ if (LoadTy.isVector()) {
+ if (Helper.fewerElementsVector(MI, 0, LoadSplitTy) != LegalizerHelper::Legalized)
+ return false;
+ } else {
+ if (Helper.narrowScalar(MI, 0, LoadSplitTy) != LegalizerHelper::Legalized)
+ return false;
+ }
+
+ MRI.setRegBank(DstReg, AMDGPU::VGPRRegBank);
+ return true;
+}
+
+bool AMDGPURegisterBankInfo::applyMappingDynStackAlloc(
+ MachineInstr &MI,
+ const AMDGPURegisterBankInfo::OperandsMapper &OpdMapper,
+ MachineRegisterInfo &MRI) const {
+ const MachineFunction &MF = *MI.getMF();
+ const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
+ const auto &TFI = *ST.getFrameLowering();
+
+ // Guard in case the stack growth direction ever changes with scratch
+ // instructions.
+ if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown)
+ return false;
+
+ Register Dst = MI.getOperand(0).getReg();
+ Register AllocSize = MI.getOperand(1).getReg();
+ Align Alignment = assumeAligned(MI.getOperand(2).getImm());
+
+ const RegisterBank *SizeBank = getRegBank(AllocSize, MRI, *TRI);
+
+ // TODO: Need to emit a wave reduction to get the maximum size.
+ if (SizeBank != &AMDGPU::SGPRRegBank)
return false;
- // At this point, the legalizer has split the original load into smaller
- // loads. At the end of lowering, it inserts an instruction (LegalizedInst)
- // that combines the outputs of the lower loads and writes it to DstReg.
- // The register bank selector has also added the RepairInst which writes to
- // DstReg as well.
+ LLT PtrTy = MRI.getType(Dst);
+ LLT IntPtrTy = LLT::scalar(PtrTy.getSizeInBits());
+
+ const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
+ Register SPReg = Info->getStackPtrOffsetReg();
+ ApplyRegBankMapping ApplyBank(*this, MRI, &AMDGPU::SGPRRegBank);
+ GISelObserverWrapper Observer(&ApplyBank);
- MachineInstr *LegalizedInst = getOtherVRegDef(MRI, DstReg, *RepairInst);
+ MachineIRBuilder B(MI);
+ B.setChangeObserver(Observer);
- // Replace the output of the LegalizedInst with a temporary register, since
- // RepairInst already defines DstReg.
- Register TmpReg = MRI.createGenericVirtualRegister(MRI.getType(DstReg));
- LegalizedInst->getOperand(0).setReg(TmpReg);
- B.setInsertPt(*RepairInst->getParent(), RepairInst);
+ auto WaveSize = B.buildConstant(LLT::scalar(32), ST.getWavefrontSizeLog2());
+ auto ScaledSize = B.buildShl(IntPtrTy, AllocSize, WaveSize);
- for (unsigned DefIdx = 0, e = DefRegs.size(); DefIdx != e; ++DefIdx) {
- Register IdxReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
- B.buildConstant(IdxReg, DefIdx);
- MRI.setRegBank(IdxReg, AMDGPU::VGPRRegBank);
- B.buildExtractVectorElement(DefRegs[DefIdx], TmpReg, IdxReg);
+ auto SPCopy = B.buildCopy(PtrTy, SPReg);
+ if (Alignment > TFI.getStackAlign()) {
+ auto PtrAdd = B.buildPtrAdd(PtrTy, SPCopy, ScaledSize);
+ B.buildMaskLowPtrBits(Dst, PtrAdd,
+ Log2(Alignment) + ST.getWavefrontSizeLog2());
+ } else {
+ B.buildPtrAdd(Dst, SPCopy, ScaledSize);
}
- MRI.setRegBank(DstReg, AMDGPU::VGPRRegBank);
+ MI.eraseFromParent();
return true;
}
@@ -1210,6 +1289,281 @@ bool AMDGPURegisterBankInfo::applyMappingImage(
return true;
}
+static Register getSrcRegIgnoringCopies(const MachineRegisterInfo &MRI,
+ Register Reg) {
+ MachineInstr *Def = getDefIgnoringCopies(Reg, MRI);
+ if (!Def)
+ return Reg;
+
+ // TODO: Guard against this being an implicit def
+ return Def->getOperand(0).getReg();
+}
+
+// Analyze a combined offset from an llvm.amdgcn.s.buffer intrinsic and store
+// the three offsets (voffset, soffset and instoffset)
+static unsigned setBufferOffsets(MachineIRBuilder &B,
+ const AMDGPURegisterBankInfo &RBI,
+ Register CombinedOffset, Register &VOffsetReg,
+ Register &SOffsetReg, int64_t &InstOffsetVal,
+ Align Alignment) {
+ const LLT S32 = LLT::scalar(32);
+ MachineRegisterInfo *MRI = B.getMRI();
+
+ if (Optional<int64_t> Imm = getConstantVRegVal(CombinedOffset, *MRI)) {
+ uint32_t SOffset, ImmOffset;
+ if (AMDGPU::splitMUBUFOffset(*Imm, SOffset, ImmOffset, &RBI.Subtarget,
+ Alignment)) {
+ VOffsetReg = B.buildConstant(S32, 0).getReg(0);
+ SOffsetReg = B.buildConstant(S32, SOffset).getReg(0);
+ InstOffsetVal = ImmOffset;
+
+ B.getMRI()->setRegBank(VOffsetReg, AMDGPU::VGPRRegBank);
+ B.getMRI()->setRegBank(SOffsetReg, AMDGPU::SGPRRegBank);
+ return SOffset + ImmOffset;
+ }
+ }
+
+ Register Base;
+ unsigned Offset;
+ MachineInstr *Unused;
+
+ std::tie(Base, Offset, Unused)
+ = AMDGPU::getBaseWithConstantOffset(*MRI, CombinedOffset);
+
+ uint32_t SOffset, ImmOffset;
+ if (Offset > 0 && AMDGPU::splitMUBUFOffset(Offset, SOffset, ImmOffset,
+ &RBI.Subtarget, Alignment)) {
+ if (RBI.getRegBank(Base, *MRI, *RBI.TRI) == &AMDGPU::VGPRRegBank) {
+ VOffsetReg = Base;
+ SOffsetReg = B.buildConstant(S32, SOffset).getReg(0);
+ B.getMRI()->setRegBank(SOffsetReg, AMDGPU::SGPRRegBank);
+ InstOffsetVal = ImmOffset;
+ return 0; // XXX - Why is this 0?
+ }
+
+ // If we have SGPR base, we can use it for soffset.
+ if (SOffset == 0) {
+ VOffsetReg = B.buildConstant(S32, 0).getReg(0);
+ B.getMRI()->setRegBank(VOffsetReg, AMDGPU::VGPRRegBank);
+ SOffsetReg = Base;
+ InstOffsetVal = ImmOffset;
+ return 0; // XXX - Why is this 0?
+ }
+ }
+
+ // Handle the variable sgpr + vgpr case.
+ if (MachineInstr *Add = getOpcodeDef(AMDGPU::G_ADD, CombinedOffset, *MRI)) {
+ Register Src0 = getSrcRegIgnoringCopies(*MRI, Add->getOperand(1).getReg());
+ Register Src1 = getSrcRegIgnoringCopies(*MRI, Add->getOperand(2).getReg());
+
+ const RegisterBank *Src0Bank = RBI.getRegBank(Src0, *MRI, *RBI.TRI);
+ const RegisterBank *Src1Bank = RBI.getRegBank(Src1, *MRI, *RBI.TRI);
+
+ if (Src0Bank == &AMDGPU::VGPRRegBank && Src1Bank == &AMDGPU::SGPRRegBank) {
+ VOffsetReg = Src0;
+ SOffsetReg = Src1;
+ return 0;
+ }
+
+ if (Src0Bank == &AMDGPU::SGPRRegBank && Src1Bank == &AMDGPU::VGPRRegBank) {
+ VOffsetReg = Src1;
+ SOffsetReg = Src0;
+ return 0;
+ }
+ }
+
+ // Ensure we have a VGPR for the combined offset. This could be an issue if we
+ // have an SGPR offset and a VGPR resource.
+ if (RBI.getRegBank(CombinedOffset, *MRI, *RBI.TRI) == &AMDGPU::VGPRRegBank) {
+ VOffsetReg = CombinedOffset;
+ } else {
+ VOffsetReg = B.buildCopy(S32, CombinedOffset).getReg(0);
+ B.getMRI()->setRegBank(VOffsetReg, AMDGPU::VGPRRegBank);
+ }
+
+ SOffsetReg = B.buildConstant(S32, 0).getReg(0);
+ B.getMRI()->setRegBank(SOffsetReg, AMDGPU::SGPRRegBank);
+ return 0;
+}
+
+bool AMDGPURegisterBankInfo::applyMappingSBufferLoad(
+ const OperandsMapper &OpdMapper) const {
+ MachineInstr &MI = OpdMapper.getMI();
+ MachineRegisterInfo &MRI = OpdMapper.getMRI();
+
+ const LLT S32 = LLT::scalar(32);
+ Register Dst = MI.getOperand(0).getReg();
+ LLT Ty = MRI.getType(Dst);
+
+ const RegisterBank *RSrcBank =
+ OpdMapper.getInstrMapping().getOperandMapping(1).BreakDown[0].RegBank;
+ const RegisterBank *OffsetBank =
+ OpdMapper.getInstrMapping().getOperandMapping(2).BreakDown[0].RegBank;
+ if (RSrcBank == &AMDGPU::SGPRRegBank &&
+ OffsetBank == &AMDGPU::SGPRRegBank)
+ return true; // Legal mapping
+
+ // FIXME: 96-bit case was widened during legalize. We neeed to narrow it back
+ // here but don't have an MMO.
+
+ unsigned LoadSize = Ty.getSizeInBits();
+ int NumLoads = 1;
+ if (LoadSize == 256 || LoadSize == 512) {
+ NumLoads = LoadSize / 128;
+ Ty = Ty.divide(NumLoads);
+ }
+
+ // Use the alignment to ensure that the required offsets will fit into the
+ // immediate offsets.
+ const Align Alignment = NumLoads > 1 ? Align(16 * NumLoads) : Align(1);
+
+ MachineIRBuilder B(MI);
+ MachineFunction &MF = B.getMF();
+
+ Register SOffset;
+ Register VOffset;
+ int64_t ImmOffset = 0;
+
+ unsigned MMOOffset = setBufferOffsets(B, *this, MI.getOperand(2).getReg(),
+ VOffset, SOffset, ImmOffset, Alignment);
+
+ // TODO: 96-bit loads were widened to 128-bit results. Shrink the result if we
+ // can, but we neeed to track an MMO for that.
+ const unsigned MemSize = (Ty.getSizeInBits() + 7) / 8;
+ const Align MemAlign(4); // FIXME: ABI type alignment?
+ MachineMemOperand *BaseMMO = MF.getMachineMemOperand(
+ MachinePointerInfo(),
+ MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant,
+ MemSize, MemAlign);
+ if (MMOOffset != 0)
+ BaseMMO = MF.getMachineMemOperand(BaseMMO, MMOOffset, MemSize);
+
+ // If only the offset is divergent, emit a MUBUF buffer load instead. We can
+ // assume that the buffer is unswizzled.
+
+ Register RSrc = MI.getOperand(1).getReg();
+ Register VIndex = B.buildConstant(S32, 0).getReg(0);
+ B.getMRI()->setRegBank(VIndex, AMDGPU::VGPRRegBank);
+
+ SmallVector<Register, 4> LoadParts(NumLoads);
+
+ MachineBasicBlock::iterator MII = MI.getIterator();
+ MachineInstrSpan Span(MII, &B.getMBB());
+
+ for (int i = 0; i < NumLoads; ++i) {
+ if (NumLoads == 1) {
+ LoadParts[i] = Dst;
+ } else {
+ LoadParts[i] = MRI.createGenericVirtualRegister(Ty);
+ MRI.setRegBank(LoadParts[i], AMDGPU::VGPRRegBank);
+ }
+
+ MachineMemOperand *MMO = BaseMMO;
+ if (i != 0)
+ BaseMMO = MF.getMachineMemOperand(BaseMMO, MMOOffset + 16 * i, MemSize);
+
+ B.buildInstr(AMDGPU::G_AMDGPU_BUFFER_LOAD)
+ .addDef(LoadParts[i]) // vdata
+ .addUse(RSrc) // rsrc
+ .addUse(VIndex) // vindex
+ .addUse(VOffset) // voffset
+ .addUse(SOffset) // soffset
+ .addImm(ImmOffset + 16 * i) // offset(imm)
+ .addImm(0) // cachepolicy, swizzled buffer(imm)
+ .addImm(0) // idxen(imm)
+ .addMemOperand(MMO);
+ }
+
+ // TODO: If only the resource is a VGPR, it may be better to execute the
+ // scalar load in the waterfall loop if the resource is expected to frequently
+ // be dynamically uniform.
+ if (RSrcBank != &AMDGPU::SGPRRegBank) {
+ // Remove the original instruction to avoid potentially confusing the
+ // waterfall loop logic.
+ B.setInstr(*Span.begin());
+ MI.eraseFromParent();
+
+ SmallSet<Register, 4> OpsToWaterfall;
+
+ OpsToWaterfall.insert(RSrc);
+ executeInWaterfallLoop(B, make_range(Span.begin(), Span.end()),
+ OpsToWaterfall, MRI);
+ }
+
+ if (NumLoads != 1) {
+ if (Ty.isVector())
+ B.buildConcatVectors(Dst, LoadParts);
+ else
+ B.buildMerge(Dst, LoadParts);
+ }
+
+ // We removed the instruction earlier with a waterfall loop.
+ if (RSrcBank == &AMDGPU::SGPRRegBank)
+ MI.eraseFromParent();
+
+ return true;
+}
+
+bool AMDGPURegisterBankInfo::applyMappingBFEIntrinsic(
+ const OperandsMapper &OpdMapper, bool Signed) const {
+ MachineInstr &MI = OpdMapper.getMI();
+ MachineRegisterInfo &MRI = OpdMapper.getMRI();
+
+ // Insert basic copies
+ applyDefaultMapping(OpdMapper);
+
+ Register DstReg = MI.getOperand(0).getReg();
+ LLT Ty = MRI.getType(DstReg);
+
+ const LLT S32 = LLT::scalar(32);
+
+ const RegisterBank *DstBank =
+ OpdMapper.getInstrMapping().getOperandMapping(0).BreakDown[0].RegBank;
+ if (DstBank == &AMDGPU::VGPRRegBank) {
+ if (Ty == S32)
+ return true;
+
+ // TODO: 64-bit version is scalar only, so we need to expand this.
+ return false;
+ }
+
+ Register SrcReg = MI.getOperand(2).getReg();
+ Register OffsetReg = MI.getOperand(3).getReg();
+ Register WidthReg = MI.getOperand(4).getReg();
+
+ // The scalar form packs the offset and width in a single operand.
+
+ ApplyRegBankMapping ApplyBank(*this, MRI, &AMDGPU::SGPRRegBank);
+ GISelObserverWrapper Observer(&ApplyBank);
+ MachineIRBuilder B(MI);
+ B.setChangeObserver(Observer);
+
+ // Ensure the high bits are clear to insert the offset.
+ auto OffsetMask = B.buildConstant(S32, maskTrailingOnes<unsigned>(6));
+ auto ClampOffset = B.buildAnd(S32, OffsetReg, OffsetMask);
+
+ // Zeros out the low bits, so don't bother clamping the input value.
+ auto ShiftWidth = B.buildShl(S32, WidthReg, B.buildConstant(S32, 16));
+
+ // Transformation function, pack the offset and width of a BFE into
+ // the format expected by the S_BFE_I32 / S_BFE_U32. In the second
+ // source, bits [5:0] contain the offset and bits [22:16] the width.
+ auto MergedInputs = B.buildOr(S32, ClampOffset, ShiftWidth);
+
+ // TODO: It might be worth using a pseudo here to avoid scc clobber and
+ // register class constraints.
+ unsigned Opc = Ty == S32 ? (Signed ? AMDGPU::S_BFE_I32 : AMDGPU::S_BFE_U32) :
+ (Signed ? AMDGPU::S_BFE_I64 : AMDGPU::S_BFE_U64);
+
+ auto MIB = B.buildInstr(Opc, {DstReg}, {SrcReg, MergedInputs});
+ if (!constrainSelectedInstRegOperands(*MIB, *TII, *TRI, *this))
+ llvm_unreachable("failed to constrain BFE");
+
+ MI.eraseFromParent();
+ return true;
+}
+
// FIXME: Duplicated from LegalizerHelper
static CmpInst::Predicate minMaxToCompare(unsigned Opc) {
switch (Opc) {
@@ -1226,6 +1580,51 @@ static CmpInst::Predicate minMaxToCompare(unsigned Opc) {
}
}
+static unsigned minMaxToExtend(unsigned Opc) {
+ switch (Opc) {
+ case TargetOpcode::G_SMIN:
+ case TargetOpcode::G_SMAX:
+ return TargetOpcode::G_SEXT;
+ case TargetOpcode::G_UMIN:
+ case TargetOpcode::G_UMAX:
+ return TargetOpcode::G_ZEXT;
+ default:
+ llvm_unreachable("not in integer min/max");
+ }
+}
+
+// Emit a legalized extension from <2 x s16> to 2 32-bit components, avoiding
+// any illegal vector extend or unmerge operations.
+static std::pair<Register, Register>
+unpackV2S16ToS32(MachineIRBuilder &B, Register Src, unsigned ExtOpcode) {
+ const LLT S32 = LLT::scalar(32);
+ auto Bitcast = B.buildBitcast(S32, Src);
+
+ if (ExtOpcode == TargetOpcode::G_SEXT) {
+ auto ExtLo = B.buildSExtInReg(S32, Bitcast, 16);
+ auto ShiftHi = B.buildAShr(S32, Bitcast, B.buildConstant(S32, 16));
+ return std::make_pair(ExtLo.getReg(0), ShiftHi.getReg(0));
+ }
+
+ auto ShiftHi = B.buildLShr(S32, Bitcast, B.buildConstant(S32, 16));
+ if (ExtOpcode == TargetOpcode::G_ZEXT) {
+ auto ExtLo = B.buildAnd(S32, Bitcast, B.buildConstant(S32, 0xffff));
+ return std::make_pair(ExtLo.getReg(0), ShiftHi.getReg(0));
+ }
+
+ assert(ExtOpcode == TargetOpcode::G_ANYEXT);
+ return std::make_pair(Bitcast.getReg(0), ShiftHi.getReg(0));
+}
+
+static MachineInstr *buildExpandedScalarMinMax(MachineIRBuilder &B,
+ CmpInst::Predicate Pred,
+ Register Dst, Register Src0,
+ Register Src1) {
+ const LLT CmpType = LLT::scalar(32);
+ auto Cmp = B.buildICmp(Pred, CmpType, Src0, Src1);
+ return B.buildSelect(Dst, Cmp, Src0, Src1);
+}
+
// FIXME: Duplicated from LegalizerHelper, except changing the boolean type.
void AMDGPURegisterBankInfo::lowerScalarMinMax(MachineIRBuilder &B,
MachineInstr &MI) const {
@@ -1234,24 +1633,25 @@ void AMDGPURegisterBankInfo::lowerScalarMinMax(MachineIRBuilder &B,
Register Src1 = MI.getOperand(2).getReg();
const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
- LLT CmpType = LLT::scalar(32);
-
- auto Cmp = B.buildICmp(Pred, CmpType, Src0, Src1);
- B.buildSelect(Dst, Cmp, Src0, Src1);
+ MachineInstr *Sel = buildExpandedScalarMinMax(B, Pred, Dst, Src0, Src1);
- B.getMRI()->setRegBank(Cmp.getReg(0), AMDGPU::SGPRRegBank);
+ Register CmpReg = Sel->getOperand(1).getReg();
+ B.getMRI()->setRegBank(CmpReg, AMDGPU::SGPRRegBank);
MI.eraseFromParent();
}
// For cases where only a single copy is inserted for matching register banks.
// Replace the register in the instruction operand
-static void substituteSimpleCopyRegs(
+static bool substituteSimpleCopyRegs(
const AMDGPURegisterBankInfo::OperandsMapper &OpdMapper, unsigned OpIdx) {
SmallVector<unsigned, 1> SrcReg(OpdMapper.getVRegs(OpIdx));
if (!SrcReg.empty()) {
assert(SrcReg.size() == 1);
OpdMapper.getMI().getOperand(OpIdx).setReg(SrcReg[0]);
+ return true;
}
+
+ return false;
}
/// Handle register layout difference for f16 images for some subtargets.
@@ -1465,6 +1865,223 @@ bool AMDGPURegisterBankInfo::buildVCopy(MachineIRBuilder &B, Register DstReg,
constrainGenericRegister(DstReg, AMDGPU::VReg_64RegClass, MRI);
}
+/// Utility function for pushing dynamic vector indexes with a constant offset
+/// into waterwall loops.
+static void reinsertVectorIndexAdd(MachineIRBuilder &B,
+ MachineInstr &IdxUseInstr,
+ unsigned OpIdx,
+ unsigned ConstOffset) {
+ MachineRegisterInfo &MRI = *B.getMRI();
+ const LLT S32 = LLT::scalar(32);
+ Register WaterfallIdx = IdxUseInstr.getOperand(OpIdx).getReg();
+ B.setInsertPt(*IdxUseInstr.getParent(), IdxUseInstr.getIterator());
+
+ auto MaterializedOffset = B.buildConstant(S32, ConstOffset);
+
+ auto Add = B.buildAdd(S32, WaterfallIdx, MaterializedOffset);
+ MRI.setRegBank(MaterializedOffset.getReg(0), AMDGPU::SGPRRegBank);
+ MRI.setRegBank(Add.getReg(0), AMDGPU::SGPRRegBank);
+ IdxUseInstr.getOperand(OpIdx).setReg(Add.getReg(0));
+}
+
+/// Implement extending a 32-bit value to a 64-bit value. \p Lo32Reg is the
+/// original 32-bit source value (to be inserted in the low part of the combined
+/// 64-bit result), and \p Hi32Reg is the high half of the combined 64-bit
+/// value.
+static void extendLow32IntoHigh32(MachineIRBuilder &B,
+ Register Hi32Reg, Register Lo32Reg,
+ unsigned ExtOpc,
+ const RegisterBank &RegBank,
+ bool IsBooleanSrc = false) {
+ if (ExtOpc == AMDGPU::G_ZEXT) {
+ B.buildConstant(Hi32Reg, 0);
+ } else if (ExtOpc == AMDGPU::G_SEXT) {
+ if (IsBooleanSrc) {
+ // If we know the original source was an s1, the high half is the same as
+ // the low.
+ B.buildCopy(Hi32Reg, Lo32Reg);
+ } else {
+ // Replicate sign bit from 32-bit extended part.
+ auto ShiftAmt = B.buildConstant(LLT::scalar(32), 31);
+ B.getMRI()->setRegBank(ShiftAmt.getReg(0), RegBank);
+ B.buildAShr(Hi32Reg, Lo32Reg, ShiftAmt);
+ }
+ } else {
+ assert(ExtOpc == AMDGPU::G_ANYEXT && "not an integer extension");
+ B.buildUndef(Hi32Reg);
+ }
+}
+
+bool AMDGPURegisterBankInfo::foldExtractEltToCmpSelect(
+ MachineInstr &MI, MachineRegisterInfo &MRI,
+ const OperandsMapper &OpdMapper) const {
+
+ Register VecReg = MI.getOperand(1).getReg();
+ Register Idx = MI.getOperand(2).getReg();
+
+ const RegisterBank &IdxBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(2).BreakDown[0].RegBank;
+
+ bool IsDivergentIdx = IdxBank == AMDGPU::VGPRRegBank;
+
+ LLT VecTy = MRI.getType(VecReg);
+ unsigned EltSize = VecTy.getScalarSizeInBits();
+ unsigned NumElem = VecTy.getNumElements();
+
+ if (!SITargetLowering::shouldExpandVectorDynExt(EltSize, NumElem,
+ IsDivergentIdx))
+ return false;
+
+ MachineIRBuilder B(MI);
+ LLT S32 = LLT::scalar(32);
+
+ const RegisterBank &DstBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(0).BreakDown[0].RegBank;
+ const RegisterBank &SrcBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(1).BreakDown[0].RegBank;
+
+ const RegisterBank &CCBank =
+ (DstBank == AMDGPU::SGPRRegBank &&
+ SrcBank == AMDGPU::SGPRRegBank &&
+ IdxBank == AMDGPU::SGPRRegBank) ? AMDGPU::SGPRRegBank
+ : AMDGPU::VCCRegBank;
+ LLT CCTy = (CCBank == AMDGPU::SGPRRegBank) ? S32 : LLT::scalar(1);
+
+ if (CCBank == AMDGPU::VCCRegBank && IdxBank == AMDGPU::SGPRRegBank) {
+ Idx = B.buildCopy(S32, Idx)->getOperand(0).getReg();
+ MRI.setRegBank(Idx, AMDGPU::VGPRRegBank);
+ }
+
+ LLT EltTy = VecTy.getScalarType();
+ SmallVector<Register, 2> DstRegs(OpdMapper.getVRegs(0));
+ unsigned NumLanes = DstRegs.size();
+ if (!NumLanes)
+ NumLanes = 1;
+ else
+ EltTy = MRI.getType(DstRegs[0]);
+
+ auto UnmergeToEltTy = B.buildUnmerge(EltTy, VecReg);
+ SmallVector<Register, 2> Res(NumLanes);
+ for (unsigned L = 0; L < NumLanes; ++L)
+ Res[L] = UnmergeToEltTy.getReg(L);
+
+ for (unsigned I = 1; I < NumElem; ++I) {
+ auto IC = B.buildConstant(S32, I);
+ MRI.setRegBank(IC->getOperand(0).getReg(), AMDGPU::SGPRRegBank);
+ auto Cmp = B.buildICmp(CmpInst::ICMP_EQ, CCTy, Idx, IC);
+ MRI.setRegBank(Cmp->getOperand(0).getReg(), CCBank);
+
+ for (unsigned L = 0; L < NumLanes; ++L) {
+ auto S = B.buildSelect(EltTy, Cmp,
+ UnmergeToEltTy.getReg(I * NumLanes + L), Res[L]);
+
+ for (unsigned N : { 0, 2, 3 })
+ MRI.setRegBank(S->getOperand(N).getReg(), DstBank);
+
+ Res[L] = S->getOperand(0).getReg();
+ }
+ }
+
+ for (unsigned L = 0; L < NumLanes; ++L) {
+ Register DstReg = (NumLanes == 1) ? MI.getOperand(0).getReg() : DstRegs[L];
+ B.buildCopy(DstReg, Res[L]);
+ MRI.setRegBank(DstReg, DstBank);
+ }
+
+ MRI.setRegBank(MI.getOperand(0).getReg(), DstBank);
+ MI.eraseFromParent();
+
+ return true;
+}
+
+bool AMDGPURegisterBankInfo::foldInsertEltToCmpSelect(
+ MachineInstr &MI, MachineRegisterInfo &MRI,
+ const OperandsMapper &OpdMapper) const {
+
+ Register VecReg = MI.getOperand(1).getReg();
+ Register Idx = MI.getOperand(3).getReg();
+
+ const RegisterBank &IdxBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(3).BreakDown[0].RegBank;
+
+ bool IsDivergentIdx = IdxBank == AMDGPU::VGPRRegBank;
+
+ LLT VecTy = MRI.getType(VecReg);
+ unsigned EltSize = VecTy.getScalarSizeInBits();
+ unsigned NumElem = VecTy.getNumElements();
+
+ if (!SITargetLowering::shouldExpandVectorDynExt(EltSize, NumElem,
+ IsDivergentIdx))
+ return false;
+
+ MachineIRBuilder B(MI);
+ LLT S32 = LLT::scalar(32);
+
+ const RegisterBank &DstBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(0).BreakDown[0].RegBank;
+ const RegisterBank &SrcBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(1).BreakDown[0].RegBank;
+ const RegisterBank &InsBank =
+ *OpdMapper.getInstrMapping().getOperandMapping(2).BreakDown[0].RegBank;
+
+ const RegisterBank &CCBank =
+ (DstBank == AMDGPU::SGPRRegBank &&
+ SrcBank == AMDGPU::SGPRRegBank &&
+ InsBank == AMDGPU::SGPRRegBank &&
+ IdxBank == AMDGPU::SGPRRegBank) ? AMDGPU::SGPRRegBank
+ : AMDGPU::VCCRegBank;
+ LLT CCTy = (CCBank == AMDGPU::SGPRRegBank) ? S32 : LLT::scalar(1);
+
+ if (CCBank == AMDGPU::VCCRegBank && IdxBank == AMDGPU::SGPRRegBank) {
+ Idx = B.buildCopy(S32, Idx)->getOperand(0).getReg();
+ MRI.setRegBank(Idx, AMDGPU::VGPRRegBank);
+ }
+
+ LLT EltTy = VecTy.getScalarType();
+ SmallVector<Register, 2> InsRegs(OpdMapper.getVRegs(2));
+ unsigned NumLanes = InsRegs.size();
+ if (!NumLanes) {
+ NumLanes = 1;
+ InsRegs.push_back(MI.getOperand(2).getReg());
+ } else {
+ EltTy = MRI.getType(InsRegs[0]);
+ }
+
+ auto UnmergeToEltTy = B.buildUnmerge(EltTy, VecReg);
+ SmallVector<Register, 16> Ops(NumElem * NumLanes);
+
+ for (unsigned I = 0; I < NumElem; ++I) {
+ auto IC = B.buildConstant(S32, I);
+ MRI.setRegBank(IC->getOperand(0).getReg(), AMDGPU::SGPRRegBank);
+ auto Cmp = B.buildICmp(CmpInst::ICMP_EQ, CCTy, Idx, IC);
+ MRI.setRegBank(Cmp->getOperand(0).getReg(), CCBank);
+
+ for (unsigned L = 0; L < NumLanes; ++L) {
+ auto S = B.buildSelect(EltTy, Cmp, InsRegs[L],
+ UnmergeToEltTy.getReg(I * NumLanes + L));
+
+ for (unsigned N : { 0, 2, 3 })
+ MRI.setRegBank(S->getOperand(N).getReg(), DstBank);
+
+ Ops[I * NumLanes + L] = S->getOperand(0).getReg();
+ }
+ }
+
+ LLT MergeTy = LLT::vector(Ops.size(), EltTy);
+ if (MergeTy == MRI.getType(MI.getOperand(0).getReg())) {
+ B.buildBuildVector(MI.getOperand(0), Ops);
+ } else {
+ auto Vec = B.buildBuildVector(MergeTy, Ops);
+ MRI.setRegBank(Vec->getOperand(0).getReg(), DstBank);
+ B.buildBitcast(MI.getOperand(0).getReg(), Vec);
+ }
+
+ MRI.setRegBank(MI.getOperand(0).getReg(), DstBank);
+ MI.eraseFromParent();
+
+ return true;
+}
+
void AMDGPURegisterBankInfo::applyMappingImpl(
const OperandsMapper &OpdMapper) const {
MachineInstr &MI = OpdMapper.getMI();
@@ -1555,7 +2172,13 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
MachineBasicBlock *MBB = MI.getParent();
B.setInsertPt(*MBB, std::next(MI.getIterator()));
- B.buildTrunc(DstReg, NewDstReg);
+
+ // If we had a constrained VCC result register, a copy was inserted to VCC
+ // from SGPR.
+ SmallVector<Register, 1> DefRegs(OpdMapper.getVRegs(0));
+ if (DefRegs.empty())
+ DefRegs.push_back(DstReg);
+ B.buildTrunc(DefRegs[0], NewDstReg);
return;
}
case AMDGPU::G_SELECT: {
@@ -1712,10 +2335,16 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
}
case AMDGPU::G_ADD:
case AMDGPU::G_SUB:
- case AMDGPU::G_MUL: {
+ case AMDGPU::G_MUL:
+ case AMDGPU::G_SHL:
+ case AMDGPU::G_LSHR:
+ case AMDGPU::G_ASHR: {
Register DstReg = MI.getOperand(0).getReg();
LLT DstTy = MRI.getType(DstReg);
- if (DstTy != LLT::scalar(16))
+
+ // 16-bit operations are VALU only, but can be promoted to 32-bit SALU.
+ // Packed 16-bit operations need to be scalarized and promoted.
+ if (DstTy != LLT::scalar(16) && DstTy != LLT::vector(2, 16))
break;
const RegisterBank *DstBank =
@@ -1723,16 +2352,42 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
if (DstBank == &AMDGPU::VGPRRegBank)
break;
- // 16-bit operations are VALU only, but can be promoted to 32-bit SALU.
- MachineFunction *MF = MI.getParent()->getParent();
+ const LLT S32 = LLT::scalar(32);
+ MachineBasicBlock *MBB = MI.getParent();
+ MachineFunction *MF = MBB->getParent();
MachineIRBuilder B(MI);
ApplyRegBankMapping ApplySALU(*this, MRI, &AMDGPU::SGPRRegBank);
GISelObserverWrapper Observer(&ApplySALU);
- LegalizerHelper Helper(*MF, Observer, B);
- if (Helper.widenScalar(MI, 0, LLT::scalar(32)) !=
- LegalizerHelper::Legalized)
- llvm_unreachable("widen scalar should have succeeded");
+ if (DstTy.isVector()) {
+ B.setChangeObserver(Observer);
+
+ Register WideSrc0Lo, WideSrc0Hi;
+ Register WideSrc1Lo, WideSrc1Hi;
+
+ std::tie(WideSrc0Lo, WideSrc0Hi)
+ = unpackV2S16ToS32(B, MI.getOperand(1).getReg(), AMDGPU::G_ANYEXT);
+ std::tie(WideSrc1Lo, WideSrc1Hi)
+ = unpackV2S16ToS32(B, MI.getOperand(2).getReg(), AMDGPU::G_ANYEXT);
+ auto Lo = B.buildInstr(MI.getOpcode(), {S32}, {WideSrc0Lo, WideSrc1Lo});
+ auto Hi = B.buildInstr(MI.getOpcode(), {S32}, {WideSrc0Hi, WideSrc1Hi});
+ B.buildBuildVectorTrunc(DstReg, {Lo.getReg(0), Hi.getReg(0)});
+ MI.eraseFromParent();
+ } else {
+ LegalizerHelper Helper(*MF, Observer, B);
+
+ if (Helper.widenScalar(MI, 0, S32) != LegalizerHelper::Legalized)
+ llvm_unreachable("widen scalar should have succeeded");
+
+ // FIXME: s16 shift amounts should be legal.
+ if (Opc == AMDGPU::G_SHL || Opc == AMDGPU::G_LSHR ||
+ Opc == AMDGPU::G_ASHR) {
+ B.setInsertPt(*MBB, MI.getIterator());
+ if (Helper.widenScalar(MI, 1, S32) != LegalizerHelper::Legalized)
+ llvm_unreachable("widen scalar should have succeeded");
+ }
+ }
+
return;
}
case AMDGPU::G_SMIN:
@@ -1750,10 +2405,44 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
// Turn scalar min/max into a compare and select.
LLT Ty = MRI.getType(DstReg);
- LLT S32 = LLT::scalar(32);
- LLT S16 = LLT::scalar(16);
+ const LLT S32 = LLT::scalar(32);
+ const LLT S16 = LLT::scalar(16);
+ const LLT V2S16 = LLT::vector(2, 16);
+
+ if (Ty == V2S16) {
+ ApplyRegBankMapping ApplySALU(*this, MRI, &AMDGPU::SGPRRegBank);
+ GISelObserverWrapper Observer(&ApplySALU);
+ B.setChangeObserver(Observer);
- if (Ty == S16) {
+ // Need to widen to s32, and expand as cmp + select, and avoid producing
+ // illegal vector extends or unmerges that would need further
+ // legalization.
+ //
+ // TODO: Should we just readfirstlane? That should probably be handled
+ // with a UniformVGPR register bank that wouldn't need special
+ // consideration here.
+
+ Register Dst = MI.getOperand(0).getReg();
+ Register Src0 = MI.getOperand(1).getReg();
+ Register Src1 = MI.getOperand(2).getReg();
+
+ Register WideSrc0Lo, WideSrc0Hi;
+ Register WideSrc1Lo, WideSrc1Hi;
+
+ unsigned ExtendOp = minMaxToExtend(MI.getOpcode());
+
+ std::tie(WideSrc0Lo, WideSrc0Hi) = unpackV2S16ToS32(B, Src0, ExtendOp);
+ std::tie(WideSrc1Lo, WideSrc1Hi) = unpackV2S16ToS32(B, Src1, ExtendOp);
+
+ Register Lo = MRI.createGenericVirtualRegister(S32);
+ Register Hi = MRI.createGenericVirtualRegister(S32);
+ const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
+ buildExpandedScalarMinMax(B, Pred, Lo, WideSrc0Lo, WideSrc1Lo);
+ buildExpandedScalarMinMax(B, Pred, Hi, WideSrc0Hi, WideSrc1Hi);
+
+ B.buildBuildVectorTrunc(Dst, {Lo, Hi});
+ MI.eraseFromParent();
+ } else if (Ty == S16) {
ApplyRegBankMapping ApplySALU(*this, MRI, &AMDGPU::SGPRRegBank);
GISelObserverWrapper Observer(&ApplySALU);
LegalizerHelper Helper(*MF, Observer, B);
@@ -1769,11 +2458,77 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
return;
}
+ case AMDGPU::G_SEXT_INREG: {
+ SmallVector<Register, 2> SrcRegs(OpdMapper.getVRegs(1));
+ if (SrcRegs.empty())
+ break; // Nothing to repair
+
+ const LLT S32 = LLT::scalar(32);
+ MachineIRBuilder B(MI);
+ ApplyRegBankMapping O(*this, MRI, &AMDGPU::VGPRRegBank);
+ GISelObserverWrapper Observer(&O);
+ B.setChangeObserver(Observer);
+
+ // Don't use LegalizerHelper's narrowScalar. It produces unwanted G_SEXTs
+ // we would need to further expand, and doesn't let us directly set the
+ // result registers.
+ SmallVector<Register, 2> DstRegs(OpdMapper.getVRegs(0));
+
+ int Amt = MI.getOperand(2).getImm();
+ if (Amt <= 32) {
+ if (Amt == 32) {
+ // The low bits are unchanged.
+ B.buildCopy(DstRegs[0], SrcRegs[0]);
+ } else {
+ // Extend in the low bits and propagate the sign bit to the high half.
+ B.buildSExtInReg(DstRegs[0], SrcRegs[0], Amt);
+ }
+
+ B.buildAShr(DstRegs[1], DstRegs[0], B.buildConstant(S32, 31));
+ } else {
+ // The low bits are unchanged, and extend in the high bits.
+ B.buildCopy(DstRegs[0], SrcRegs[0]);
+ B.buildSExtInReg(DstRegs[1], DstRegs[0], Amt - 32);
+ }
+
+ Register DstReg = MI.getOperand(0).getReg();
+ MRI.setRegBank(DstReg, AMDGPU::VGPRRegBank);
+ MI.eraseFromParent();
+ return;
+ }
+ case AMDGPU::G_CTPOP:
+ case AMDGPU::G_CTLZ_ZERO_UNDEF:
+ case AMDGPU::G_CTTZ_ZERO_UNDEF: {
+ MachineIRBuilder B(MI);
+ MachineFunction &MF = B.getMF();
+
+ const RegisterBank *DstBank =
+ OpdMapper.getInstrMapping().getOperandMapping(0).BreakDown[0].RegBank;
+ if (DstBank == &AMDGPU::SGPRRegBank)
+ break;
+
+ Register SrcReg = MI.getOperand(1).getReg();
+ const LLT S32 = LLT::scalar(32);
+ LLT Ty = MRI.getType(SrcReg);
+ if (Ty == S32)
+ break;
+
+ ApplyRegBankMapping ApplyVALU(*this, MRI, &AMDGPU::VGPRRegBank);
+ GISelObserverWrapper Observer(&ApplyVALU);
+ LegalizerHelper Helper(MF, Observer, B);
+
+ if (Helper.narrowScalar(MI, 1, S32) != LegalizerHelper::Legalized)
+ llvm_unreachable("narrowScalar should have succeeded");
+ return;
+ }
case AMDGPU::G_SEXT:
- case AMDGPU::G_ZEXT: {
+ case AMDGPU::G_ZEXT:
+ case AMDGPU::G_ANYEXT: {
Register SrcReg = MI.getOperand(1).getReg();
LLT SrcTy = MRI.getType(SrcReg);
- bool Signed = Opc == AMDGPU::G_SEXT;
+ const bool Signed = Opc == AMDGPU::G_SEXT;
+
+ assert(empty(OpdMapper.getVRegs(1)));
MachineIRBuilder B(MI);
const RegisterBank *SrcBank =
@@ -1788,23 +2543,19 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
// breakdowns supported.
DstTy.getSizeInBits() == 64 &&
SrcTy.getSizeInBits() <= 32) {
- const LLT S32 = LLT::scalar(32);
SmallVector<Register, 2> DefRegs(OpdMapper.getVRegs(0));
// Extend to 32-bit, and then extend the low half.
if (Signed) {
// TODO: Should really be buildSExtOrCopy
B.buildSExtOrTrunc(DefRegs[0], SrcReg);
-
- // Replicate sign bit from 32-bit extended part.
- auto ShiftAmt = B.buildConstant(S32, 31);
- MRI.setRegBank(ShiftAmt.getReg(0), *SrcBank);
- B.buildAShr(DefRegs[1], DefRegs[0], ShiftAmt);
- } else {
+ } else if (Opc == AMDGPU::G_ZEXT) {
B.buildZExtOrTrunc(DefRegs[0], SrcReg);
- B.buildConstant(DefRegs[1], 0);
+ } else {
+ B.buildAnyExtOrTrunc(DefRegs[0], SrcReg);
}
+ extendLow32IntoHigh32(B, DefRegs[1], DefRegs[0], Opc, *SrcBank);
MRI.setRegBank(DstReg, *SrcBank);
MI.eraseFromParent();
return;
@@ -1813,6 +2564,9 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
if (SrcTy != LLT::scalar(1))
return;
+ // It is not legal to have a legalization artifact with a VCC source. Rather
+ // than introducing a copy, insert the select we would have to select the
+ // copy to.
if (SrcBank == &AMDGPU::VCCRegBank) {
SmallVector<Register, 2> DefRegs(OpdMapper.getVRegs(0));
@@ -1834,7 +2588,7 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
if (DstSize > 32) {
B.buildSelect(DefRegs[0], SrcReg, True, False);
- B.buildCopy(DefRegs[1], DefRegs[0]);
+ extendLow32IntoHigh32(B, DefRegs[1], DefRegs[0], Opc, *SrcBank, true);
} else if (DstSize < 32) {
auto Sel = B.buildSelect(SelType, SrcReg, True, False);
MRI.setRegBank(Sel.getReg(0), *DstBank);
@@ -1847,24 +2601,7 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
return;
}
- // Fixup the case with an s1 src that isn't a condition register. Use shifts
- // instead of introducing a compare to avoid an unnecessary condition
- // register (and since there's no scalar 16-bit compares).
- auto Ext = B.buildAnyExt(DstTy, SrcReg);
- auto ShiftAmt = B.buildConstant(LLT::scalar(32), DstTy.getSizeInBits() - 1);
- auto Shl = B.buildShl(DstTy, Ext, ShiftAmt);
-
- if (MI.getOpcode() == AMDGPU::G_SEXT)
- B.buildAShr(DstReg, Shl, ShiftAmt);
- else
- B.buildLShr(DstReg, Shl, ShiftAmt);
-
- MRI.setRegBank(DstReg, *SrcBank);
- MRI.setRegBank(Ext.getReg(0), *SrcBank);
- MRI.setRegBank(ShiftAmt.getReg(0), *SrcBank);
- MRI.setRegBank(Shl.getReg(0), *SrcBank);
- MI.eraseFromParent();
- return;
+ break;
}
case AMDGPU::G_BUILD_VECTOR:
case AMDGPU::G_BUILD_VECTOR_TRUNC: {
@@ -1934,7 +2671,16 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
assert(OpdMapper.getVRegs(1).empty() && OpdMapper.getVRegs(2).empty());
- LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
+ Register DstReg = MI.getOperand(0).getReg();
+ Register SrcReg = MI.getOperand(1).getReg();
+
+ const LLT S32 = LLT::scalar(32);
+ LLT DstTy = MRI.getType(DstReg);
+ LLT SrcTy = MRI.getType(SrcReg);
+
+ if (foldExtractEltToCmpSelect(MI, MRI, OpdMapper))
+ return;
+
MachineIRBuilder B(MI);
const ValueMapping &DstMapping
@@ -1942,10 +2688,26 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
const RegisterBank *DstBank = DstMapping.BreakDown[0].RegBank;
const RegisterBank *SrcBank =
OpdMapper.getInstrMapping().getOperandMapping(1).BreakDown[0].RegBank;
+ const RegisterBank *IdxBank =
+ OpdMapper.getInstrMapping().getOperandMapping(2).BreakDown[0].RegBank;
- Register DstReg = MI.getOperand(0).getReg();
- Register SrcReg = MI.getOperand(1).getReg();
- Register IdxReg = MI.getOperand(2).getReg();
+ Register BaseIdxReg;
+ unsigned ConstOffset;
+ MachineInstr *OffsetDef;
+ std::tie(BaseIdxReg, ConstOffset, OffsetDef) =
+ AMDGPU::getBaseWithConstantOffset(MRI, MI.getOperand(2).getReg());
+
+ // See if the index is an add of a constant which will be foldable by moving
+ // the base register of the index later if this is going to be executed in a
+ // waterfall loop. This is essentially to reassociate the add of a constant
+ // with the readfirstlane.
+ bool ShouldMoveIndexIntoLoop = IdxBank != &AMDGPU::SGPRRegBank &&
+ ConstOffset > 0 &&
+ ConstOffset < SrcTy.getNumElements();
+
+ // Move the base register. We'll re-insert the add later.
+ if (ShouldMoveIndexIntoLoop)
+ MI.getOperand(2).setReg(BaseIdxReg);
// If this is a VGPR result only because the index was a VGPR result, the
// actual indexing will be done on the SGPR source vector, which will
@@ -1969,26 +2731,30 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
buildVCopy(B, DstReg, TmpReg);
}
+ // Re-insert the constant offset add inside the waterfall loop.
+ if (ShouldMoveIndexIntoLoop)
+ reinsertVectorIndexAdd(B, MI, 2, ConstOffset);
+
return;
}
assert(DstTy.getSizeInBits() == 64);
- LLT SrcTy = MRI.getType(SrcReg);
- const LLT S32 = LLT::scalar(32);
LLT Vec32 = LLT::vector(2 * SrcTy.getNumElements(), 32);
auto CastSrc = B.buildBitcast(Vec32, SrcReg);
auto One = B.buildConstant(S32, 1);
+ MachineBasicBlock::iterator MII = MI.getIterator();
+
// Split the vector index into 32-bit pieces. Prepare to move all of the
// new instructions into a waterfall loop if necessary.
//
// Don't put the bitcast or constant in the loop.
- MachineInstrSpan Span(MachineBasicBlock::iterator(&MI), &B.getMBB());
+ MachineInstrSpan Span(MII, &B.getMBB());
// Compute 32-bit element indices, (2 * OrigIdx, 2 * OrigIdx + 1).
- auto IdxLo = B.buildShl(S32, IdxReg, One);
+ auto IdxLo = B.buildShl(S32, BaseIdxReg, One);
auto IdxHi = B.buildAdd(S32, IdxLo, One);
auto Extract0 = B.buildExtractVectorElement(DstRegs[0], CastSrc, IdxLo);
@@ -2029,33 +2795,70 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
buildVCopy(B, DstRegs[1], TmpReg1);
}
+ if (ShouldMoveIndexIntoLoop)
+ reinsertVectorIndexAdd(B, *IdxLo, 1, ConstOffset);
+
return;
}
case AMDGPU::G_INSERT_VECTOR_ELT: {
SmallVector<Register, 2> InsRegs(OpdMapper.getVRegs(2));
+ Register DstReg = MI.getOperand(0).getReg();
+ LLT VecTy = MRI.getType(DstReg);
+
assert(OpdMapper.getVRegs(0).empty());
- assert(OpdMapper.getVRegs(1).empty());
assert(OpdMapper.getVRegs(3).empty());
- if (InsRegs.empty()) {
- applyDefaultMapping(OpdMapper);
- executeInWaterfallLoop(MI, MRI, { 3 });
+ if (substituteSimpleCopyRegs(OpdMapper, 1))
+ MRI.setType(MI.getOperand(1).getReg(), VecTy);
+
+ if (foldInsertEltToCmpSelect(MI, MRI, OpdMapper))
return;
- }
- Register DstReg = MI.getOperand(0).getReg();
+ const RegisterBank *IdxBank =
+ OpdMapper.getInstrMapping().getOperandMapping(3).BreakDown[0].RegBank;
+
Register SrcReg = MI.getOperand(1).getReg();
Register InsReg = MI.getOperand(2).getReg();
- Register IdxReg = MI.getOperand(3).getReg();
- LLT SrcTy = MRI.getType(SrcReg);
LLT InsTy = MRI.getType(InsReg);
(void)InsTy;
+ Register BaseIdxReg;
+ unsigned ConstOffset;
+ MachineInstr *OffsetDef;
+ std::tie(BaseIdxReg, ConstOffset, OffsetDef) =
+ AMDGPU::getBaseWithConstantOffset(MRI, MI.getOperand(3).getReg());
+
+ // See if the index is an add of a constant which will be foldable by moving
+ // the base register of the index later if this is going to be executed in a
+ // waterfall loop. This is essentially to reassociate the add of a constant
+ // with the readfirstlane.
+ bool ShouldMoveIndexIntoLoop = IdxBank != &AMDGPU::SGPRRegBank &&
+ ConstOffset > 0 &&
+ ConstOffset < VecTy.getNumElements();
+
+ // Move the base register. We'll re-insert the add later.
+ if (ShouldMoveIndexIntoLoop)
+ MI.getOperand(3).setReg(BaseIdxReg);
+
+
+ if (InsRegs.empty()) {
+ executeInWaterfallLoop(MI, MRI, { 3 });
+
+ // Re-insert the constant offset add inside the waterfall loop.
+ if (ShouldMoveIndexIntoLoop) {
+ MachineIRBuilder B(MI);
+ reinsertVectorIndexAdd(B, MI, 3, ConstOffset);
+ }
+
+ return;
+ }
+
+
assert(InsTy.getSizeInBits() == 64);
const LLT S32 = LLT::scalar(32);
- LLT Vec32 = LLT::vector(2 * SrcTy.getNumElements(), 32);
+ LLT Vec32 = LLT::vector(2 * VecTy.getNumElements(), 32);
MachineIRBuilder B(MI);
auto CastSrc = B.buildBitcast(Vec32, SrcReg);
@@ -2068,12 +2871,11 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
MachineInstrSpan Span(MachineBasicBlock::iterator(&MI), &B.getMBB());
// Compute 32-bit element indices, (2 * OrigIdx, 2 * OrigIdx + 1).
- auto IdxLo = B.buildShl(S32, IdxReg, One);
+ auto IdxLo = B.buildShl(S32, BaseIdxReg, One);
auto IdxHi = B.buildAdd(S32, IdxLo, One);
auto InsLo = B.buildInsertVectorElement(Vec32, CastSrc, InsRegs[0], IdxLo);
auto InsHi = B.buildInsertVectorElement(Vec32, InsLo, InsRegs[1], IdxHi);
- B.buildBitcast(DstReg, InsHi);
const RegisterBank *DstBank =
OpdMapper.getInstrMapping().getOperandMapping(0).BreakDown[0].RegBank;
@@ -2093,6 +2895,8 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
SmallSet<Register, 4> OpsToWaterfall;
if (!collectWaterfallOperands(OpsToWaterfall, MI, MRI, { 3 })) {
+ B.setInsertPt(B.getMBB(), MI);
+ B.buildBitcast(DstReg, InsHi);
MI.eraseFromParent();
return;
}
@@ -2100,17 +2904,70 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
B.setInstr(*Span.begin());
MI.eraseFromParent();
+ // Figure out the point after the waterfall loop before mangling the control
+ // flow.
executeInWaterfallLoop(B, make_range(Span.begin(), Span.end()),
OpsToWaterfall, MRI);
+
+ // The insertion point is now right after the original instruction.
+ //
+ // Keep the bitcast to the original vector type out of the loop. Doing this
+ // saved an extra phi we don't need inside the loop.
+ B.buildBitcast(DstReg, InsHi);
+
+ // Re-insert the constant offset add inside the waterfall loop.
+ if (ShouldMoveIndexIntoLoop)
+ reinsertVectorIndexAdd(B, *IdxLo, 1, ConstOffset);
+
+ return;
+ }
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_SSHORT:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_SBYTE:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16:
+ case AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT:
+ case AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT_D16:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_BYTE:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_SHORT:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT_D16:
+ case AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT:
+ case AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT_D16: {
+ applyDefaultMapping(OpdMapper);
+ executeInWaterfallLoop(MI, MRI, {1, 4});
+ return;
+ }
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SWAP:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_ADD:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMIN:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMIN:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMAX:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMAX:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_AND:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_OR:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC: {
+ applyDefaultMapping(OpdMapper);
+ executeInWaterfallLoop(MI, MRI, {2, 5});
+ return;
+ }
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP: {
+ applyDefaultMapping(OpdMapper);
+ executeInWaterfallLoop(MI, MRI, {3, 6});
+ return;
+ }
+ case AMDGPU::G_AMDGPU_S_BUFFER_LOAD: {
+ applyMappingSBufferLoad(OpdMapper);
return;
}
case AMDGPU::G_INTRINSIC: {
switch (MI.getIntrinsicID()) {
- case Intrinsic::amdgcn_s_buffer_load: {
- // FIXME: Move to G_INTRINSIC_W_SIDE_EFFECTS
- executeInWaterfallLoop(MI, MRI, { 2, 3 });
- return;
- }
case Intrinsic::amdgcn_readlane: {
substituteSimpleCopyRegs(OpdMapper, 2);
@@ -2132,18 +2989,51 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
constrainOpWithReadfirstlane(MI, MRI, 3); // Index
return;
}
- default:
- break;
+ case Intrinsic::amdgcn_ballot:
+ case Intrinsic::amdgcn_interp_p1:
+ case Intrinsic::amdgcn_interp_p2:
+ case Intrinsic::amdgcn_interp_mov:
+ case Intrinsic::amdgcn_interp_p1_f16:
+ case Intrinsic::amdgcn_interp_p2_f16: {
+ applyDefaultMapping(OpdMapper);
+
+ // Readlane for m0 value, which is always the last operand.
+ // FIXME: Should this be a waterfall loop instead?
+ constrainOpWithReadfirstlane(MI, MRI, MI.getNumOperands() - 1); // Index
+ return;
+ }
+ case Intrinsic::amdgcn_permlane16:
+ case Intrinsic::amdgcn_permlanex16: {
+ // Doing a waterfall loop over these wouldn't make any sense.
+ substituteSimpleCopyRegs(OpdMapper, 2);
+ substituteSimpleCopyRegs(OpdMapper, 3);
+ constrainOpWithReadfirstlane(MI, MRI, 4);
+ constrainOpWithReadfirstlane(MI, MRI, 5);
+ return;
+ }
+ case Intrinsic::amdgcn_sbfe:
+ applyMappingBFEIntrinsic(OpdMapper, true);
+ return;
+ case Intrinsic::amdgcn_ubfe:
+ applyMappingBFEIntrinsic(OpdMapper, false);
+ return;
}
break;
}
+ case AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD:
+ case AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE: {
+ const AMDGPU::RsrcIntrinsic *RSrcIntrin
+ = AMDGPU::lookupRsrcIntrinsic(MI.getIntrinsicID());
+ assert(RSrcIntrin && RSrcIntrin->IsImage);
+ // Non-images can have complications from operands that allow both SGPR
+ // and VGPR. For now it's too complicated to figure out the final opcode
+ // to derive the register bank from the MCInstrDesc.
+ applyMappingImage(MI, OpdMapper, MRI, RSrcIntrin->RsrcArg);
+ return;
+ }
case AMDGPU::G_INTRINSIC_W_SIDE_EFFECTS: {
auto IntrID = MI.getIntrinsicID();
switch (IntrID) {
- case Intrinsic::amdgcn_buffer_load: {
- executeInWaterfallLoop(MI, MRI, { 2 });
- return;
- }
case Intrinsic::amdgcn_ds_ordered_add:
case Intrinsic::amdgcn_ds_ordered_swap: {
// This is only allowed to execute with 1 lane, so readfirstlane is safe.
@@ -2167,28 +3057,19 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
constrainOpWithReadfirstlane(MI, MRI, 1); // M0
return;
}
+ case Intrinsic::amdgcn_ds_append:
+ case Intrinsic::amdgcn_ds_consume: {
+ constrainOpWithReadfirstlane(MI, MRI, 2); // M0
+ return;
+ }
case Intrinsic::amdgcn_s_sendmsg:
case Intrinsic::amdgcn_s_sendmsghalt: {
// FIXME: Should this use a waterfall loop?
constrainOpWithReadfirstlane(MI, MRI, 2); // M0
return;
}
- case Intrinsic::amdgcn_raw_buffer_load:
- case Intrinsic::amdgcn_raw_buffer_load_format:
- case Intrinsic::amdgcn_raw_tbuffer_load:
- case Intrinsic::amdgcn_raw_buffer_store:
- case Intrinsic::amdgcn_raw_buffer_store_format:
- case Intrinsic::amdgcn_raw_tbuffer_store: {
- applyDefaultMapping(OpdMapper);
- executeInWaterfallLoop(MI, MRI, {2, 4});
- return;
- }
- case Intrinsic::amdgcn_struct_buffer_load:
- case Intrinsic::amdgcn_struct_buffer_store:
- case Intrinsic::amdgcn_struct_tbuffer_load:
- case Intrinsic::amdgcn_struct_tbuffer_store: {
- applyDefaultMapping(OpdMapper);
- executeInWaterfallLoop(MI, MRI, {2, 5});
+ case Intrinsic::amdgcn_s_setreg: {
+ constrainOpWithReadfirstlane(MI, MRI, 2);
return;
}
default: {
@@ -2211,10 +3092,13 @@ void AMDGPURegisterBankInfo::applyMappingImpl(
case AMDGPU::G_LOAD:
case AMDGPU::G_ZEXTLOAD:
case AMDGPU::G_SEXTLOAD: {
- if (applyMappingWideLoad(MI, OpdMapper, MRI))
+ if (applyMappingLoad(MI, OpdMapper, MRI))
return;
break;
}
+ case AMDGPU::G_DYN_STACKALLOC:
+ applyMappingDynStackAlloc(MI, OpdMapper, MRI);
+ return;
default:
break;
}
@@ -2244,7 +3128,11 @@ AMDGPURegisterBankInfo::getDefaultMappingSOP(const MachineInstr &MI) const {
SmallVector<const ValueMapping*, 8> OpdsMapping(MI.getNumOperands());
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
- unsigned Size = getSizeInBits(MI.getOperand(i).getReg(), MRI, *TRI);
+ const MachineOperand &SrcOp = MI.getOperand(i);
+ if (!SrcOp.isReg())
+ continue;
+
+ unsigned Size = getSizeInBits(SrcOp.getReg(), MRI, *TRI);
OpdsMapping[i] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
}
return getInstructionMapping(1, 1, getOperandsMapping(OpdsMapping),
@@ -2256,31 +3144,19 @@ AMDGPURegisterBankInfo::getDefaultMappingVOP(const MachineInstr &MI) const {
const MachineFunction &MF = *MI.getParent()->getParent();
const MachineRegisterInfo &MRI = MF.getRegInfo();
SmallVector<const ValueMapping*, 8> OpdsMapping(MI.getNumOperands());
- unsigned OpdIdx = 0;
-
- unsigned Size0 = getSizeInBits(MI.getOperand(0).getReg(), MRI, *TRI);
- OpdsMapping[OpdIdx++] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size0);
-
- if (MI.getOperand(OpdIdx).isIntrinsicID())
- OpdsMapping[OpdIdx++] = nullptr;
-
- Register Reg1 = MI.getOperand(OpdIdx).getReg();
- unsigned Size1 = getSizeInBits(Reg1, MRI, *TRI);
-
- unsigned DefaultBankID = Size1 == 1 ?
- AMDGPU::VCCRegBankID : AMDGPU::VGPRRegBankID;
- unsigned Bank1 = getRegBankID(Reg1, MRI, *TRI, DefaultBankID);
- OpdsMapping[OpdIdx++] = AMDGPU::getValueMapping(Bank1, Size1);
-
- for (unsigned e = MI.getNumOperands(); OpdIdx != e; ++OpdIdx) {
- const MachineOperand &MO = MI.getOperand(OpdIdx);
- if (!MO.isReg())
+ // Even though we technically could use SGPRs, this would require knowledge of
+ // the constant bus restriction. Force all sources to VGPR (except for VCC).
+ //
+ // TODO: Unary ops are trivially OK, so accept SGPRs?
+ for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
+ const MachineOperand &Src = MI.getOperand(i);
+ if (!Src.isReg())
continue;
- unsigned Size = getSizeInBits(MO.getReg(), MRI, *TRI);
+ unsigned Size = getSizeInBits(Src.getReg(), MRI, *TRI);
unsigned BankID = Size == 1 ? AMDGPU::VCCRegBankID : AMDGPU::VGPRRegBankID;
- OpdsMapping[OpdIdx] = AMDGPU::getValueMapping(BankID, Size);
+ OpdsMapping[i] = AMDGPU::getValueMapping(BankID, Size);
}
return getInstructionMapping(1, 1, getOperandsMapping(OpdsMapping),
@@ -2324,6 +3200,10 @@ AMDGPURegisterBankInfo::getImageMapping(const MachineRegisterInfo &MRI,
continue;
Register OpReg = MI.getOperand(I).getReg();
+ // We replace some dead address operands with $noreg
+ if (!OpReg)
+ continue;
+
unsigned Size = getSizeInBits(OpReg, MRI, *TRI);
// FIXME: Probably need a new intrinsic register bank searchable table to
@@ -2345,6 +3225,22 @@ AMDGPURegisterBankInfo::getImageMapping(const MachineRegisterInfo &MRI,
return getInstructionMapping(1, 1, getOperandsMapping(OpdsMapping), NumOps);
}
+/// Return the mapping for a pointer arugment.
+const RegisterBankInfo::ValueMapping *
+AMDGPURegisterBankInfo::getValueMappingForPtr(const MachineRegisterInfo &MRI,
+ Register PtrReg) const {
+ LLT PtrTy = MRI.getType(PtrReg);
+ unsigned Size = PtrTy.getSizeInBits();
+ if (Subtarget.useFlatForGlobal() ||
+ !SITargetLowering::isFlatGlobalAddrSpace(PtrTy.getAddressSpace()))
+ return AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+
+ // If we're using MUBUF instructions for global memory, an SGPR base register
+ // is possible. Otherwise this needs to be a VGPR.
+ const RegisterBank *PtrBank = getRegBank(PtrReg, MRI, *TRI);
+ return AMDGPU::getValueMapping(PtrBank->getID(), Size);
+}
+
const RegisterBankInfo::InstructionMapping &
AMDGPURegisterBankInfo::getInstrMappingForLoad(const MachineInstr &MI) const {
@@ -2352,7 +3248,6 @@ AMDGPURegisterBankInfo::getInstrMappingForLoad(const MachineInstr &MI) const {
const MachineRegisterInfo &MRI = MF.getRegInfo();
SmallVector<const ValueMapping*, 2> OpdsMapping(2);
unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, *TRI);
- LLT LoadTy = MRI.getType(MI.getOperand(0).getReg());
Register PtrReg = MI.getOperand(1).getReg();
LLT PtrTy = MRI.getType(PtrReg);
unsigned AS = PtrTy.getAddressSpace();
@@ -2364,14 +3259,23 @@ AMDGPURegisterBankInfo::getInstrMappingForLoad(const MachineInstr &MI) const {
const RegisterBank *PtrBank = getRegBank(PtrReg, MRI, *TRI);
if (PtrBank == &AMDGPU::SGPRRegBank &&
- (AS != AMDGPUAS::LOCAL_ADDRESS && AS != AMDGPUAS::REGION_ADDRESS &&
- AS != AMDGPUAS::PRIVATE_ADDRESS) &&
- isScalarLoadLegal(MI)) {
- // We have a uniform instruction so we want to use an SMRD load
- ValMapping = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
- PtrMapping = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, PtrSize);
+ SITargetLowering::isFlatGlobalAddrSpace(AS)) {
+ if (isScalarLoadLegal(MI)) {
+ // We have a uniform instruction so we want to use an SMRD load
+ ValMapping = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
+ PtrMapping = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, PtrSize);
+ } else {
+ ValMapping = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+
+ // If we're using MUBUF instructions for global memory, an SGPR base
+ // register is possible. Otherwise this needs to be a VGPR.
+ unsigned PtrBankID = Subtarget.useFlatForGlobal() ?
+ AMDGPU::VGPRRegBankID : AMDGPU::SGPRRegBankID;
+
+ PtrMapping = AMDGPU::getValueMapping(PtrBankID, PtrSize);
+ }
} else {
- ValMapping = AMDGPU::getValueMappingLoadSGPROnly(AMDGPU::VGPRRegBankID, LoadTy);
+ ValMapping = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
PtrMapping = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, PtrSize);
}
@@ -2449,11 +3353,35 @@ AMDGPURegisterBankInfo::getAGPROpMapping(Register Reg,
/// in RegBankSelect::Mode::Fast. Any mapping that would cause a
/// VGPR to SGPR generated is illegal.
///
+// Operands that must be SGPRs must accept potentially divergent VGPRs as
+// legal. These will be dealt with in applyMappingImpl.
+//
const RegisterBankInfo::InstructionMapping &
AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
const MachineFunction &MF = *MI.getParent()->getParent();
const MachineRegisterInfo &MRI = MF.getRegInfo();
+ if (MI.isCopy()) {
+ // The default logic bothers to analyze impossible alternative mappings. We
+ // want the most straightforward mapping, so just directly handle this.
+ const RegisterBank *DstBank = getRegBank(MI.getOperand(0).getReg(), MRI,
+ *TRI);
+ const RegisterBank *SrcBank = getRegBank(MI.getOperand(1).getReg(), MRI,
+ *TRI);
+ assert(SrcBank && "src bank should have been assigned already");
+ if (!DstBank)
+ DstBank = SrcBank;
+
+ unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, *TRI);
+ if (cannotCopy(*DstBank, *SrcBank, Size))
+ return getInvalidInstructionMapping();
+
+ const ValueMapping &ValMap = getValueMapping(0, Size, *DstBank);
+ return getInstructionMapping(
+ 1, /*Cost*/ 1,
+ /*OperandsMapping*/ getOperandsMapping({&ValMap}), 1);
+ }
+
if (MI.isRegSequence()) {
// If any input is a VGPR, the result must be a VGPR. The default handling
// assumes any copy between banks is legal.
@@ -2592,6 +3520,7 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
LLVM_FALLTHROUGH;
}
case AMDGPU::G_PTR_ADD:
+ case AMDGPU::G_PTRMASK:
case AMDGPU::G_ADD:
case AMDGPU::G_SUB:
case AMDGPU::G_MUL:
@@ -2608,6 +3537,7 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_SMAX:
case AMDGPU::G_UMIN:
case AMDGPU::G_UMAX:
+ case AMDGPU::G_SHUFFLE_VECTOR:
if (isSALUMapping(MI))
return getDefaultMappingSOP(MI);
LLVM_FALLTHROUGH;
@@ -2635,7 +3565,16 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_FMAXNUM_IEEE:
case AMDGPU::G_FCANONICALIZE:
case AMDGPU::G_INTRINSIC_TRUNC:
+ case AMDGPU::G_BSWAP: // TODO: Somehow expand for scalar?
+ case AMDGPU::G_FSHR: // TODO: Expand for scalar
case AMDGPU::G_AMDGPU_FFBH_U32:
+ case AMDGPU::G_AMDGPU_FMIN_LEGACY:
+ case AMDGPU::G_AMDGPU_FMAX_LEGACY:
+ case AMDGPU::G_AMDGPU_RCP_IFLAG:
+ case AMDGPU::G_AMDGPU_CVT_F32_UBYTE0:
+ case AMDGPU::G_AMDGPU_CVT_F32_UBYTE1:
+ case AMDGPU::G_AMDGPU_CVT_F32_UBYTE2:
+ case AMDGPU::G_AMDGPU_CVT_F32_UBYTE3:
return getDefaultMappingVOP(MI);
case AMDGPU::G_UMULH:
case AMDGPU::G_SMULH: {
@@ -2664,6 +3603,13 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
break;
}
+ case AMDGPU::G_DYN_STACKALLOC: {
+ // Result is always uniform, and a wave reduction is needed for the source.
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, 32);
+ unsigned SrcBankID = getRegBankID(MI.getOperand(1).getReg(), MRI, *TRI);
+ OpdsMapping[1] = AMDGPU::getValueMapping(SrcBankID, 32);
+ break;
+ }
case AMDGPU::G_INSERT: {
unsigned BankID = isSALUMapping(MI) ? AMDGPU::SGPRRegBankID :
AMDGPU::VGPRRegBankID;
@@ -2719,12 +3665,6 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_BITCAST:
case AMDGPU::G_INTTOPTR:
case AMDGPU::G_PTRTOINT:
- case AMDGPU::G_CTLZ:
- case AMDGPU::G_CTLZ_ZERO_UNDEF:
- case AMDGPU::G_CTTZ:
- case AMDGPU::G_CTTZ_ZERO_UNDEF:
- case AMDGPU::G_CTPOP:
- case AMDGPU::G_BSWAP:
case AMDGPU::G_BITREVERSE:
case AMDGPU::G_FABS:
case AMDGPU::G_FNEG: {
@@ -2733,21 +3673,33 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[0] = OpdsMapping[1] = AMDGPU::getValueMapping(BankID, Size);
break;
}
+ case AMDGPU::G_CTLZ_ZERO_UNDEF:
+ case AMDGPU::G_CTTZ_ZERO_UNDEF:
+ case AMDGPU::G_CTPOP: {
+ unsigned Size = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
+ unsigned BankID = getRegBankID(MI.getOperand(1).getReg(), MRI, *TRI);
+ OpdsMapping[0] = AMDGPU::getValueMapping(BankID, 32);
+
+ // This should really be getValueMappingSGPR64Only, but allowing the generic
+ // code to handle the register split just makes using LegalizerHelper more
+ // difficult.
+ OpdsMapping[1] = AMDGPU::getValueMapping(BankID, Size);
+ break;
+ }
case AMDGPU::G_TRUNC: {
Register Dst = MI.getOperand(0).getReg();
Register Src = MI.getOperand(1).getReg();
unsigned Bank = getRegBankID(Src, MRI, *TRI);
unsigned DstSize = getSizeInBits(Dst, MRI, *TRI);
unsigned SrcSize = getSizeInBits(Src, MRI, *TRI);
- OpdsMapping[0] = DstSize == 1 && Bank != AMDGPU::SGPRRegBankID ?
- AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, DstSize) :
- AMDGPU::getValueMapping(Bank, DstSize);
+ OpdsMapping[0] = AMDGPU::getValueMapping(Bank, DstSize);
OpdsMapping[1] = AMDGPU::getValueMapping(Bank, SrcSize);
break;
}
case AMDGPU::G_ZEXT:
case AMDGPU::G_SEXT:
- case AMDGPU::G_ANYEXT: {
+ case AMDGPU::G_ANYEXT:
+ case AMDGPU::G_SEXT_INREG: {
Register Dst = MI.getOperand(0).getReg();
Register Src = MI.getOperand(1).getReg();
unsigned DstSize = getSizeInBits(Dst, MRI, *TRI);
@@ -2765,17 +3717,11 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
break;
}
- // TODO: Should anyext be split into 32-bit part as well?
- if (MI.getOpcode() == AMDGPU::G_ANYEXT) {
- OpdsMapping[0] = AMDGPU::getValueMapping(DstBank, DstSize);
- OpdsMapping[1] = AMDGPU::getValueMapping(SrcBank->getID(), SrcSize);
- } else {
- // Scalar extend can use 64-bit BFE, but VGPRs require extending to
- // 32-bits, and then to 64.
- OpdsMapping[0] = AMDGPU::getValueMappingSGPR64Only(DstBank, DstSize);
- OpdsMapping[1] = AMDGPU::getValueMappingSGPR64Only(SrcBank->getID(),
- SrcSize);
- }
+ // Scalar extend can use 64-bit BFE, but VGPRs require extending to
+ // 32-bits, and then to 64.
+ OpdsMapping[0] = AMDGPU::getValueMappingSGPR64Only(DstBank, DstSize);
+ OpdsMapping[1] = AMDGPU::getValueMappingSGPR64Only(SrcBank->getID(),
+ SrcSize);
break;
}
case AMDGPU::G_FCMP: {
@@ -2790,43 +3736,43 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_STORE: {
assert(MI.getOperand(0).isReg());
unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
- // FIXME: We need to specify a different reg bank once scalar stores
- // are supported.
+
+ // FIXME: We need to specify a different reg bank once scalar stores are
+ // supported.
const ValueMapping *ValMapping =
AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
- // FIXME: Depending on the type of store, the pointer could be in
- // the SGPR Reg bank.
- // FIXME: Pointer size should be based on the address space.
- const ValueMapping *PtrMapping =
- AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 64);
-
OpdsMapping[0] = ValMapping;
- OpdsMapping[1] = PtrMapping;
+ OpdsMapping[1] = getValueMappingForPtr(MRI, MI.getOperand(1).getReg());
break;
}
-
case AMDGPU::G_ICMP: {
auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
unsigned Size = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
+
+ // See if the result register has already been constrained to vcc, which may
+ // happen due to control flow intrinsic lowering.
+ unsigned DstBank = getRegBankID(MI.getOperand(0).getReg(), MRI, *TRI,
+ AMDGPU::SGPRRegBankID);
unsigned Op2Bank = getRegBankID(MI.getOperand(2).getReg(), MRI, *TRI);
unsigned Op3Bank = getRegBankID(MI.getOperand(3).getReg(), MRI, *TRI);
- bool CanUseSCC = Op2Bank == AMDGPU::SGPRRegBankID &&
+ bool CanUseSCC = DstBank == AMDGPU::SGPRRegBankID &&
+ Op2Bank == AMDGPU::SGPRRegBankID &&
Op3Bank == AMDGPU::SGPRRegBankID &&
(Size == 32 || (Size == 64 &&
(Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE) &&
Subtarget.hasScalarCompareEq64()));
- unsigned Op0Bank = CanUseSCC ? AMDGPU::SGPRRegBankID : AMDGPU::VCCRegBankID;
+ DstBank = CanUseSCC ? AMDGPU::SGPRRegBankID : AMDGPU::VCCRegBankID;
+ unsigned SrcBank = CanUseSCC ? AMDGPU::SGPRRegBankID : AMDGPU::VGPRRegBankID;
// TODO: Use 32-bit for scalar output size.
// SCC results will need to be copied to a 32-bit SGPR virtual register.
const unsigned ResultSize = 1;
- OpdsMapping[0] = AMDGPU::getValueMapping(Op0Bank, ResultSize);
- OpdsMapping[1] = nullptr; // Predicate Operand.
- OpdsMapping[2] = AMDGPU::getValueMapping(Op2Bank, Size);
- OpdsMapping[3] = AMDGPU::getValueMapping(Op3Bank, Size);
+ OpdsMapping[0] = AMDGPU::getValueMapping(DstBank, ResultSize);
+ OpdsMapping[2] = AMDGPU::getValueMapping(SrcBank, Size);
+ OpdsMapping[3] = AMDGPU::getValueMapping(SrcBank, Size);
break;
}
case AMDGPU::G_EXTRACT_VECTOR_ELT: {
@@ -2852,15 +3798,22 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
unsigned VecSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
unsigned InsertSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
unsigned IdxSize = MRI.getType(MI.getOperand(3).getReg()).getSizeInBits();
- unsigned SrcBankID = getRegBankID(MI.getOperand(1).getReg(), MRI, *TRI);
unsigned InsertEltBankID = getRegBankID(MI.getOperand(2).getReg(),
MRI, *TRI);
unsigned IdxBankID = getRegBankID(MI.getOperand(3).getReg(), MRI, *TRI);
OpdsMapping[0] = AMDGPU::getValueMapping(OutputBankID, VecSize);
- OpdsMapping[1] = AMDGPU::getValueMapping(SrcBankID, VecSize);
- OpdsMapping[2] = AMDGPU::getValueMappingSGPR64Only(InsertEltBankID,
- InsertSize);
+ OpdsMapping[1] = AMDGPU::getValueMapping(OutputBankID, VecSize);
+
+ // This is a weird case, because we need to break down the mapping based on
+ // the register bank of a different operand.
+ if (InsertSize == 64 && OutputBankID == AMDGPU::VGPRRegBankID) {
+ OpdsMapping[2] = AMDGPU::getValueMappingSplit64(InsertEltBankID,
+ InsertSize);
+ } else {
+ assert(InsertSize == 32 || InsertSize == 64);
+ OpdsMapping[2] = AMDGPU::getValueMapping(InsertEltBankID, InsertSize);
+ }
// The index can be either if the source vector is VGPR.
OpdsMapping[3] = AMDGPU::getValueMapping(IdxBankID, IdxSize);
@@ -2878,6 +3831,116 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
}
break;
}
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_SBYTE:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_SSHORT:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT:
+ case AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16:
+ case AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT:
+ case AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT_D16:
+ case AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT:
+ case AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT_D16:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_BYTE:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_SHORT:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT:
+ case AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT_D16: {
+ OpdsMapping[0] = getVGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+
+ // rsrc
+ OpdsMapping[1] = getSGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+
+ // vindex
+ OpdsMapping[2] = getVGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+
+ // voffset
+ OpdsMapping[3] = getVGPROpMapping(MI.getOperand(3).getReg(), MRI, *TRI);
+
+ // soffset
+ OpdsMapping[4] = getSGPROpMapping(MI.getOperand(4).getReg(), MRI, *TRI);
+
+ // Any remaining operands are immediates and were correctly null
+ // initialized.
+ break;
+ }
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SWAP:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_ADD:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMIN:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMIN:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMAX:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMAX:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_AND:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_OR:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC:
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC: {
+ // vdata_out
+ OpdsMapping[0] = getVGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+
+ // vdata_in
+ OpdsMapping[1] = getVGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+
+ // rsrc
+ OpdsMapping[2] = getSGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+
+ // vindex
+ OpdsMapping[3] = getVGPROpMapping(MI.getOperand(3).getReg(), MRI, *TRI);
+
+ // voffset
+ OpdsMapping[4] = getVGPROpMapping(MI.getOperand(4).getReg(), MRI, *TRI);
+
+ // soffset
+ OpdsMapping[5] = getSGPROpMapping(MI.getOperand(5).getReg(), MRI, *TRI);
+
+ // Any remaining operands are immediates and were correctly null
+ // initialized.
+ break;
+ }
+ case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP: {
+ // vdata_out
+ OpdsMapping[0] = getVGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+
+ // vdata_in
+ OpdsMapping[1] = getVGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+
+ // cmp
+ OpdsMapping[2] = getVGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+
+ // rsrc
+ OpdsMapping[3] = getSGPROpMapping(MI.getOperand(3).getReg(), MRI, *TRI);
+
+ // vindex
+ OpdsMapping[4] = getVGPROpMapping(MI.getOperand(4).getReg(), MRI, *TRI);
+
+ // voffset
+ OpdsMapping[5] = getVGPROpMapping(MI.getOperand(5).getReg(), MRI, *TRI);
+
+ // soffset
+ OpdsMapping[6] = getSGPROpMapping(MI.getOperand(6).getReg(), MRI, *TRI);
+
+ // Any remaining operands are immediates and were correctly null
+ // initialized.
+ break;
+ }
+ case AMDGPU::G_AMDGPU_S_BUFFER_LOAD: {
+ // Lie and claim everything is legal, even though some need to be
+ // SGPRs. applyMapping will have to deal with it as a waterfall loop.
+ OpdsMapping[1] = getSGPROpMapping(MI.getOperand(1).getReg(), MRI, *TRI);
+ OpdsMapping[2] = getSGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+
+ // We need to convert this to a MUBUF if either the resource of offset is
+ // VGPR.
+ unsigned RSrcBank = OpdsMapping[1]->BreakDown[0].RegBank->getID();
+ unsigned OffsetBank = OpdsMapping[2]->BreakDown[0].RegBank->getID();
+ unsigned ResultBank = regBankUnion(RSrcBank, OffsetBank);
+
+ unsigned Size0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ OpdsMapping[0] = AMDGPU::getValueMapping(ResultBank, Size0);
+ break;
+ }
case AMDGPU::G_INTRINSIC: {
switch (MI.getIntrinsicID()) {
default:
@@ -2890,9 +3953,11 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_log_clamp:
case Intrinsic::amdgcn_rcp:
case Intrinsic::amdgcn_rcp_legacy:
+ case Intrinsic::amdgcn_sqrt:
case Intrinsic::amdgcn_rsq:
case Intrinsic::amdgcn_rsq_legacy:
case Intrinsic::amdgcn_rsq_clamp:
+ case Intrinsic::amdgcn_fmul_legacy:
case Intrinsic::amdgcn_ldexp:
case Intrinsic::amdgcn_frexp_mant:
case Intrinsic::amdgcn_frexp_exp:
@@ -2911,8 +3976,6 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_fmad_ftz:
case Intrinsic::amdgcn_mbcnt_lo:
case Intrinsic::amdgcn_mbcnt_hi:
- case Intrinsic::amdgcn_ubfe:
- case Intrinsic::amdgcn_sbfe:
case Intrinsic::amdgcn_mul_u24:
case Intrinsic::amdgcn_mul_i24:
case Intrinsic::amdgcn_lerp:
@@ -2933,13 +3996,21 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_udot4:
case Intrinsic::amdgcn_sdot8:
case Intrinsic::amdgcn_udot8:
- case Intrinsic::amdgcn_wwm:
- case Intrinsic::amdgcn_wqm:
+ return getDefaultMappingVOP(MI);
+ case Intrinsic::amdgcn_sbfe:
+ case Intrinsic::amdgcn_ubfe:
+ if (isSALUMapping(MI))
+ return getDefaultMappingSOP(MI);
return getDefaultMappingVOP(MI);
case Intrinsic::amdgcn_ds_swizzle:
case Intrinsic::amdgcn_ds_permute:
case Intrinsic::amdgcn_ds_bpermute:
case Intrinsic::amdgcn_update_dpp:
+ case Intrinsic::amdgcn_mov_dpp8:
+ case Intrinsic::amdgcn_mov_dpp:
+ case Intrinsic::amdgcn_wwm:
+ case Intrinsic::amdgcn_wqm:
+ case Intrinsic::amdgcn_softwqm:
return getDefaultMappingAllVGPR(MI);
case Intrinsic::amdgcn_kernarg_segment_ptr:
case Intrinsic::amdgcn_s_getpc:
@@ -2954,26 +4025,8 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
= AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, Size);
break;
}
- case Intrinsic::amdgcn_s_buffer_load: {
- // FIXME: This should be moved to G_INTRINSIC_W_SIDE_EFFECTS
- Register RSrc = MI.getOperand(2).getReg(); // SGPR
- Register Offset = MI.getOperand(3).getReg(); // SGPR/imm
-
- unsigned Size0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
- unsigned Size2 = MRI.getType(RSrc).getSizeInBits();
- unsigned Size3 = MRI.getType(Offset).getSizeInBits();
-
- unsigned RSrcBank = getRegBankID(RSrc, MRI, *TRI);
- unsigned OffsetBank = getRegBankID(Offset, MRI, *TRI);
-
- OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size0);
- OpdsMapping[1] = nullptr; // intrinsic id
-
- // Lie and claim everything is legal, even though some need to be
- // SGPRs. applyMapping will have to deal with it as a waterfall loop.
- OpdsMapping[2] = AMDGPU::getValueMapping(RSrcBank, Size2); // rsrc
- OpdsMapping[3] = AMDGPU::getValueMapping(OffsetBank, Size3);
- OpdsMapping[4] = nullptr;
+ case Intrinsic::amdgcn_ps_live: {
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, 1);
break;
}
case Intrinsic::amdgcn_div_scale: {
@@ -2983,11 +4036,8 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[1] = AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, Dst1Size);
unsigned SrcSize = MRI.getType(MI.getOperand(3).getReg()).getSizeInBits();
- OpdsMapping[3] = AMDGPU::getValueMapping(
- getRegBankID(MI.getOperand(3).getReg(), MRI, *TRI), SrcSize);
- OpdsMapping[4] = AMDGPU::getValueMapping(
- getRegBankID(MI.getOperand(4).getReg(), MRI, *TRI), SrcSize);
-
+ OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, SrcSize);
+ OpdsMapping[4] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, SrcSize);
break;
}
case Intrinsic::amdgcn_class: {
@@ -2997,10 +4047,8 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
unsigned Src1Size = MRI.getType(Src1Reg).getSizeInBits();
unsigned DstSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, DstSize);
- OpdsMapping[2] = AMDGPU::getValueMapping(getRegBankID(Src0Reg, MRI, *TRI),
- Src0Size);
- OpdsMapping[3] = AMDGPU::getValueMapping(getRegBankID(Src1Reg, MRI, *TRI),
- Src1Size);
+ OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Src0Size);
+ OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Src1Size);
break;
}
case Intrinsic::amdgcn_icmp:
@@ -3009,10 +4057,8 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
// This is not VCCRegBank because this is not used in boolean contexts.
OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, DstSize);
unsigned OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
- unsigned Op1Bank = getRegBankID(MI.getOperand(2).getReg(), MRI, *TRI);
- unsigned Op2Bank = getRegBankID(MI.getOperand(3).getReg(), MRI, *TRI);
- OpdsMapping[2] = AMDGPU::getValueMapping(Op1Bank, OpSize);
- OpdsMapping[3] = AMDGPU::getValueMapping(Op2Bank, OpSize);
+ OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, OpSize);
+ OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, OpSize);
break;
}
case Intrinsic::amdgcn_readlane: {
@@ -3054,6 +4100,16 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
break;
}
+ case Intrinsic::amdgcn_permlane16:
+ case Intrinsic::amdgcn_permlanex16: {
+ unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, *TRI);
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size);
+ OpdsMapping[4] = getSGPROpMapping(MI.getOperand(3).getReg(), MRI, *TRI);
+ OpdsMapping[5] = getSGPROpMapping(MI.getOperand(4).getReg(), MRI, *TRI);
+ break;
+ }
case Intrinsic::amdgcn_mfma_f32_4x4x1f32:
case Intrinsic::amdgcn_mfma_f32_4x4x4f16:
case Intrinsic::amdgcn_mfma_i32_4x4x4i8:
@@ -3086,9 +4142,46 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[4] = getAGPROpMapping(MI.getOperand(4).getReg(), MRI, *TRI);
break;
}
+ case Intrinsic::amdgcn_interp_p1:
+ case Intrinsic::amdgcn_interp_p2:
+ case Intrinsic::amdgcn_interp_mov:
+ case Intrinsic::amdgcn_interp_p1_f16:
+ case Intrinsic::amdgcn_interp_p2_f16: {
+ const int M0Idx = MI.getNumOperands() - 1;
+ Register M0Reg = MI.getOperand(M0Idx).getReg();
+ unsigned M0Bank = getRegBankID(M0Reg, MRI, *TRI, AMDGPU::SGPRRegBankID);
+ unsigned DstSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, DstSize);
+ for (int I = 2; I != M0Idx && MI.getOperand(I).isReg(); ++I)
+ OpdsMapping[I] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 32);
+
+ // Must be SGPR, but we must take whatever the original bank is and fix it
+ // later.
+ OpdsMapping[M0Idx] = AMDGPU::getValueMapping(M0Bank, 32);
+ break;
+ }
+ case Intrinsic::amdgcn_ballot: {
+ unsigned DstSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ unsigned SrcSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, DstSize);
+ OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::VCCRegBankID, SrcSize);
+ break;
+ }
}
break;
}
+ case AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD:
+ case AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE: {
+ auto IntrID = MI.getIntrinsicID();
+ const AMDGPU::RsrcIntrinsic *RSrcIntrin = AMDGPU::lookupRsrcIntrinsic(IntrID);
+ assert(RSrcIntrin && "missing RsrcIntrinsic for image intrinsic");
+ // Non-images can have complications from operands that allow both SGPR
+ // and VGPR. For now it's too complicated to figure out the final opcode
+ // to derive the register bank from the MCInstrDesc.
+ assert(RSrcIntrin->IsImage);
+ return getImageMapping(MRI, MI, RSrcIntrin->RsrcArg);
+ }
case AMDGPU::G_INTRINSIC_W_SIDE_EFFECTS: {
auto IntrID = MI.getIntrinsicID();
switch (IntrID) {
@@ -3100,13 +4193,9 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
break;
}
- case Intrinsic::amdgcn_ds_append:
- case Intrinsic::amdgcn_ds_consume:
case Intrinsic::amdgcn_ds_fadd:
case Intrinsic::amdgcn_ds_fmin:
case Intrinsic::amdgcn_ds_fmax:
- case Intrinsic::amdgcn_atomic_inc:
- case Intrinsic::amdgcn_atomic_dec:
return getDefaultMappingAllVGPR(MI);
case Intrinsic::amdgcn_ds_ordered_add:
case Intrinsic::amdgcn_ds_ordered_swap: {
@@ -3118,17 +4207,16 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 32);
break;
}
+ case Intrinsic::amdgcn_ds_append:
+ case Intrinsic::amdgcn_ds_consume: {
+ unsigned DstSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, DstSize);
+ OpdsMapping[2] = getSGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+ break;
+ }
case Intrinsic::amdgcn_exp_compr:
- OpdsMapping[0] = nullptr; // IntrinsicID
- // FIXME: These are immediate values which can't be read from registers.
- OpdsMapping[1] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, 32);
- OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, 32);
- // FIXME: Could we support packed types here?
OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 32);
OpdsMapping[4] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 32);
- // FIXME: These are immediate values which can't be read from registers.
- OpdsMapping[5] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, 32);
- OpdsMapping[6] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, 32);
break;
case Intrinsic::amdgcn_exp:
// FIXME: Could we support packed types here?
@@ -3137,31 +4225,6 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[5] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 32);
OpdsMapping[6] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, 32);
break;
- case Intrinsic::amdgcn_buffer_load: {
- Register RSrc = MI.getOperand(2).getReg(); // SGPR
- Register VIndex = MI.getOperand(3).getReg(); // VGPR
- Register Offset = MI.getOperand(4).getReg(); // SGPR/VGPR/imm
-
- unsigned Size0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
- unsigned Size2 = MRI.getType(RSrc).getSizeInBits();
- unsigned Size3 = MRI.getType(VIndex).getSizeInBits();
- unsigned Size4 = MRI.getType(Offset).getSizeInBits();
-
- unsigned RSrcBank = getRegBankID(RSrc, MRI, *TRI);
- unsigned OffsetBank = getRegBankID(Offset, MRI, *TRI);
-
- OpdsMapping[0] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size0);
- OpdsMapping[1] = nullptr; // intrinsic id
-
- // Lie and claim everything is legal, even though some need to be
- // SGPRs. applyMapping will have to deal with it as a waterfall loop.
- OpdsMapping[2] = AMDGPU::getValueMapping(RSrcBank, Size2); // rsrc
- OpdsMapping[3] = AMDGPU::getValueMapping(AMDGPU::VGPRRegBankID, Size3);
- OpdsMapping[4] = AMDGPU::getValueMapping(OffsetBank, Size4);
- OpdsMapping[5] = nullptr;
- OpdsMapping[6] = nullptr;
- break;
- }
case Intrinsic::amdgcn_s_sendmsg:
case Intrinsic::amdgcn_s_sendmsghalt: {
// This must be an SGPR, but accept a VGPR.
@@ -3170,8 +4233,14 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[2] = AMDGPU::getValueMapping(Bank, 32);
break;
}
- case Intrinsic::amdgcn_end_cf:
- case Intrinsic::amdgcn_init_exec: {
+ case Intrinsic::amdgcn_s_setreg: {
+ // This must be an SGPR, but accept a VGPR.
+ unsigned Bank = getRegBankID(MI.getOperand(2).getReg(), MRI, *TRI,
+ AMDGPU::SGPRRegBankID);
+ OpdsMapping[2] = AMDGPU::getValueMapping(Bank, 32);
+ break;
+ }
+ case Intrinsic::amdgcn_end_cf: {
unsigned Size = getSizeInBits(MI.getOperand(1).getReg(), MRI, *TRI);
OpdsMapping[1] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
break;
@@ -3227,7 +4296,6 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::amdgcn_init_exec_from_input: {
unsigned Size = getSizeInBits(MI.getOperand(1).getReg(), MRI, *TRI);
OpdsMapping[1] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
- OpdsMapping[2] = AMDGPU::getValueMapping(AMDGPU::SGPRRegBankID, Size);
break;
}
case Intrinsic::amdgcn_ds_gws_init:
@@ -3251,15 +4319,6 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
break;
}
default:
- if (const AMDGPU::RsrcIntrinsic *RSrcIntrin =
- AMDGPU::lookupRsrcIntrinsic(IntrID)) {
- // Non-images can have complications from operands that allow both SGPR
- // and VGPR. For now it's too complicated to figure out the final opcode
- // to derive the register bank from the MCInstrDesc.
- if (RSrcIntrin->IsImage)
- return getImageMapping(MRI, MI, RSrcIntrin->RsrcArg);
- }
-
return getInvalidInstructionMapping();
}
break;
@@ -3319,9 +4378,20 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case AMDGPU::G_ATOMICRMW_UMAX:
case AMDGPU::G_ATOMICRMW_UMIN:
case AMDGPU::G_ATOMICRMW_FADD:
- case AMDGPU::G_ATOMIC_CMPXCHG:
- case AMDGPU::G_AMDGPU_ATOMIC_CMPXCHG: {
- return getDefaultMappingAllVGPR(MI);
+ case AMDGPU::G_AMDGPU_ATOMIC_CMPXCHG:
+ case AMDGPU::G_AMDGPU_ATOMIC_INC:
+ case AMDGPU::G_AMDGPU_ATOMIC_DEC: {
+ OpdsMapping[0] = getVGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+ OpdsMapping[1] = getValueMappingForPtr(MRI, MI.getOperand(1).getReg());
+ OpdsMapping[2] = getVGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+ break;
+ }
+ case AMDGPU::G_ATOMIC_CMPXCHG: {
+ OpdsMapping[0] = getVGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI);
+ OpdsMapping[1] = getValueMappingForPtr(MRI, MI.getOperand(1).getReg());
+ OpdsMapping[2] = getVGPROpMapping(MI.getOperand(2).getReg(), MRI, *TRI);
+ OpdsMapping[3] = getVGPROpMapping(MI.getOperand(3).getReg(), MRI, *TRI);
+ break;
}
case AMDGPU::G_BRCOND: {
unsigned Bank = getRegBankID(MI.getOperand(0).getReg(), MRI, *TRI,