diff options
author | Valery Pykhtin <valery.pykhtin@gmail.com> | 2023-08-17 11:47:46 +0200 |
---|---|---|
committer | Valery Pykhtin <valery.pykhtin@gmail.com> | 2023-09-12 10:59:43 +0200 |
commit | af2dcc3052a8e2c88d7d919ee19f811e806c5e9b (patch) | |
tree | c702d430587cda8a86a40f0a58b3f861b43900be /llvm/unittests/MI | |
parent | a1e38e0b8e3e9d02304cf1a578f02a80fdb02bce (diff) | |
download | llvm-af2dcc3052a8e2c88d7d919ee19f811e806c5e9b.zip llvm-af2dcc3052a8e2c88d7d919ee19f811e806c5e9b.tar.gz llvm-af2dcc3052a8e2c88d7d919ee19f811e806c5e9b.tar.bz2 |
[AMDGPU] Handle inUndef flag in LiveVariables::recomputeForSingleDefVirtReg
A register's use with isUndef flags shouldn't be considered as a point where the register is live. LiveVariables::runOnInstr ignores such uses.
This was found when I tried to replace calls to
SIOptimizeVGPRLiveRange::updateLiveRangeInThenRegion
SIOptimizeVGPRLiveRange::updateLiveRangeInElseRegion
with LiveVariables::recomputeForSingleDefVirtReg.
In the testcase below %2 use is undef in the last REG_SEQUENCE.
CodeGen/AMDGPU/si-opt-vgpr-liverange-bug-deadlanes.mir failed:
Function Live Ins: $vgpr0 in %0
bb.0:
successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
liveins: $vgpr0
%0:vgpr_32 = COPY killed $vgpr0
%1:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
%2:vgpr_32 = BUFFER_LOAD_DWORD_OFFEN killed %0:vgpr_32, undef %5:sgpr_128, 0, 0, 0, 0, implicit $exec :: (dereferenceable invariant load (s32))
%3:sreg_64 = V_CMP_NE_U32_e64 0, %2:vgpr_32, implicit $exec
%7:sreg_64 = SI_IF killed %3:sreg_64, %bb.2, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
S_BRANCH %bb.1
bb.1:
; predecessors: %bb.0
successors: %bb.2(0x80000000); %bb.2(100.00%)
%8:vreg_128 = REG_SEQUENCE killed %1:vgpr_32, %subreg.sub0, %1:vgpr_32, %subreg.sub1, %1:vgpr_32, %subreg.sub2, undef %4.sub3:vreg_128, %subreg.sub3
bb.2:
; predecessors: %bb.0, %bb.1
successors: %bb.3(0x40000000), %bb.4(0x40000000); %bb.3(50.00%), %bb.4(50.00%)
%9:vreg_128 = PHI undef %10:vreg_128, %bb.0, %8:vreg_128, %bb.1
%14:vgpr_32 = PHI %2:vgpr_32, %bb.0, undef %15:vgpr_32, %bb.1
%11:sreg_64 = SI_ELSE killed %7:sreg_64, %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
S_BRANCH %bb.3
bb.3:
; predecessors: %bb.2
successors: %bb.4(0x80000000); %bb.4(100.00%)
%12:vreg_128 = REG_SEQUENCE killed %14:vgpr_32, %subreg.sub0, %14:vgpr_32, %subreg.sub1, %14:vgpr_32, %subreg.sub2, undef %6:vgpr_32, %subreg.sub3
bb.4:
; predecessors: %bb.2, %bb.3
%13:vreg_128 = PHI %9:vreg_128, %bb.2, %12:vreg_128, %bb.3
SI_END_CF killed %11:sreg_64, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
dead %4:vreg_128 = REG_SEQUENCE killed %13.sub2:vreg_128, %subreg.sub0, %13.sub2:vreg_128, %subreg.sub1, %13.sub2:vreg_128, %subreg.sub2, **undef %2:vgpr_32**, %subreg.sub3
S_ENDPGM 0
*** Bad machine code: LiveVariables: Block should not be in AliveBlocks ***
- function: _amdgpu_ps_main
- basic block: %bb.1 (0x55e17ebd7100)
Virtual register %2 is not needed live through the block.
*** Bad machine code: LiveVariables: Block should not be in AliveBlocks ***
- function: _amdgpu_ps_main
- basic block: %bb.2 (0x55e17ebd7200)
Virtual register %2 is not needed live through the block.
*** Bad machine code: LiveVariables: Block should not be in AliveBlocks ***
- function: _amdgpu_ps_main
- basic block: %bb.3 (0x55e17ebd7300)
Virtual register %2 is not needed live through the block.
Differential Revision: https://reviews.llvm.org/D158167
Diffstat (limited to 'llvm/unittests/MI')
-rw-r--r-- | llvm/unittests/MI/LiveIntervalTest.cpp | 107 |
1 files changed, 89 insertions, 18 deletions
diff --git a/llvm/unittests/MI/LiveIntervalTest.cpp b/llvm/unittests/MI/LiveIntervalTest.cpp index 0957891..e3b07c9 100644 --- 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 @@ std::unique_ptr<Module> parseMIR(LLVMContext &Context, return M; } -typedef std::function<void(MachineFunction&,LiveIntervals&)> LiveIntervalTest; - struct TestPass : public MachineFunctionPass { static char ID; - TestPass() : MachineFunctionPass(ID) { + TestPass() : MachineFunctionPass(ID) {} +}; + +template <typename AnalysisType> +struct TestPassT : public TestPass { + + typedef std::function<void(MachineFunction&,AnalysisType&)> 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<LiveIntervals>(); - T(MF, LIS); + AnalysisType &A = getAnalysis<AnalysisType>(); + T(MF, A); EXPECT_EQ(MF.verify(this, /* Banner */ nullptr, /* AbortOnError */ false), ShouldPass); return true; @@ -98,12 +105,12 @@ struct TestPass : public MachineFunctionPass { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); - AU.addRequired<LiveIntervals>(); - AU.addPreserved<LiveIntervals>(); + AU.addRequired<AnalysisType>(); + AU.addPreserved<AnalysisType>(); MachineFunctionPass::getAnalysisUsage(AU); } private: - LiveIntervalTest T; + TestFx T; bool ShouldPass; }; @@ -188,8 +195,10 @@ static bool checkRegUnitInterference(LiveIntervals &LIS, return false; } -static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T, - bool ShouldPass = true) { +template <typename AnalysisType> +static void doTest(StringRef MIRFunc, + typename TestPassT<AnalysisType>::TestFx T, + bool ShouldPass = true) { LLVMContext Context; std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine(); // This test is designed for the X86 backend; stop if it is not available. @@ -197,7 +206,18 @@ static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T, return; legacy::PassManager PM; + std::unique_ptr<MIRParser> MIR; + std::unique_ptr<Module> M = parseMIR(Context, PM, MIR, *TM, MIRFunc, "func"); + ASSERT_TRUE(M); + + PM.add(new TestPassT<AnalysisType>(T, ShouldPass)); + + PM.run(*M); +} +static void liveIntervalTest(StringRef MIRFunc, + TestPassT<LiveIntervals>::TestFx T, + bool ShouldPass = true) { SmallString<160> S; StringRef MIRString = (Twine(R"MIR( --- @@ -208,14 +228,25 @@ registers: body: | bb.0: )MIR") + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S); - std::unique_ptr<MIRParser> MIR; - std::unique_ptr<Module> M = parseMIR(Context, PM, MIR, *TM, MIRString, - "func"); - ASSERT_TRUE(M); - PM.add(new TestPass(T, ShouldPass)); + doTest<LiveIntervals>(MIRString, T, ShouldPass); +} - PM.run(*M); +static void liveVariablesTest(StringRef MIRFunc, + TestPassT<LiveVariables>::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<LiveVariables>(MIRString, T, ShouldPass); } } // End of anonymous namespace. @@ -778,6 +809,46 @@ TEST(LiveIntervalTest, LiveThroughSegments) { 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(); |