@@ -1772,3 +1772,95 @@ TEST_F(MemorySSATest, TestInvariantGroup) {
1772
1772
EXPECT_EQ (CallAccess, LClobber);
1773
1773
}
1774
1774
}
1775
+
1776
+ static BasicBlock *getBasicBlockByName (Function &F, StringRef Name) {
1777
+ for (BasicBlock &BB : F)
1778
+ if (BB.getName () == Name)
1779
+ return &BB;
1780
+ llvm_unreachable (" Expected to find basic block!" );
1781
+ }
1782
+
1783
+ static Instruction *getInstructionByName (Function &F, StringRef Name) {
1784
+ for (BasicBlock &BB : F)
1785
+ for (Instruction &I : BB)
1786
+ if (I.getName () == Name)
1787
+ return &I;
1788
+ llvm_unreachable (" Expected to find instruction!" );
1789
+ }
1790
+
1791
+ TEST_F (MemorySSATest, TestVisitedBlocks) {
1792
+ SMDiagnostic E;
1793
+ auto M = parseAssemblyString (
1794
+ " define void @test(i64* noalias %P, i64 %N) {\n "
1795
+ " preheader.n:\n "
1796
+ " br label %header.n\n "
1797
+ " header.n:\n "
1798
+ " %n = phi i64 [ 0, %preheader.n ], [ %inc.n, %latch.n ]\n "
1799
+ " %guard.cond.i = icmp slt i64 0, %N\n "
1800
+ " br i1 %guard.cond.i, label %header.i.check, label %other.i\n "
1801
+ " header.i.check:\n "
1802
+ " br label %preheader.i\n "
1803
+ " preheader.i:\n "
1804
+ " br label %header.i\n "
1805
+ " header.i:\n "
1806
+ " %i = phi i64 [ 0, %preheader.i ], [ %inc.i, %header.i ]\n "
1807
+ " %v1 = load i64, i64* %P, align 8\n "
1808
+ " %v2 = load i64, i64* %P, align 8\n "
1809
+ " %inc.i = add nsw i64 %i, 1\n "
1810
+ " %cmp.i = icmp slt i64 %inc.i, %N\n "
1811
+ " br i1 %cmp.i, label %header.i, label %exit.i\n "
1812
+ " exit.i:\n "
1813
+ " br label %commonexit\n "
1814
+ " other.i:\n "
1815
+ " br label %commonexit\n "
1816
+ " commonexit:\n "
1817
+ " br label %latch.n\n "
1818
+ " latch.n:\n "
1819
+ " %inc.n = add nsw i64 %n, 1\n "
1820
+ " %cmp.n = icmp slt i64 %inc.n, %N\n "
1821
+ " br i1 %cmp.n, label %header.n, label %exit.n\n "
1822
+ " exit.n:\n "
1823
+ " ret void\n "
1824
+ " }\n " ,
1825
+ E, C);
1826
+ ASSERT_TRUE (M);
1827
+ F = M->getFunction (" test" );
1828
+ ASSERT_TRUE (F);
1829
+ setupAnalyses ();
1830
+ MemorySSA &MSSA = *Analyses->MSSA ;
1831
+ MemorySSAUpdater Updater (&MSSA);
1832
+
1833
+ {
1834
+ // Move %v1 before the terminator of %header.i.check
1835
+ BasicBlock *BB = getBasicBlockByName (*F, " header.i.check" );
1836
+ Instruction *LI = getInstructionByName (*F, " v1" );
1837
+ LI->moveBefore (BB->getTerminator ());
1838
+ if (MemoryUseOrDef *MUD = MSSA.getMemoryAccess (LI))
1839
+ Updater.moveToPlace (MUD, BB, MemorySSA::BeforeTerminator);
1840
+
1841
+ // Change the termiantor of %header.i.check to `br label true, label
1842
+ // %preheader.i, label %other.i`
1843
+ BB->getTerminator ()->eraseFromParent ();
1844
+ ConstantInt *BoolTrue = ConstantInt::getTrue (F->getContext ());
1845
+ BranchInst::Create (getBasicBlockByName (*F, " preheader.i" ),
1846
+ getBasicBlockByName (*F, " other.i" ), BoolTrue, BB);
1847
+ SmallVector<DominatorTree::UpdateType, 4 > DTUpdates;
1848
+ DTUpdates.push_back (DominatorTree::UpdateType (
1849
+ DominatorTree::Insert, BB, getBasicBlockByName (*F, " other.i" )));
1850
+ Updater.applyUpdates (DTUpdates, Analyses->DT , true );
1851
+ }
1852
+
1853
+ // After the first moveToPlace(), %other.i is in VisitedBlocks, even after
1854
+ // there is a new edge to %other.i, which makes the second moveToPlace()
1855
+ // traverse incorrectly.
1856
+ {
1857
+ // Move %v2 before the terminator of %preheader.i
1858
+ BasicBlock *BB = getBasicBlockByName (*F, " preheader.i" );
1859
+ Instruction *LI = getInstructionByName (*F, " v2" );
1860
+ LI->moveBefore (BB->getTerminator ());
1861
+ // Check that there is no assertion of "Incomplete phi during partial
1862
+ // rename"
1863
+ if (MemoryUseOrDef *MUD = MSSA.getMemoryAccess (LI))
1864
+ Updater.moveToPlace (MUD, BB, MemorySSA::BeforeTerminator);
1865
+ }
1866
+ }
0 commit comments