Skip to content

Commit

Permalink
[CodeGen]Allow targets to use target specific COPY instructions for l…
Browse files Browse the repository at this point in the history
…ive range splitting

Replacing D143754. Right now the LiveRangeSplitting during register allocation uses
TargetOpcode::COPY instruction for splitting. For AMDGPU target that creates a
problem as we have both vector and scalar copies. Vector copies perform a copy over
a vector register but only on the lanes(threads) that are active. This is mostly sufficient
however we do run into cases when we have to copy the entire vector register and
not just active lane data. One major place where we need that is live range splitting.

Allowing targets to use their own copy instructions(if defined) will provide a lot of
flexibility and ease to lower these pseudo instructions to correct MIR.

- Introduce getTargetCopyOpcode() virtual function and use if to generate copy in Live range
 splitting.
- Replace necessary MI.isCopy() checks with TII.isCopyInstr() in register allocator pipeline.

Reviewed By: arsenm, cdevadas, kparzysz

Differential Revision: https://reviews.llvm.org/D150388
  • Loading branch information
Yashwant Singh authored and Yashwant Singh committed Jul 7, 2023
1 parent eb98aba commit b7836d8
Show file tree
Hide file tree
Showing 15 changed files with 148 additions and 107 deletions.
17 changes: 17 additions & 0 deletions llvm/include/llvm/CodeGen/TargetInstrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,16 @@ class TargetInstrInfo : public MCInstrInfo {
return isCopyInstrImpl(MI);
}

bool isFullCopyInstr(const MachineInstr &MI) const {
auto DestSrc = isCopyInstr(MI);
if (!DestSrc)
return false;

const MachineOperand *DestRegOp = DestSrc->Destination;
const MachineOperand *SrcRegOp = DestSrc->Source;
return !DestRegOp->getSubReg() && !SrcRegOp->getSubReg();
}

/// If the specific machine instruction is an instruction that adds an
/// immediate value and a physical register, and stores the result in
/// the given physical register \c Reg, return a pair of the source
Expand Down Expand Up @@ -1958,6 +1968,13 @@ class TargetInstrInfo : public MCInstrInfo {
return false;
}

/// Allows targets to use appropriate copy instruction while spilitting live
/// range of a register in register allocation.
virtual unsigned getLiveRangeSplitOpcode(Register Reg,
const MachineFunction &MF) const {
return TargetOpcode::COPY;
}

