Skip to content

Commit 4df6d3d

Browse files
Reland "RegisterCoalescer: Add implicit-def of super register when coalescing SUBREG_TO_REG" (#123632)
This PR aims to reland work done by @arsenm which was previously reverted due to some tangentially related scheduler issues as discussed on #76416. This PR cherry-picks the original commit (0e46b49), and adds another patch on top with the following changes: * The code in `updateRegDefsUses` now updates subranges when subreg-liveness-tracking is enabled. * When adding an implicit-def operand for the super-register, the code in `reMaterializeTrivialDef` which tries to remove undefined subranges should now take into account that the lanes from the super-reg are no longer undefined. Co-authored-by: Matt Arsenault <[email protected]>
1 parent 76672e3 commit 4df6d3d

24 files changed

+1263
-154
lines changed

llvm/lib/CodeGen/RegisterCoalescer.cpp

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,11 @@ namespace {
306306
/// number if it is not zero. If DstReg is a physical register and the
307307
/// existing subregister number of the def / use being updated is not zero,
308308
/// make sure to set it to the correct physical subregister.
309-
void updateRegDefsUses(Register SrcReg, Register DstReg, unsigned SubIdx);
309+
///
310+
/// If \p IsSubregToReg, we are coalescing a DstReg = SUBREG_TO_REG
311+
/// SrcReg. This introduces an implicit-def of DstReg on coalesced users.
312+
void updateRegDefsUses(Register SrcReg, Register DstReg, unsigned SubIdx,
313+
bool IsSubregToReg);
310314

311315
/// If the given machine operand reads only undefined lanes add an undef
312316
/// flag.
@@ -1430,6 +1434,7 @@ bool RegisterCoalescer::reMaterializeTrivialDef(const CoalescerPair &CP,
14301434

14311435
// CopyMI may have implicit operands, save them so that we can transfer them
14321436
// over to the newly materialized instruction after CopyMI is removed.
1437+
LaneBitmask NewMIImplicitOpsMask;
14331438
SmallVector<MachineOperand, 4> ImplicitOps;
14341439
ImplicitOps.reserve(CopyMI->getNumOperands() -
14351440
CopyMI->getDesc().getNumOperands());
@@ -1443,6 +1448,9 @@ bool RegisterCoalescer::reMaterializeTrivialDef(const CoalescerPair &CP,
14431448
(MO.getSubReg() == 0 && MO.getReg() == DstOperand.getReg())) &&
14441449
"unexpected implicit virtual register def");
14451450
ImplicitOps.push_back(MO);
1451+
if (MO.isDef() && MO.getReg().isVirtual() &&
1452+
MRI->shouldTrackSubRegLiveness(DstReg))
1453+
NewMIImplicitOpsMask |= MRI->getMaxLaneMaskForVReg(MO.getReg());
14461454
}
14471455
}
14481456

