diff --git a/llvm/lib/CodeGen/LiveVariables.cpp b/llvm/lib/CodeGen/LiveVariables.cpp --- a/llvm/lib/CodeGen/LiveVariables.cpp +++ b/llvm/lib/CodeGen/LiveVariables.cpp @@ -661,22 +661,18 @@ MachineInstr &DefMI = *MRI->getUniqueVRegDef(Reg); MachineBasicBlock &DefBB = *DefMI.getParent(); - // Handle the case where all uses have been removed. - if (MRI->use_nodbg_empty(Reg)) { - VI.Kills.push_back(&DefMI); - DefMI.addRegisterDead(Reg, nullptr); - return; - } - DefMI.clearRegisterDeads(Reg); - // Initialize a worklist of BBs that Reg is live-to-end of. (Here // "live-to-end" means Reg is live at the end of a block even if it is only // live because of phi uses in a successor. This is different from isLiveOut() // which does not consider phi uses.) SmallVector LiveToEndBlocks; SparseBitVector<> UseBlocks; + unsigned NumRealUses = 0; for (auto &UseMO : MRI->use_nodbg_operands(Reg)) { UseMO.setIsKill(false); + if (!UseMO.readsReg()) + continue; + ++NumRealUses; MachineInstr &UseMI = *UseMO.getParent(); MachineBasicBlock &UseBB = *UseMI.getParent(); UseBlocks.set(UseBB.getNumber()); @@ -693,6 +689,14 @@ } } + // Handle the case where all uses have been removed. + if (NumRealUses == 0) { + VI.Kills.push_back(&DefMI); + DefMI.addRegisterDead(Reg, nullptr); + return; + } + DefMI.clearRegisterDeads(Reg); + // Iterate over the worklist adding blocks to AliveBlocks. bool LiveToEndOfDefBB = false; while (!LiveToEndBlocks.empty()) { @@ -721,7 +725,7 @@ continue; if (MI.isPHI()) break; - if (MI.readsRegister(Reg)) { + if (MI.readsWritesVirtualRegister(Reg).first) { assert(!MI.killsRegister(Reg)); MI.addRegisterKilled(Reg, nullptr); VI.Kills.push_back(&MI); diff --git a/llvm/unittests/MI/LiveIntervalTest.cpp b/llvm/unittests/MI/LiveIntervalTest.cpp --- a/llvm/unittests/MI/LiveIntervalTest.cpp +++ b/llvm/unittests/MI/LiveIntervalTest.cpp @@ -1,5 +1,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/LiveIntervals.h" +#include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -75,22 +76,28 @@ return M; } -typedef std::function LiveIntervalTest; - struct TestPass : public MachineFunctionPass { static char ID; - TestPass() : MachineFunctionPass(ID) { + TestPass() : MachineFunctionPass(ID) {} +}; + +template +struct TestPassT : public TestPass { + + typedef std::function TestFx; + + TestPassT() { // We should never call this but always use PM.add(new TestPass(...)) abort(); } - TestPass(LiveIntervalTest T, bool ShouldPass) - : MachineFunctionPass(ID), T(T), ShouldPass(ShouldPass) { + TestPassT(TestFx T, bool ShouldPass) + : T(T), ShouldPass(ShouldPass) { initializeTestPassPass(*PassRegistry::getPassRegistry()); } bool runOnMachineFunction(MachineFunction &MF) override { - LiveIntervals &LIS = getAnalysis(); - T(MF, LIS); + AnalysisType &A = getAnalysis(); + T(MF, A); EXPECT_EQ(MF.verify(this, /* Banner */ nullptr, /* AbortOnError */ false), ShouldPass); return true; @@ -98,12 +105,12 @@ void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - AU.addRequired(); - AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); MachineFunctionPass::getAnalysisUsage(AU); } private: - LiveIntervalTest T; + TestFx T; bool ShouldPass; }; @@ -188,8 +195,10 @@ return false; } -static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T, - bool ShouldPass = true) { +template +static void doTest(StringRef MIRFunc, + typename TestPassT::TestFx T, + bool ShouldPass = true) { LLVMContext Context; std::unique_ptr TM = createTargetMachine(); // This test is designed for the X86 backend; stop if it is not available. @@ -197,7 +206,18 @@ return; legacy::PassManager PM; + std::unique_ptr MIR; + std::unique_ptr M = parseMIR(Context, PM, MIR, *TM, MIRFunc, "func"); + ASSERT_TRUE(M); + + PM.add(new TestPassT(T, ShouldPass)); + + PM.run(*M); +} +static void liveIntervalTest(StringRef MIRFunc, + TestPassT::TestFx T, + bool ShouldPass = true) { SmallString<160> S; StringRef MIRString = (Twine(R"MIR( --- @@ -208,14 +228,25 @@ body: | bb.0: )MIR") + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S); - std::unique_ptr MIR; - std::unique_ptr M = parseMIR(Context, PM, MIR, *TM, MIRString, - "func"); - ASSERT_TRUE(M); - PM.add(new TestPass(T, ShouldPass)); + doTest(MIRString, T, ShouldPass); +} - PM.run(*M); +static void liveVariablesTest(StringRef MIRFunc, + TestPassT::TestFx T, + bool ShouldPass = true) { + SmallString<160> S; + StringRef MIRString = (Twine(R"MIR( +--- +... +name: func +tracksRegLiveness: true +registers: + - { id: 0, class: sreg_64 } +body: | + bb.0: +)MIR") + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S); + doTest(MIRString, T, ShouldPass); } } // End of anonymous namespace. @@ -778,6 +809,46 @@ false); } +TEST(LiveVariablesTest, recomputeForSingleDefVirtReg_handle_undef1) { + liveVariablesTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0, implicit %0 + S_NOP 0, implicit undef %0 +)MIR", [](MachineFunction &MF, LiveVariables &LV) { + auto &FirstNop = getMI(MF, 1, 0); + auto &SecondNop = getMI(MF, 2, 0); + EXPECT_TRUE(FirstNop.getOperand(1).isKill()); + EXPECT_FALSE(SecondNop.getOperand(1).isKill()); + + Register R = Register::index2VirtReg(0); + LV.recomputeForSingleDefVirtReg(R); + + EXPECT_TRUE(FirstNop.getOperand(1).isKill()); + EXPECT_FALSE(SecondNop.getOperand(1).isKill()); + }); +} + +TEST(LiveVariablesTest, recomputeForSingleDefVirtReg_handle_undef2) { + liveVariablesTest(R"MIR( + %0 = IMPLICIT_DEF + S_NOP 0, implicit %0 + S_NOP 0, implicit undef %0, implicit %0 +)MIR", [](MachineFunction &MF, LiveVariables &LV) { + auto &FirstNop = getMI(MF, 1, 0); + auto &SecondNop = getMI(MF, 2, 0); + EXPECT_FALSE(FirstNop.getOperand(1).isKill()); + EXPECT_FALSE(SecondNop.getOperand(1).isKill()); + EXPECT_TRUE(SecondNop.getOperand(2).isKill()); + + Register R = Register::index2VirtReg(0); + LV.recomputeForSingleDefVirtReg(R); + + EXPECT_FALSE(FirstNop.getOperand(1).isKill()); + EXPECT_FALSE(SecondNop.getOperand(1).isKill()); + EXPECT_TRUE(SecondNop.getOperand(2).isKill()); + }); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); initLLVM();