@@ -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
18591865void 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\t updated: " ;
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