@@ -1485,14 +1493,11 @@ bool RegisterCoalescer::reMaterializeTrivialDef(const CoalescerPair &CP,
14851493
} else {
14861494
assert(MO.getReg() == NewMI.getOperand(0).getReg());
14871495

1488-
// We're only expecting another def of the main output, so the range
1489-
// should get updated with the regular output range.
1490-
//
1491-
// FIXME: The range updating below probably needs updating to look at
1492-
// the super register if subranges are tracked.
1493-
assert(!MRI->shouldTrackSubRegLiveness(DstReg) &&
1494-
"subrange update for implicit-def of super register may not be "
1495-
"properly handled");
1496+
// If lanemasks need to be tracked, compile the lanemask of the NewMI
1497+
// implicit def operands to avoid subranges for the super-regs from
1498+
// being removed by code later on in this function.
1499+
if (MRI->shouldTrackSubRegLiveness(MO.getReg()))
1500+
NewMIImplicitOpsMask |= MRI->getMaxLaneMaskForVReg(MO.getReg());
14961501
}
14971502
}
14981503
}
@@ -1516,7 +1521,7 @@ bool RegisterCoalescer::reMaterializeTrivialDef(const CoalescerPair &CP,
15161521
MRI->setRegClass(DstReg, NewRC);
15171522

15181523
// Update machine operands and add flags.
1519-
updateRegDefsUses(DstReg, DstReg, DstIdx);
1524+
updateRegDefsUses(DstReg, DstReg, DstIdx, false);
15201525
NewMI.getOperand(0).setSubReg(NewIdx);
15211526
// updateRegDefUses can add an "undef" flag to the definition, since
15221527
// it will replace DstReg with DstReg.DstIdx. If NewIdx is 0, make
@@ -1592,7 +1597,8 @@ bool RegisterCoalescer::reMaterializeTrivialDef(const CoalescerPair &CP,
15921597
CurrIdx.getRegSlot(NewMI.getOperand(0).isEarlyClobber());
15931598
VNInfo::Allocator &Alloc = LIS->getVNInfoAllocator();
15941599
for (LiveInterval::SubRange &SR : DstInt.subranges()) {
1595-
if ((SR.LaneMask & DstMask).none()) {
1600+
if ((SR.LaneMask & DstMask).none() &&
1601+
(SR.LaneMask & NewMIImplicitOpsMask).none()) {
15961602
LLVM_DEBUG(dbgs()
15971603
<< "Removing undefined SubRange "
15981604
<< PrintLaneMask(SR.LaneMask) << " : " << SR << "\n");
@@ -1857,7 +1863,7 @@ void RegisterCoalescer::addUndefFlag(const LiveInterval &Int, SlotIndex UseIdx,
18571863
}
18581864

18591865
void RegisterCoalescer::updateRegDefsUses(Register SrcReg, Register DstReg,
1860-
unsigned SubIdx) {
1866+
unsigned SubIdx, bool IsSubregToReg) {
18611867
bool DstIsPhys = DstReg.isPhysical();
18621868
LiveInterval *DstInt = DstIsPhys ? nullptr : &LIS->getInterval(DstReg);
18631869

@@ -1877,6 +1883,14 @@ void RegisterCoalescer::updateRegDefsUses(Register SrcReg, Register DstReg,
18771883
}
18781884
}
18791885

1886+
// If DstInt already has a subrange for the unused lanes, then we shouldn't
1887+
// create duplicate subranges when we update the interval for unused lanes.
1888+
LaneBitmask DefinedLanes;
1889+
if (DstInt && MRI->shouldTrackSubRegLiveness(DstReg)) {
1890+
for (LiveInterval::SubRange &SR : DstInt->subranges())
1891+
DefinedLanes |= SR.LaneMask;
1892+
}
1893+
18801894
SmallPtrSet<MachineInstr*, 8> Visited;
18811895
for (MachineRegisterInfo::reg_instr_iterator
18821896
I = MRI->reg_instr_begin(SrcReg), E = MRI->reg_instr_end();
@@ -1900,15 +1914,19 @@ void RegisterCoalescer::updateRegDefsUses(Register SrcReg, Register DstReg,
19001914
if (DstInt && !Reads && SubIdx && !UseMI->isDebugInstr())
19011915
Reads = DstInt->liveAt(LIS->getInstructionIndex(*UseMI));
19021916

1917+
bool FullDef = true;
1918+
19031919
// Replace SrcReg with DstReg in all UseMI operands.
19041920
for (unsigned Op : Ops) {
19051921
MachineOperand &MO = UseMI->getOperand(Op);
19061922

19071923
// Adjust <undef> flags in case of sub-register joins. We don't want to
19081924
// turn a full def into a read-modify-write sub-register def and vice
19091925
// versa.
1910-
if (SubIdx && MO.isDef())
1926+
if (SubIdx && MO.isDef()) {
19111927
MO.setIsUndef(!Reads);
1928+
FullDef = false;
1929+
}
19121930

19131931
// A subreg use of a partially undef (super) register may be a complete
19141932
// undef use now and then has to be marked that way.
@@ -1941,6 +1959,32 @@ void RegisterCoalescer::updateRegDefsUses(Register SrcReg, Register DstReg,
19411959
MO.substVirtReg(DstReg, SubIdx, *TRI);
19421960
}
19431961

1962+
if (IsSubregToReg && !FullDef) {
1963+
// If the coalesed instruction doesn't fully define the register, we need
1964+
// to preserve the original super register liveness for SUBREG_TO_REG.
1965+
//
1966+
// We pretended SUBREG_TO_REG was a regular copy for coalescing purposes,
1967+
// but it introduces liveness for other subregisters. Downstream users may
1968+
// have been relying on those bits, so we need to ensure their liveness is
1969+
// captured with a def of other lanes.
1970+
1971+
if (DstInt && MRI->shouldTrackSubRegLiveness(DstReg)) {
1972+
assert(DstInt->hasSubRanges() &&
1973+
"SUBREG_TO_REG should have resulted in subrange");
1974+
LaneBitmask DstMask = MRI->getMaxLaneMaskForVReg(DstInt->reg());
1975+
LaneBitmask UsedLanes = TRI->getSubRegIndexLaneMask(SubIdx);
1976+
LaneBitmask UnusedLanes = DstMask & ~UsedLanes & ~DefinedLanes;
1977+
if ((UnusedLanes).any()) {
1978+
BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
1979+
DstInt->createSubRangeFrom(Allocator, UnusedLanes, *DstInt);
1980+
DefinedLanes |= UnusedLanes;
1981+
}
1982+
}
1983+
1984+
MachineInstrBuilder MIB(*MF, UseMI);
1985+
MIB.addReg(DstReg, RegState::ImplicitDefine);
1986+
}
1987+
19441988
LLVM_DEBUG({
19451989
dbgs() << "\t\tupdated: ";
19461990
if (!UseMI->isDebugInstr())
@@ -2142,6 +2186,8 @@ bool RegisterCoalescer::joinCopy(
21422186
});
21432187
}
21442188

2189+
const bool IsSubregToReg = CopyMI->isSubregToReg();
2190+
21452191
ShrinkMask = LaneBitmask::getNone();
21462192
ShrinkMainRange = false;
21472193

@@ -2211,9 +2257,12 @@ bool RegisterCoalescer::joinCopy(
22112257

22122258
// Rewrite all SrcReg operands to DstReg.
22132259
// Also update DstReg operands to include DstIdx if it is set.
2214-
if (CP.getDstIdx())
2215-
updateRegDefsUses(CP.getDstReg(), CP.getDstReg(), CP.getDstIdx());
2216-
updateRegDefsUses(CP.getSrcReg(), CP.getDstReg(), CP.getSrcIdx());
2260+
if (CP.getDstIdx()) {
2261+
assert(!IsSubregToReg && "can this happen?");
2262+
updateRegDefsUses(CP.getDstReg(), CP.getDstReg(), CP.getDstIdx(), false);
2263+
}
2264+
updateRegDefsUses(CP.getSrcReg(), CP.getDstReg(), CP.getSrcIdx(),
2265+
IsSubregToReg);
22172266

22182267
// Shrink subregister ranges if necessary.
22192268
if (ShrinkMask.any()) {

0 commit comments

Comments
 (0)