/// During PHI eleimination lets target to make necessary checks and
/// insert the copy to the PHI destination register in a target specific
/// manner.
Expand Down
15 changes: 12 additions & 3 deletions llvm/lib/CodeGen/CalcSpillWeights.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ bool VirtRegAuxInfo::isRematerializable(const LiveInterval &LI,
// Trace copies introduced by live range splitting. The inline
// spiller can rematerialize through these copies, so the spill
// weight must reflect this.
while (MI->isFullCopy()) {
while (TII.isFullCopyInstr(*MI)) {
// The copy destination must match the interval register.
if (MI->getOperand(0).getReg() != Reg)
return false;
Expand Down Expand Up @@ -224,7 +224,16 @@ float VirtRegAuxInfo::weightCalcHelper(LiveInterval &LI, SlotIndex *Start,
continue;

NumInstr++;
if (MI->isIdentityCopy() || MI->isImplicitDef())
bool identityCopy = false;
auto DestSrc = TII.isCopyInstr(*MI);
if (DestSrc) {
const MachineOperand *DestRegOp = DestSrc->Destination;
const MachineOperand *SrcRegOp = DestSrc->Source;
identityCopy = DestRegOp->getReg() == SrcRegOp->getReg() &&
DestRegOp->getSubReg() == SrcRegOp->getSubReg();
}

if (identityCopy || MI->isImplicitDef())
continue;
if (!Visited.insert(MI).second)
continue;
Expand Down Expand Up @@ -258,7 +267,7 @@ float VirtRegAuxInfo::weightCalcHelper(LiveInterval &LI, SlotIndex *Start,
}

// Get allocation hints from copies.
if (!MI->isCopy())
if (!TII.isCopyInstr(*MI))
continue;
Register HintReg = copyHint(MI, LI.reg(), TRI, MRI);
if (!HintReg)
Expand Down
29 changes: 15 additions & 14 deletions llvm/lib/CodeGen/InlineSpiller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,11 @@ Spiller *llvm::createInlineSpiller(MachineFunctionPass &Pass,
// This minimizes register pressure and maximizes the store-to-load distance for
// spill slots which can be important in tight loops.

/// If MI is a COPY to or from Reg, return the other register, otherwise return
/// 0.
static Register isCopyOf(const MachineInstr &MI, Register Reg) {
assert(!MI.isBundled());
if (!MI.isCopy())
/// isFullCopyOf - If MI is a COPY to or from Reg, return the other register,
/// otherwise return 0.
static Register isCopyOf(const MachineInstr &MI, Register Reg,
const TargetInstrInfo &TII) {
if (!TII.isCopyInstr(MI))
return Register();

const MachineOperand &DstOp = MI.getOperand(0);
Expand All @@ -277,9 +277,10 @@ static Register isCopyOf(const MachineInstr &MI, Register Reg) {
}

/// Check for a copy bundle as formed by SplitKit.
static Register isCopyOfBundle(const MachineInstr &FirstMI, Register Reg) {
static Register isCopyOfBundle(const MachineInstr &FirstMI, Register Reg,
const TargetInstrInfo &TII) {
if (!FirstMI.isBundled())
return isCopyOf(FirstMI, Reg);
return isCopyOf(FirstMI, Reg, TII);

assert(!FirstMI.isBundledWithPred() && FirstMI.isBundledWithSucc() &&
"expected to see first instruction in bundle");
Expand All @@ -288,7 +289,7 @@ static Register isCopyOfBundle(const MachineInstr &FirstMI, Register Reg) {
MachineBasicBlock::const_instr_iterator I = FirstMI.getIterator();
while (I->isBundledWithSucc()) {
const MachineInstr &MI = *I;
if (!MI.isCopy())
if (!TII.isCopyInstr(FirstMI))
return Register();

const MachineOperand &DstOp = MI.getOperand(0);
Expand Down Expand Up @@ -358,7 +359,7 @@ bool InlineSpiller::isSnippet(const LiveInterval &SnipLI) {
MachineInstr &MI = *RI++;

// Allow copies to/from Reg.
if (isCopyOfBundle(MI, Reg))
if (isCopyOfBundle(MI, Reg, TII))
continue;

// Allow stack slot loads.
Expand Down Expand Up @@ -396,7 +397,7 @@ void InlineSpiller::collectRegsToSpill() {
return;

for (MachineInstr &MI : llvm::make_early_inc_range(MRI.reg_bundles(Reg))) {
Register SnipReg = isCopyOfBundle(MI, Reg);
Register SnipReg = isCopyOfBundle(MI, Reg, TII);
if (!isSibling(SnipReg))
continue;
LiveInterval &SnipLI = LIS.getInterval(SnipReg);
Expand Down Expand Up @@ -519,14 +520,14 @@ void InlineSpiller::eliminateRedundantSpills(LiveInterval &SLI, VNInfo *VNI) {
// Find all spills and copies of VNI.
for (MachineInstr &MI :
llvm::make_early_inc_range(MRI.use_nodbg_bundles(Reg))) {
if (!MI.isCopy() && !MI.mayStore())
if (!MI.mayStore() && !TII.isCopyInstr(MI))
continue;
SlotIndex Idx = LIS.getInstructionIndex(MI);
if (LI->getVNInfoAt(Idx) != VNI)
continue;

// Follow sibling copies down the dominator tree.
if (Register DstReg = isCopyOfBundle(MI, Reg)) {
if (Register DstReg = isCopyOfBundle(MI, Reg, TII)) {
if (isSibling(DstReg)) {
LiveInterval &DstLI = LIS.getInterval(DstReg);
VNInfo *DstVNI = DstLI.getVNInfoAt(Idx.getRegSlot());
Expand Down Expand Up @@ -870,7 +871,7 @@ foldMemoryOperand(ArrayRef<std::pair<MachineInstr *, unsigned>> Ops,
if (Ops.back().first != MI || MI->isBundled())
return false;

bool WasCopy = MI->isCopy();
bool WasCopy = TII.isCopyInstr(*MI).has_value();
Register ImpReg;

// TII::foldMemoryOperand will do what we need here for statepoint
Expand Down Expand Up @@ -1155,7 +1156,7 @@ void InlineSpiller::spillAroundUses(Register Reg) {
Idx = VNI->def;

// Check for a sibling copy.
Register SibReg = isCopyOfBundle(MI, Reg);
Register SibReg = isCopyOfBundle(MI, Reg, TII);
if (SibReg && isSibling(SibReg)) {
// This may actually be a copy between snippets.
if (isRegToSpill(SibReg)) {
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/CodeGen/LiveRangeEdit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
// unlikely to change anything. We typically don't want to shrink the
// PIC base register that has lots of uses everywhere.
// Always shrink COPY uses that probably come from live range splitting.
if ((MI->readsVirtualRegister(Reg) && (MI->isCopy() || MO.isDef())) ||
if ((MI->readsVirtualRegister(Reg) &&
(MO.isDef() || TII.isCopyInstr(*MI))) ||
(MO.readsReg() && (MRI.hasOneNonDBGUse(Reg) || useIsKill(LI, MO))))
ToShrink.insert(&LI);
else if (MO.readsReg())
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/CodeGen/LiveRangeShrink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
Expand Down Expand Up @@ -109,6 +110,7 @@ bool LiveRangeShrink::runOnMachineFunction(MachineFunction &MF) {
return false;

MachineRegisterInfo &MRI = MF.getRegInfo();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();

LLVM_DEBUG(dbgs() << "**** Analysing " << MF.getName() << '\n');

Expand Down Expand Up @@ -197,7 +199,7 @@ bool LiveRangeShrink::runOnMachineFunction(MachineFunction &MF) {
// is because it needs more accurate model to handle register
// pressure correctly.
MachineInstr &DefInstr = *MRI.def_instr_begin(Reg);
if (!DefInstr.isCopy())
if (!TII.isCopyInstr(DefInstr))
NumEligibleUse++;
Insert = FindDominatedInstruction(DefInstr, Insert, IOM);
} else {
Expand Down
21 changes: 12 additions & 9 deletions llvm/lib/CodeGen/RegAllocGreedy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1282,10 +1282,12 @@ static LaneBitmask getInstReadLaneMask(const MachineRegisterInfo &MRI,
/// VirtReg.
static bool readsLaneSubset(const MachineRegisterInfo &MRI,
const MachineInstr *MI, const LiveInterval &VirtReg,
const TargetRegisterInfo *TRI, SlotIndex Use) {
const TargetRegisterInfo *TRI, SlotIndex Use,
const TargetInstrInfo *TII) {
// Early check the common case.
if (MI->isCopy() &&
MI->getOperand(0).getSubReg() == MI->getOperand(1).getSubReg())
auto DestSrc = TII->isCopyInstr(*MI);
if (DestSrc &&
DestSrc->Destination->getSubReg() == DestSrc->Source->getSubReg())
return false;

// FIXME: We're only considering uses, but should be consider defs too?
Expand Down Expand Up @@ -1344,14 +1346,14 @@ unsigned RAGreedy::tryInstructionSplit(const LiveInterval &VirtReg,
// the allocation.
for (const SlotIndex Use : Uses) {
if (const MachineInstr *MI = Indexes->getInstructionFromIndex(Use)) {
if (MI->isFullCopy() ||
if (TII->isFullCopyInstr(*MI) ||
(SplitSubClass &&
SuperRCNumAllocatableRegs ==
getNumAllocatableRegsForConstraints(MI, VirtReg.reg(), SuperRC,
TII, TRI, RegClassInfo)) ||
// TODO: Handle split for subranges with subclass constraints?
(!SplitSubClass && VirtReg.hasSubRanges() &&
!readsLaneSubset(*MRI, MI, VirtReg, TRI, Use))) {
!readsLaneSubset(*MRI, MI, VirtReg, TRI, Use, TII))) {
LLVM_DEBUG(dbgs() << " skip:\t" << Use << '\t' << *MI);
continue;
}
Expand Down Expand Up @@ -2138,7 +2140,7 @@ void RAGreedy::initializeCSRCost() {
/// \p Out is not cleared before being populated.
void RAGreedy::collectHintInfo(Register Reg, HintsInfo &Out) {
for (const MachineInstr &Instr : MRI->reg_nodbg_instructions(Reg)) {
if (!Instr.isFullCopy())
if (!TII->isFullCopyInstr(Instr))
continue;
// Look for the other end of the copy.
Register OtherReg = Instr.getOperand(0).getReg();
Expand Down Expand Up @@ -2453,9 +2455,10 @@ RAGreedy::RAGreedyStats RAGreedy::computeStats(MachineBasicBlock &MBB) {
MI.getOpcode() == TargetOpcode::STATEPOINT;
};
for (MachineInstr &MI : MBB) {
if (MI.isCopy()) {
const MachineOperand &Dest = MI.getOperand(0);
const MachineOperand &Src = MI.getOperand(1);
auto DestSrc = TII->isCopyInstr(MI);
if (DestSrc) {
const MachineOperand &Dest = *DestSrc->Destination;
const MachineOperand &Src = *DestSrc->Source;
Register SrcReg = Src.getReg();
Register DestReg = Dest.getReg();
// Only count `COPY`s with a virtual register as source or destination.
Expand Down
17 changes: 10 additions & 7 deletions llvm/lib/CodeGen/SplitKit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,10 +514,10 @@ void SplitEditor::forceRecompute(unsigned RegIdx, const VNInfo &ParentVNI) {
VFP = ValueForcePair(nullptr, true);
}

SlotIndex SplitEditor::buildSingleSubRegCopy(Register FromReg, Register ToReg,
MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore,
unsigned SubIdx, LiveInterval &DestLI, bool Late, SlotIndex Def) {
const MCInstrDesc &Desc = TII.get(TargetOpcode::COPY);
SlotIndex SplitEditor::buildSingleSubRegCopy(
Register FromReg, Register ToReg, MachineBasicBlock &MBB,
MachineBasicBlock::iterator InsertBefore, unsigned SubIdx,
LiveInterval &DestLI, bool Late, SlotIndex Def, const MCInstrDesc &Desc) {
bool FirstCopy = !Def.isValid();
MachineInstr *CopyMI = BuildMI(MBB, InsertBefore, DebugLoc(), Desc)
.addReg(ToReg, RegState::Define | getUndefRegState(FirstCopy)
Expand All @@ -536,7 +536,8 @@ SlotIndex SplitEditor::buildSingleSubRegCopy(Register FromReg, Register ToReg,
SlotIndex SplitEditor::buildCopy(Register FromReg, Register ToReg,
LaneBitmask LaneMask, MachineBasicBlock &MBB,
MachineBasicBlock::iterator InsertBefore, bool Late, unsigned RegIdx) {
const MCInstrDesc &Desc = TII.get(TargetOpcode::COPY);
const MCInstrDesc &Desc =
TII.get(TII.getLiveRangeSplitOpcode(FromReg, *MBB.getParent()));
SlotIndexes &Indexes = *LIS.getSlotIndexes();
if (LaneMask.all() || LaneMask == MRI.getMaxLaneMaskForVReg(FromReg)) {
// The full vreg is copied.
Expand Down Expand Up @@ -564,7 +565,7 @@ SlotIndex SplitEditor::buildCopy(Register FromReg, Register ToReg,
SlotIndex Def;
for (unsigned BestIdx : SubIndexes) {
Def = buildSingleSubRegCopy(FromReg, ToReg, MBB, InsertBefore, BestIdx,
DestLI, Late, Def);
DestLI, Late, Def, Desc);
}

BumpPtrAllocator &Allocator = LIS.getVNInfoAllocator();
Expand Down Expand Up @@ -1584,7 +1585,9 @@ bool SplitAnalysis::shouldSplitSingleBlock(const BlockInfo &BI,
if (BI.LiveIn && BI.LiveOut)
return true;
// No point in isolating a copy. It has no register class constraints.
if (LIS.getInstructionFromIndex(BI.FirstInstr)->isCopyLike())
MachineInstr *MI = LIS.getInstructionFromIndex(BI.FirstInstr);
bool copyLike = TII.isCopyInstr(*MI) || MI->isSubregToReg();
if (copyLike)
return false;
// Finally, don't isolate an end point that was created by earlier splits.
return isOriginalEndpoint(BI.FirstInstr);
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/CodeGen/SplitKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,11 @@ class LLVM_LIBRARY_VISIBILITY SplitEditor {
bool Late, unsigned RegIdx);

SlotIndex buildSingleSubRegCopy(Register FromReg, Register ToReg,
MachineBasicBlock &MB, MachineBasicBlock::iterator InsertBefore,
unsigned SubIdx, LiveInterval &DestLI, bool Late, SlotIndex Def);
MachineBasicBlock &MB,
MachineBasicBlock::iterator InsertBefore,
unsigned SubIdx, LiveInterval &DestLI,
bool Late, SlotIndex Def,
const MCInstrDesc &Desc);

public:
/// Create a new SplitEditor for editing the LiveInterval analyzed by SA.
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/CodeGen/TargetInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,9 @@ MachineInstr &TargetInstrInfo::duplicate(MachineBasicBlock &MBB,
// If the COPY instruction in MI can be folded to a stack operation, return
// the register class to use.
static const TargetRegisterClass *canFoldCopy(const MachineInstr &MI,
const TargetInstrInfo &TII,
unsigned FoldIdx) {
assert(MI.isCopy() && "MI must be a COPY instruction");
assert(TII.isCopyInstr(MI) && "MI must be a COPY instruction");
if (MI.getNumOperands() != 2)
return nullptr;
assert(FoldIdx<2 && "FoldIdx refers no nonexistent operand");
Expand Down Expand Up @@ -630,10 +631,10 @@ MachineInstr *TargetInstrInfo::foldMemoryOperand(MachineInstr &MI,
}

// Straight COPY may fold as load/store.
if (!MI.isCopy() || Ops.size() != 1)
if (!isCopyInstr(MI) || Ops.size() != 1)
return nullptr;

const TargetRegisterClass *RC = canFoldCopy(MI, Ops[0]);
const TargetRegisterClass *RC = canFoldCopy(MI, *this, Ops[0]);
if (!RC)
return nullptr;

Expand Down
Loading

0 comments on commit b7836d8

Please sign in to comment.