Index: llvm/trunk/lib/CodeGen/LiveIntervals.cpp =================================================================== --- llvm/trunk/lib/CodeGen/LiveIntervals.cpp +++ llvm/trunk/lib/CodeGen/LiveIntervals.cpp @@ -1291,6 +1291,36 @@ if (OldIdxIn != E && SlotIndex::isEarlierInstr(NewIdx, OldIdxIn->end)) OldIdxIn->end = NewIdx.getRegSlot(); } + } else if (OldIdxIn != E + && SlotIndex::isEarlierInstr(NewIdxOut->start, NewIdx) + && SlotIndex::isEarlierInstr(NewIdx, NewIdxOut->end)) { + // OldIdxVNI is a dead def that has been moved into the middle of + // another value in LR. That can happen when LR is a whole register, + // but the dead def is a write to a subreg that is dead at NewIdx. + // The dead def may have been moved across other values + // in LR, so move OldIdxOut up to NewIdxOut. Slide [NewIdxOut;OldIdxOut) + // down one position. + // |- X0/NewIdxOut -| ... |- Xn-1 -| |- Xn/OldIdxOut -| |- next - | + // => |- X0/NewIdxOut -| |- X0 -| ... |- Xn-1 -| |- next -| + std::copy_backward(NewIdxOut, OldIdxOut, std::next(OldIdxOut)); + // Modify the segment at NewIdxOut and the following segment to meet at + // the point of the dead def, with the following segment getting + // OldIdxVNI as its value number. + *NewIdxOut = LiveRange::Segment( + NewIdxOut->start, NewIdxDef.getRegSlot(), NewIdxOut->valno); + *(NewIdxOut + 1) = LiveRange::Segment( + NewIdxDef.getRegSlot(), (NewIdxOut + 1)->end, OldIdxVNI); + OldIdxVNI->def = NewIdxDef; + // Modify subsequent segments to be defined by the moved def OldIdxVNI. + for (auto Idx = NewIdxOut + 2; Idx <= OldIdxOut; ++Idx) + Idx->valno = OldIdxVNI; + // Aggressively remove all dead flags from the former dead definition. + // Kill/dead flags shouldn't be used while live intervals exist; they + // will be reinserted by VirtRegRewriter. + if (MachineInstr *KillMI = LIS.getInstructionFromIndex(NewIdx)) + for (MIBundleOperands MO(*KillMI); MO.isValid(); ++MO) + if (MO->isReg() && !MO->isUse()) + MO->setIsDead(false); } else { // OldIdxVNI is a dead def. It may have been moved across other values // in LR, so move OldIdxOut up to NewIdxOut. Slide [NewIdxOut;OldIdxOut) Index: llvm/trunk/unittests/MI/LiveIntervalTest.cpp =================================================================== --- llvm/trunk/unittests/MI/LiveIntervalTest.cpp +++ llvm/trunk/unittests/MI/LiveIntervalTest.cpp @@ -395,6 +395,31 @@ }); } +TEST(LiveIntervalTest, DeadSubRegMoveUp) { + // handleMoveUp had a bug where moving a dead subreg def into the middle of + // an earlier segment resulted in an invalid live range. + liveIntervalTest(R"MIR( + undef %125.sub0:vreg_128 = V_MOV_B32_e32 0, implicit $exec + %125.sub1:vreg_128 = COPY %125.sub0 + %125.sub2:vreg_128 = COPY %125.sub0 + undef %51.sub0:vreg_128 = V_MOV_B32_e32 898625526, implicit $exec + %51.sub1:vreg_128 = COPY %51.sub0 + %51.sub2:vreg_128 = COPY %51.sub0 + %52:vgpr_32 = V_MOV_B32_e32 986714345, implicit $exec + %54:vgpr_32 = V_MOV_B32_e32 1742342378, implicit $exec + %57:vgpr_32 = V_MOV_B32_e32 3168768712, implicit $exec + %59:vgpr_32 = V_MOV_B32_e32 1039972644, implicit $exec + %60:vgpr_32 = V_MAD_F32 0, %52, 0, undef %61:vgpr_32, 0, %59, 0, 0, implicit $exec + %63:vgpr_32 = V_ADD_F32_e32 %51.sub3, undef %64:vgpr_32, implicit $exec + dead %66:vgpr_32 = V_MAD_F32 0, %60, 0, undef %67:vgpr_32, 0, %125.sub2, 0, 0, implicit $exec + undef %124.sub1:vreg_128 = V_MAD_F32 0, %57, 0, undef %70:vgpr_32, 0, %125.sub1, 0, 0, implicit $exec + %124.sub0:vreg_128 = V_MAD_F32 0, %54, 0, undef %73:vgpr_32, 0, %125.sub0, 0, 0, implicit $exec + dead undef %125.sub3:vreg_128 = V_MAC_F32_e32 %63, undef %76:vgpr_32, %125.sub3, implicit $exec +)MIR", [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 15, 12); + }); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); initLLVM();