aboutsummaryrefslogtreecommitdiff
path: root/unittests/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/Transforms')
-rw-r--r--unittests/Transforms/Scalar/LoopPassManagerTest.cpp399
-rw-r--r--unittests/Transforms/Utils/CMakeLists.txt1
-rw-r--r--unittests/Transforms/Utils/Cloning.cpp65
-rw-r--r--unittests/Transforms/Utils/IntegerDivision.cpp16
-rw-r--r--unittests/Transforms/Utils/MemorySSA.cpp534
5 files changed, 339 insertions, 676 deletions
diff --git a/unittests/Transforms/Scalar/LoopPassManagerTest.cpp b/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
index a099e35c7f19..227060f0a46e 100644
--- a/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
+++ b/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
@@ -46,7 +46,10 @@ public:
DerivedT *Handle;
- Analysis(DerivedT &Handle) : Handle(&Handle) {}
+ Analysis(DerivedT &Handle) : Handle(&Handle) {
+ static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,
+ "Must pass the derived type to this template!");
+ }
public:
class Result {
@@ -152,7 +155,10 @@ public:
DerivedT *Handle;
- Pass(DerivedT &Handle) : Handle(&Handle) {}
+ Pass(DerivedT &Handle) : Handle(&Handle) {
+ static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
+ "Must pass the derived type to this template!");
+ }
public:
PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
@@ -244,27 +250,38 @@ protected:
public:
LoopPassManagerTest()
- : M(parseIR(Context, "define void @f() {\n"
- "entry:\n"
- " br label %loop.0\n"
- "loop.0:\n"
- " br i1 undef, label %loop.0.0, label %end\n"
- "loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.1\n"
- "loop.0.1:\n"
- " br i1 undef, label %loop.0.1, label %loop.0\n"
- "end:\n"
- " ret void\n"
- "}\n"
- "\n"
- "define void @g() {\n"
- "entry:\n"
- " br label %loop.g.0\n"
- "loop.g.0:\n"
- " br i1 undef, label %loop.g.0, label %end\n"
- "end:\n"
- " ret void\n"
- "}\n")),
+ : M(parseIR(Context,
+ "define void @f(i1* %ptr) {\n"
+ "entry:\n"
+ " br label %loop.0\n"
+ "loop.0:\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %end\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
+ "loop.0.0:\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.1.ph\n"
+ "loop.0.1.ph:\n"
+ " br label %loop.0.1\n"
+ "loop.0.1:\n"
+ " %cond.0.1 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.1, label %loop.0.1, label %loop.0.latch\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
+ "end:\n"
+ " ret void\n"
+ "}\n"
+ "\n"
+ "define void @g(i1* %ptr) {\n"
+ "entry:\n"
+ " br label %loop.g.0\n"
+ "loop.g.0:\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.g.0, label %end\n"
+ "end:\n"
+ " ret void\n"
+ "}\n")),
LAM(true), FAM(true), MAM(true) {
// Register our mock analysis.
LAM.registerPass([&] { return MLAHandle.getAnalysis(); });
@@ -551,7 +568,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
// Not preserving `AAManager`.
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -568,24 +584,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- // Not preserving `AssumptionAnalysis`.
- PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<LoopAnalysis>();
- PA.preserve<LoopAnalysisManagerFunctionProxy>();
- PA.preserve<ScalarEvolutionAnalysis>();
- return PA;
- }));
- EXPECT_CALL(MLAHandle, run(HasName("loop.0.0"), _, _));
- EXPECT_CALL(MLAHandle, run(HasName("loop.0.1"), _, _));
- EXPECT_CALL(MLAHandle, run(HasName("loop.0"), _, _));
- FPM.addPass(MFPHandle.getPass());
- FPM.addPass(createFunctionToLoopPassAdaptor(
- RequireAnalysisLoopPass<MockLoopAnalysisHandle::Analysis>()));
-
- EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
- auto PA = PreservedAnalyses::none();
- PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
// Not preserving `DominatorTreeAnalysis`.
PA.preserve<LoopAnalysis>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -602,7 +600,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
// Not preserving the `LoopAnalysis`.
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -619,7 +616,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
// Not preserving the `LoopAnalysisManagerFunctionProxy`.
@@ -636,7 +632,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -654,7 +649,7 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
// 'g' once with a requires pass and then run our mock pass over g a bunch
// but just get cached results each time.
EXPECT_CALL(MLAHandle, run(HasName("loop.g.0"), _, _));
- EXPECT_CALL(MFPHandle, run(HasName("g"), _)).Times(7);
+ EXPECT_CALL(MFPHandle, run(HasName("g"), _)).Times(6);
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
MPM.run(*M, MAM);
@@ -842,17 +837,29 @@ TEST_F(LoopPassManagerTest, IndirectOuterPassInvalidation) {
TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// Super boring module with three loops in a single loop nest.
- M = parseIR(Context, "define void @f() {\n"
+ M = parseIR(Context, "define void @f(i1* %ptr) {\n"
"entry:\n"
" br label %loop.0\n"
"loop.0:\n"
- " br i1 undef, label %loop.0.0, label %end\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %end\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
"loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.1\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.1.ph\n"
+ "loop.0.1.ph:\n"
+ " br label %loop.0.1\n"
"loop.0.1:\n"
- " br i1 undef, label %loop.0.1, label %loop.0.2\n"
+ " %cond.0.1 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.1, label %loop.0.1, label %loop.0.2.ph\n"
+ "loop.0.2.ph:\n"
+ " br label %loop.0.2\n"
"loop.0.2:\n"
- " br i1 undef, label %loop.0.2, label %loop.0\n"
+ " %cond.0.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2, label %loop.0.2, label %loop.0.latch\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
"end:\n"
" ret void\n"
"}\n");
@@ -861,20 +868,34 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// easily.
Function &F = *M->begin();
ASSERT_THAT(F, HasName("f"));
+ Argument &Ptr = *F.arg_begin();
auto BBI = F.begin();
BasicBlock &EntryBB = *BBI++;
ASSERT_THAT(EntryBB, HasName("entry"));
BasicBlock &Loop0BB = *BBI++;
ASSERT_THAT(Loop0BB, HasName("loop.0"));
+ BasicBlock &Loop00PHBB = *BBI++;
+ ASSERT_THAT(Loop00PHBB, HasName("loop.0.0.ph"));
BasicBlock &Loop00BB = *BBI++;
ASSERT_THAT(Loop00BB, HasName("loop.0.0"));
+ BasicBlock &Loop01PHBB = *BBI++;
+ ASSERT_THAT(Loop01PHBB, HasName("loop.0.1.ph"));
BasicBlock &Loop01BB = *BBI++;
ASSERT_THAT(Loop01BB, HasName("loop.0.1"));
+ BasicBlock &Loop02PHBB = *BBI++;
+ ASSERT_THAT(Loop02PHBB, HasName("loop.0.2.ph"));
BasicBlock &Loop02BB = *BBI++;
ASSERT_THAT(Loop02BB, HasName("loop.0.2"));
+ BasicBlock &Loop0LatchBB = *BBI++;
+ ASSERT_THAT(Loop0LatchBB, HasName("loop.0.latch"));
BasicBlock &EndBB = *BBI++;
ASSERT_THAT(EndBB, HasName("end"));
ASSERT_THAT(BBI, F.end());
+ auto CreateCondBr = [&](BasicBlock *TrueBB, BasicBlock *FalseBB,
+ const char *Name, BasicBlock *BB) {
+ auto *Cond = new LoadInst(&Ptr, Name, /*isVolatile*/ true, BB);
+ BranchInst::Create(TrueBB, FalseBB, Cond, BB);
+ };
// Build the pass managers and register our pipeline. We build a single loop
// pass pipeline consisting of three mock pass runs over each loop. After
@@ -909,20 +930,33 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// When running over the middle loop, the second run inserts two new child
// loops, inserting them and itself into the worklist.
- BasicBlock *NewLoop010BB;
+ BasicBlock *NewLoop010BB, *NewLoop01LatchBB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.1"), _, _, _))
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
L.addChildLoop(NewLoop);
- NewLoop010BB = BasicBlock::Create(Context, "loop.0.1.0", &F, &Loop02BB);
- BranchInst::Create(&Loop01BB, NewLoop010BB,
- UndefValue::get(Type::getInt1Ty(Context)),
- NewLoop010BB);
- Loop01BB.getTerminator()->replaceUsesOfWith(&Loop01BB, NewLoop010BB);
- AR.DT.addNewBlock(NewLoop010BB, &Loop01BB);
+ auto *NewLoop010PHBB =
+ BasicBlock::Create(Context, "loop.0.1.0.ph", &F, &Loop02PHBB);
+ NewLoop010BB =
+ BasicBlock::Create(Context, "loop.0.1.0", &F, &Loop02PHBB);
+ NewLoop01LatchBB =
+ BasicBlock::Create(Context, "loop.0.1.latch", &F, &Loop02PHBB);
+ Loop01BB.getTerminator()->replaceUsesOfWith(&Loop01BB, NewLoop010PHBB);
+ BranchInst::Create(NewLoop010BB, NewLoop010PHBB);
+ CreateCondBr(NewLoop01LatchBB, NewLoop010BB, "cond.0.1.0",
+ NewLoop010BB);
+ BranchInst::Create(&Loop01BB, NewLoop01LatchBB);
+ AR.DT.addNewBlock(NewLoop010PHBB, &Loop01BB);
+ AR.DT.addNewBlock(NewLoop010BB, NewLoop010PHBB);
+ AR.DT.addNewBlock(NewLoop01LatchBB, NewLoop010BB);
+ AR.DT.verifyDomTree();
+ L.addBasicBlockToLoop(NewLoop010PHBB, AR.LI);
NewLoop->addBasicBlockToLoop(NewLoop010BB, AR.LI);
+ L.addBasicBlockToLoop(NewLoop01LatchBB, AR.LI);
+ NewLoop->verifyLoop();
+ L.verifyLoop();
Updater.addChildLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -943,21 +977,27 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// In the second run over the middle loop after we've visited the new child,
// we add another child to check that we can repeatedly add children, and add
// children to a loop that already has children.
- BasicBlock *NewLoop011BB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.1"), _, _, _))
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
L.addChildLoop(NewLoop);
- NewLoop011BB = BasicBlock::Create(Context, "loop.0.1.1", &F, &Loop02BB);
- BranchInst::Create(&Loop01BB, NewLoop011BB,
- UndefValue::get(Type::getInt1Ty(Context)),
- NewLoop011BB);
- NewLoop010BB->getTerminator()->replaceUsesOfWith(&Loop01BB,
- NewLoop011BB);
- AR.DT.addNewBlock(NewLoop011BB, NewLoop010BB);
+ auto *NewLoop011PHBB = BasicBlock::Create(Context, "loop.0.1.1.ph", &F, NewLoop01LatchBB);
+ auto *NewLoop011BB = BasicBlock::Create(Context, "loop.0.1.1", &F, NewLoop01LatchBB);
+ NewLoop010BB->getTerminator()->replaceUsesOfWith(NewLoop01LatchBB,
+ NewLoop011PHBB);
+ BranchInst::Create(NewLoop011BB, NewLoop011PHBB);
+ CreateCondBr(NewLoop01LatchBB, NewLoop011BB, "cond.0.1.1",
+ NewLoop011BB);
+ AR.DT.addNewBlock(NewLoop011PHBB, NewLoop010BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop011BB, NewLoop011PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[NewLoop01LatchBB], NewDTNode);
+ AR.DT.verifyDomTree();
+ L.addBasicBlockToLoop(NewLoop011PHBB, AR.LI);
NewLoop->addBasicBlockToLoop(NewLoop011BB, AR.LI);
+ NewLoop->verifyLoop();
+ L.verifyLoop();
Updater.addChildLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -999,17 +1039,29 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
// Super boring module with two loop nests and loop nest with two child
// loops.
- M = parseIR(Context, "define void @f() {\n"
+ M = parseIR(Context, "define void @f(i1* %ptr) {\n"
"entry:\n"
" br label %loop.0\n"
"loop.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.2\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %loop.2.ph\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
"loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.2\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.2.ph\n"
+ "loop.0.2.ph:\n"
+ " br label %loop.0.2\n"
"loop.0.2:\n"
- " br i1 undef, label %loop.0.2, label %loop.0\n"
+ " %cond.0.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2, label %loop.0.2, label %loop.0.latch\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
+ "loop.2.ph:\n"
+ " br label %loop.2\n"
"loop.2:\n"
- " br i1 undef, label %loop.2, label %end\n"
+ " %cond.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.2, label %loop.2, label %end\n"
"end:\n"
" ret void\n"
"}\n");
@@ -1018,21 +1070,34 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
// easily.
Function &F = *M->begin();
ASSERT_THAT(F, HasName("f"));
+ Argument &Ptr = *F.arg_begin();
auto BBI = F.begin();
BasicBlock &EntryBB = *BBI++;
ASSERT_THAT(EntryBB, HasName("entry"));
BasicBlock &Loop0BB = *BBI++;
ASSERT_THAT(Loop0BB, HasName("loop.0"));
+ BasicBlock &Loop00PHBB = *BBI++;
+ ASSERT_THAT(Loop00PHBB, HasName("loop.0.0.ph"));
BasicBlock &Loop00BB = *BBI++;
ASSERT_THAT(Loop00BB, HasName("loop.0.0"));
+ BasicBlock &Loop02PHBB = *BBI++;
+ ASSERT_THAT(Loop02PHBB, HasName("loop.0.2.ph"));
BasicBlock &Loop02BB = *BBI++;
ASSERT_THAT(Loop02BB, HasName("loop.0.2"));
+ BasicBlock &Loop0LatchBB = *BBI++;
+ ASSERT_THAT(Loop0LatchBB, HasName("loop.0.latch"));
+ BasicBlock &Loop2PHBB = *BBI++;
+ ASSERT_THAT(Loop2PHBB, HasName("loop.2.ph"));
BasicBlock &Loop2BB = *BBI++;
ASSERT_THAT(Loop2BB, HasName("loop.2"));
BasicBlock &EndBB = *BBI++;
ASSERT_THAT(EndBB, HasName("end"));
ASSERT_THAT(BBI, F.end());
- Constant *Undefi1 = UndefValue::get(Type::getInt1Ty(Context));
+ auto CreateCondBr = [&](BasicBlock *TrueBB, BasicBlock *FalseBB,
+ const char *Name, BasicBlock *BB) {
+ auto *Cond = new LoadInst(&Ptr, Name, /*isVolatile*/ true, BB);
+ BranchInst::Create(TrueBB, FalseBB, Cond, BB);
+ };
// Build the pass managers and register our pipeline. We build a single loop
// pass pipeline consisting of three mock pass runs over each loop. After
@@ -1059,19 +1124,24 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
EXPECT_CALL(MLAHandle, run(HasName("loop.0.0"), _, _));
// On the second run, we insert a sibling loop.
- BasicBlock *NewLoop01BB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.0"), _, _, _))
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
L.getParentLoop()->addChildLoop(NewLoop);
- NewLoop01BB = BasicBlock::Create(Context, "loop.0.1", &F, &Loop02BB);
- BranchInst::Create(&Loop02BB, NewLoop01BB, Undefi1, NewLoop01BB);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop02BB, NewLoop01BB);
- auto *NewDTNode = AR.DT.addNewBlock(NewLoop01BB, &Loop00BB);
- AR.DT.changeImmediateDominator(AR.DT[&Loop02BB], NewDTNode);
+ auto *NewLoop01PHBB = BasicBlock::Create(Context, "loop.0.1.ph", &F, &Loop02PHBB);
+ auto *NewLoop01BB = BasicBlock::Create(Context, "loop.0.1", &F, &Loop02PHBB);
+ BranchInst::Create(NewLoop01BB, NewLoop01PHBB);
+ CreateCondBr(&Loop02PHBB, NewLoop01BB, "cond.0.1", NewLoop01BB);
+ Loop00BB.getTerminator()->replaceUsesOfWith(&Loop02PHBB, NewLoop01PHBB);
+ AR.DT.addNewBlock(NewLoop01PHBB, &Loop00BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop01BB, NewLoop01PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop02PHBB], NewDTNode);
+ AR.DT.verifyDomTree();
+ L.getParentLoop()->addBasicBlockToLoop(NewLoop01PHBB, AR.LI);
NewLoop->addBasicBlockToLoop(NewLoop01BB, AR.LI);
+ L.getParentLoop()->verifyLoop();
Updater.addSiblingLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -1104,22 +1174,45 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
L.getParentLoop()->addChildLoop(NewLoops[0]);
L.getParentLoop()->addChildLoop(NewLoops[1]);
NewLoops[1]->addChildLoop(NewLoops[2]);
+ auto *NewLoop03PHBB =
+ BasicBlock::Create(Context, "loop.0.3.ph", &F, &Loop0LatchBB);
auto *NewLoop03BB =
- BasicBlock::Create(Context, "loop.0.3", &F, &Loop2BB);
+ BasicBlock::Create(Context, "loop.0.3", &F, &Loop0LatchBB);
+ auto *NewLoop04PHBB =
+ BasicBlock::Create(Context, "loop.0.4.ph", &F, &Loop0LatchBB);
auto *NewLoop04BB =
- BasicBlock::Create(Context, "loop.0.4", &F, &Loop2BB);
+ BasicBlock::Create(Context, "loop.0.4", &F, &Loop0LatchBB);
+ auto *NewLoop040PHBB =
+ BasicBlock::Create(Context, "loop.0.4.0.ph", &F, &Loop0LatchBB);
auto *NewLoop040BB =
- BasicBlock::Create(Context, "loop.0.4.0", &F, &Loop2BB);
- Loop02BB.getTerminator()->replaceUsesOfWith(&Loop0BB, NewLoop03BB);
- BranchInst::Create(NewLoop04BB, NewLoop03BB, Undefi1, NewLoop03BB);
- BranchInst::Create(&Loop0BB, NewLoop040BB, Undefi1, NewLoop04BB);
- BranchInst::Create(NewLoop04BB, NewLoop040BB, Undefi1, NewLoop040BB);
- AR.DT.addNewBlock(NewLoop03BB, &Loop02BB);
- AR.DT.addNewBlock(NewLoop04BB, NewLoop03BB);
- AR.DT.addNewBlock(NewLoop040BB, NewLoop04BB);
+ BasicBlock::Create(Context, "loop.0.4.0", &F, &Loop0LatchBB);
+ auto *NewLoop04LatchBB =
+ BasicBlock::Create(Context, "loop.0.4.latch", &F, &Loop0LatchBB);
+ Loop02BB.getTerminator()->replaceUsesOfWith(&Loop0LatchBB, NewLoop03PHBB);
+ BranchInst::Create(NewLoop03BB, NewLoop03PHBB);
+ CreateCondBr(NewLoop04PHBB, NewLoop03BB, "cond.0.3", NewLoop03BB);
+ BranchInst::Create(NewLoop04BB, NewLoop04PHBB);
+ CreateCondBr(&Loop0LatchBB, NewLoop040PHBB, "cond.0.4", NewLoop04BB);
+ BranchInst::Create(NewLoop040BB, NewLoop040PHBB);
+ CreateCondBr(NewLoop04LatchBB, NewLoop040BB, "cond.0.4.0", NewLoop040BB);
+ BranchInst::Create(NewLoop04BB, NewLoop04LatchBB);
+ AR.DT.addNewBlock(NewLoop03PHBB, &Loop02BB);
+ AR.DT.addNewBlock(NewLoop03BB, NewLoop03PHBB);
+ AR.DT.addNewBlock(NewLoop04PHBB, NewLoop03BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop04BB, NewLoop04PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop0LatchBB], NewDTNode);
+ AR.DT.addNewBlock(NewLoop040PHBB, NewLoop04BB);
+ AR.DT.addNewBlock(NewLoop040BB, NewLoop040PHBB);
+ AR.DT.addNewBlock(NewLoop04LatchBB, NewLoop040BB);
+ AR.DT.verifyDomTree();
+ L.getParentLoop()->addBasicBlockToLoop(NewLoop03PHBB, AR.LI);
NewLoops[0]->addBasicBlockToLoop(NewLoop03BB, AR.LI);
+ L.getParentLoop()->addBasicBlockToLoop(NewLoop04PHBB, AR.LI);
NewLoops[1]->addBasicBlockToLoop(NewLoop04BB, AR.LI);
+ NewLoops[1]->addBasicBlockToLoop(NewLoop040PHBB, AR.LI);
NewLoops[2]->addBasicBlockToLoop(NewLoop040BB, AR.LI);
+ NewLoops[1]->addBasicBlockToLoop(NewLoop04LatchBB, AR.LI);
+ L.getParentLoop()->verifyLoop();
Updater.addSiblingLoops({NewLoops[0], NewLoops[1]});
return PreservedAnalyses::all();
}));
@@ -1158,12 +1251,17 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
AR.LI.addTopLevelLoop(NewLoop);
+ auto *NewLoop1PHBB = BasicBlock::Create(Context, "loop.1.ph", &F, &Loop2BB);
auto *NewLoop1BB = BasicBlock::Create(Context, "loop.1", &F, &Loop2BB);
- BranchInst::Create(&Loop2BB, NewLoop1BB, Undefi1, NewLoop1BB);
- Loop0BB.getTerminator()->replaceUsesOfWith(&Loop2BB, NewLoop1BB);
- auto *NewDTNode = AR.DT.addNewBlock(NewLoop1BB, &Loop0BB);
- AR.DT.changeImmediateDominator(AR.DT[&Loop2BB], NewDTNode);
+ BranchInst::Create(NewLoop1BB, NewLoop1PHBB);
+ CreateCondBr(&Loop2PHBB, NewLoop1BB, "cond.1", NewLoop1BB);
+ Loop0BB.getTerminator()->replaceUsesOfWith(&Loop2PHBB, NewLoop1PHBB);
+ AR.DT.addNewBlock(NewLoop1PHBB, &Loop0BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop1BB, NewLoop1PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop2PHBB], NewDTNode);
+ AR.DT.verifyDomTree();
NewLoop->addBasicBlockToLoop(NewLoop1BB, AR.LI);
+ NewLoop->verifyLoop();
Updater.addSiblingLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -1193,19 +1291,36 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
// Build a module with a single loop nest that contains one outer loop with
// three subloops, and one of those with its own subloop. We will
// incrementally delete all of these to test different deletion scenarios.
- M = parseIR(Context, "define void @f() {\n"
+ M = parseIR(Context, "define void @f(i1* %ptr) {\n"
"entry:\n"
" br label %loop.0\n"
"loop.0:\n"
- " br i1 undef, label %loop.0.0, label %end\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %end\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
"loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.1\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.1.ph\n"
+ "loop.0.1.ph:\n"
+ " br label %loop.0.1\n"
"loop.0.1:\n"
- " br i1 undef, label %loop.0.1, label %loop.0.2\n"
+ " %cond.0.1 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.1, label %loop.0.1, label %loop.0.2.ph\n"
+ "loop.0.2.ph:\n"
+ " br label %loop.0.2\n"
"loop.0.2:\n"
- " br i1 undef, label %loop.0.2.0, label %loop.0\n"
+ " %cond.0.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2, label %loop.0.2.0.ph, label %loop.0.latch\n"
+ "loop.0.2.0.ph:\n"
+ " br label %loop.0.2.0\n"
"loop.0.2.0:\n"
- " br i1 undef, label %loop.0.2.0, label %loop.0.2\n"
+ " %cond.0.2.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2.0, label %loop.0.2.0, label %loop.0.2.latch\n"
+ "loop.0.2.latch:\n"
+ " br label %loop.0.2\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
"end:\n"
" ret void\n"
"}\n");
@@ -1214,44 +1329,64 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
// easily.
Function &F = *M->begin();
ASSERT_THAT(F, HasName("f"));
+ Argument &Ptr = *F.arg_begin();
auto BBI = F.begin();
BasicBlock &EntryBB = *BBI++;
ASSERT_THAT(EntryBB, HasName("entry"));
BasicBlock &Loop0BB = *BBI++;
ASSERT_THAT(Loop0BB, HasName("loop.0"));
+ BasicBlock &Loop00PHBB = *BBI++;
+ ASSERT_THAT(Loop00PHBB, HasName("loop.0.0.ph"));
BasicBlock &Loop00BB = *BBI++;
ASSERT_THAT(Loop00BB, HasName("loop.0.0"));
+ BasicBlock &Loop01PHBB = *BBI++;
+ ASSERT_THAT(Loop01PHBB, HasName("loop.0.1.ph"));
BasicBlock &Loop01BB = *BBI++;
ASSERT_THAT(Loop01BB, HasName("loop.0.1"));
+ BasicBlock &Loop02PHBB = *BBI++;
+ ASSERT_THAT(Loop02PHBB, HasName("loop.0.2.ph"));
BasicBlock &Loop02BB = *BBI++;
ASSERT_THAT(Loop02BB, HasName("loop.0.2"));
+ BasicBlock &Loop020PHBB = *BBI++;
+ ASSERT_THAT(Loop020PHBB, HasName("loop.0.2.0.ph"));
BasicBlock &Loop020BB = *BBI++;
ASSERT_THAT(Loop020BB, HasName("loop.0.2.0"));
+ BasicBlock &Loop02LatchBB = *BBI++;
+ ASSERT_THAT(Loop02LatchBB, HasName("loop.0.2.latch"));
+ BasicBlock &Loop0LatchBB = *BBI++;
+ ASSERT_THAT(Loop0LatchBB, HasName("loop.0.latch"));
BasicBlock &EndBB = *BBI++;
ASSERT_THAT(EndBB, HasName("end"));
ASSERT_THAT(BBI, F.end());
- Constant *Undefi1 = UndefValue::get(Type::getInt1Ty(Context));
// Helper to do the actual deletion of a loop. We directly encode this here
// to isolate ourselves from the rest of LLVM and for simplicity. Here we can
// egregiously cheat based on knowledge of the test case. For example, we
// have no PHI nodes and there is always a single i-dom.
- auto DeleteLoopBlocks = [](Loop &L, BasicBlock &IDomBB,
+ auto RemoveLoop = [](Loop &L, BasicBlock &IDomBB,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- for (BasicBlock *LoopBB : L.blocks()) {
+ assert(L.empty() && "Can only delete leaf loops with this routine!");
+ SmallVector<BasicBlock *, 4> LoopBBs(L.block_begin(), L.block_end());
+ Updater.markLoopAsDeleted(L);
+ IDomBB.getTerminator()->replaceUsesOfWith(L.getHeader(),
+ L.getUniqueExitBlock());
+ for (BasicBlock *LoopBB : LoopBBs) {
SmallVector<DomTreeNode *, 4> ChildNodes(AR.DT[LoopBB]->begin(),
AR.DT[LoopBB]->end());
for (DomTreeNode *ChildNode : ChildNodes)
AR.DT.changeImmediateDominator(ChildNode, AR.DT[&IDomBB]);
AR.DT.eraseNode(LoopBB);
+ AR.LI.removeBlock(LoopBB);
LoopBB->dropAllReferences();
}
- SmallVector<BasicBlock *, 4> LoopBBs(L.block_begin(), L.block_end());
- Updater.markLoopAsDeleted(L);
- AR.LI.markAsRemoved(&L);
for (BasicBlock *LoopBB : LoopBBs)
LoopBB->eraseFromParent();
+
+ if (Loop *ParentL = L.getParentLoop())
+ return ParentL->removeChildLoop(find(*ParentL, &L));
+
+ return AR.LI.removeLoop(find(AR.LI, &L));
};
// Build up the pass managers.
@@ -1294,9 +1429,10 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
.WillOnce(
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
+ Loop *ParentL = L.getParentLoop();
AR.SE.forgetLoop(&L);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop01BB, &Loop02BB);
- DeleteLoopBlocks(L, Loop00BB, AR, Updater);
+ delete RemoveLoop(L, Loop01PHBB, AR, Updater);
+ ParentL->verifyLoop();
return PreservedAnalyses::all();
}));
@@ -1337,38 +1473,40 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
EXPECT_CALL(MLPHandle, run(HasName("loop.0.2"), _, _, _))
.WillOnce(Invoke(getLoopAnalysisResult));
- BasicBlock *NewLoop03BB;
+ BasicBlock *NewLoop03PHBB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.2"), _, _, _))
.WillOnce(
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
- // Delete the inner loop first. we also do this manually because we
- // want to preserve the loop object and reuse it.
+ // Remove the inner loop first but retain it to reuse later.
AR.SE.forgetLoop(*L.begin());
- Loop02BB.getTerminator()->replaceUsesOfWith(&Loop020BB, &Loop02BB);
- assert(std::next((*L.begin())->block_begin()) ==
- (*L.begin())->block_end() &&
- "There should only be one block.");
- assert(AR.DT[&Loop020BB]->getNumChildren() == 0 &&
- "Cannot have children in the domtree!");
- AR.DT.eraseNode(&Loop020BB);
- Updater.markLoopAsDeleted(**L.begin());
- AR.LI.removeBlock(&Loop020BB);
- auto *OldL = L.removeChildLoop(L.begin());
- Loop020BB.eraseFromParent();
+ auto *OldL = RemoveLoop(**L.begin(), Loop020PHBB, AR, Updater);
auto *ParentL = L.getParentLoop();
AR.SE.forgetLoop(&L);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop02BB, &Loop0BB);
- DeleteLoopBlocks(L, Loop00BB, AR, Updater);
+ delete RemoveLoop(L, Loop02PHBB, AR, Updater);
// Now insert a new sibling loop, reusing a loop pointer.
ParentL->addChildLoop(OldL);
- NewLoop03BB = BasicBlock::Create(Context, "loop.0.3", &F, &EndBB);
- BranchInst::Create(&Loop0BB, NewLoop03BB, Undefi1, NewLoop03BB);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop0BB, NewLoop03BB);
- AR.DT.addNewBlock(NewLoop03BB, &Loop00BB);
+ NewLoop03PHBB =
+ BasicBlock::Create(Context, "loop.0.3.ph", &F, &Loop0LatchBB);
+ auto *NewLoop03BB =
+ BasicBlock::Create(Context, "loop.0.3", &F, &Loop0LatchBB);
+ BranchInst::Create(NewLoop03BB, NewLoop03PHBB);
+ auto *Cond = new LoadInst(&Ptr, "cond.0.3", /*isVolatile*/ true,
+ NewLoop03BB);
+ BranchInst::Create(&Loop0LatchBB, NewLoop03BB, Cond, NewLoop03BB);
+ Loop02PHBB.getTerminator()->replaceUsesOfWith(&Loop0LatchBB,
+ NewLoop03PHBB);
+ AR.DT.addNewBlock(NewLoop03PHBB, &Loop02PHBB);
+ AR.DT.addNewBlock(NewLoop03BB, NewLoop03PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop0LatchBB],
+ AR.DT[NewLoop03BB]);
+ AR.DT.verifyDomTree();
+ ParentL->addBasicBlockToLoop(NewLoop03PHBB, AR.LI);
OldL->addBasicBlockToLoop(NewLoop03BB, AR.LI);
+ OldL->verifyLoop();
+ ParentL->verifyLoop();
Updater.addSiblingLoops({OldL});
return PreservedAnalyses::all();
}));
@@ -1401,8 +1539,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- Loop0BB.getTerminator()->replaceUsesOfWith(&Loop00BB, NewLoop03BB);
- DeleteLoopBlocks(L, Loop0BB, AR, Updater);
+ delete RemoveLoop(L, Loop00PHBB, AR, Updater);
return PreservedAnalyses::all();
}));
@@ -1413,8 +1550,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- Loop0BB.getTerminator()->replaceUsesOfWith(NewLoop03BB, &Loop0BB);
- DeleteLoopBlocks(L, Loop0BB, AR, Updater);
+ delete RemoveLoop(L, *NewLoop03PHBB, AR, Updater);
return PreservedAnalyses::all();
}));
@@ -1425,8 +1561,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- EntryBB.getTerminator()->replaceUsesOfWith(&Loop0BB, &EndBB);
- DeleteLoopBlocks(L, EntryBB, AR, Updater);
+ delete RemoveLoop(L, EntryBB, AR, Updater);
return PreservedAnalyses::all();
}));
diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt
index c0f37418e492..0fc19ef09fb0 100644
--- a/unittests/Transforms/Utils/CMakeLists.txt
+++ b/unittests/Transforms/Utils/CMakeLists.txt
@@ -11,6 +11,5 @@ add_llvm_unittest(UtilsTests
FunctionComparator.cpp
IntegerDivision.cpp
Local.cpp
- MemorySSA.cpp
ValueMapperTest.cpp
)
diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp
index 216bd32c50d2..403c9c06c18a 100644
--- a/unittests/Transforms/Utils/Cloning.cpp
+++ b/unittests/Transforms/Utils/Cloning.cpp
@@ -163,7 +163,7 @@ TEST_F(CloneInstruction, Attributes) {
Function *F2 = Function::Create(FT1, Function::ExternalLinkage);
Attribute::AttrKind AK[] = { Attribute::NoCapture };
- AttributeSet AS = AttributeSet::get(context, 0, AK);
+ AttributeList AS = AttributeList::get(context, 0, AK);
Argument *A = &*F1->arg_begin();
A->addAttr(AS);
@@ -201,6 +201,53 @@ TEST_F(CloneInstruction, CallingConvention) {
delete F2;
}
+TEST_F(CloneInstruction, DuplicateInstructionsToSplit) {
+ Type *ArgTy1[] = {Type::getInt32PtrTy(context)};
+ FunctionType *FT = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
+ V = new Argument(Type::getInt32Ty(context));
+
+ Function *F = Function::Create(FT, Function::ExternalLinkage);
+
+ BasicBlock *BB1 = BasicBlock::Create(context, "", F);
+ IRBuilder<> Builder1(BB1);
+
+ BasicBlock *BB2 = BasicBlock::Create(context, "", F);
+ IRBuilder<> Builder2(BB2);
+
+ Builder1.CreateBr(BB2);
+
+ Instruction *AddInst = cast<Instruction>(Builder2.CreateAdd(V, V));
+ Instruction *MulInst = cast<Instruction>(Builder2.CreateMul(AddInst, V));
+ Instruction *SubInst = cast<Instruction>(Builder2.CreateSub(MulInst, V));
+ Builder2.CreateRetVoid();
+
+ ValueToValueMapTy Mapping;
+
+ auto Split = DuplicateInstructionsInSplitBetween(BB2, BB1, SubInst, Mapping);
+
+ EXPECT_TRUE(Split);
+ EXPECT_EQ(Mapping.size(), 2u);
+ EXPECT_TRUE(Mapping.find(AddInst) != Mapping.end());
+ EXPECT_TRUE(Mapping.find(MulInst) != Mapping.end());
+
+ auto AddSplit = dyn_cast<Instruction>(Mapping[AddInst]);
+ EXPECT_TRUE(AddSplit);
+ EXPECT_EQ(AddSplit->getOperand(0), V);
+ EXPECT_EQ(AddSplit->getOperand(1), V);
+ EXPECT_EQ(AddSplit->getParent(), Split);
+
+ auto MulSplit = dyn_cast<Instruction>(Mapping[MulInst]);
+ EXPECT_TRUE(MulSplit);
+ EXPECT_EQ(MulSplit->getOperand(0), AddSplit);
+ EXPECT_EQ(MulSplit->getOperand(1), V);
+ EXPECT_EQ(MulSplit->getParent(), Split);
+
+ EXPECT_EQ(AddSplit->getNextNode(), MulSplit);
+ EXPECT_EQ(MulSplit->getNextNode(), Split->getTerminator());
+
+ delete F;
+}
+
class CloneFunc : public ::testing::Test {
protected:
void SetUp() override {
@@ -405,10 +452,14 @@ protected:
void SetupModule() { OldM = new Module("", C); }
void CreateOldModule() {
+ auto *CD = OldM->getOrInsertComdat("comdat");
+ CD->setSelectionKind(Comdat::ExactMatch);
+
auto GV = new GlobalVariable(
*OldM, Type::getInt32Ty(C), false, GlobalValue::ExternalLinkage,
ConstantInt::get(Type::getInt32Ty(C), 1), "gv");
GV->addMetadata(LLVMContext::MD_type, *MDNode::get(C, {}));
+ GV->setComdat(CD);
DIBuilder DBuilder(*OldM);
IRBuilder<> IBuilder(C);
@@ -419,6 +470,7 @@ protected:
auto *F =
Function::Create(FuncType, GlobalValue::PrivateLinkage, "f", OldM);
F->setPersonalityFn(PersFn);
+ F->setComdat(CD);
// Create debug info
auto *File = DBuilder.createFile("filename.c", "/file/dir/");
@@ -472,4 +524,15 @@ TEST_F(CloneModule, GlobalMetadata) {
GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
EXPECT_NE(nullptr, NewGV->getMetadata(LLVMContext::MD_type));
}
+
+TEST_F(CloneModule, Comdat) {
+ GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
+ auto *CD = NewGV->getComdat();
+ ASSERT_NE(nullptr, CD);
+ EXPECT_EQ("comdat", CD->getName());
+ EXPECT_EQ(Comdat::ExactMatch, CD->getSelectionKind());
+
+ Function *NewF = NewM->getFunction("f");
+ EXPECT_EQ(CD, NewF->getComdat());
+}
}
diff --git a/unittests/Transforms/Utils/IntegerDivision.cpp b/unittests/Transforms/Utils/IntegerDivision.cpp
index b6b1b1665ab1..e337b9f547a8 100644
--- a/unittests/Transforms/Utils/IntegerDivision.cpp
+++ b/unittests/Transforms/Utils/IntegerDivision.cpp
@@ -29,7 +29,7 @@ TEST(IntegerDivision, SDiv) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -59,7 +59,7 @@ TEST(IntegerDivision, UDiv) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -89,7 +89,7 @@ TEST(IntegerDivision, SRem) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -119,7 +119,7 @@ TEST(IntegerDivision, URem) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -150,7 +150,7 @@ TEST(IntegerDivision, SDiv64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -180,7 +180,7 @@ TEST(IntegerDivision, UDiv64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -210,7 +210,7 @@ TEST(IntegerDivision, SRem64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -240,7 +240,7 @@ TEST(IntegerDivision, URem64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
diff --git a/unittests/Transforms/Utils/MemorySSA.cpp b/unittests/Transforms/Utils/MemorySSA.cpp
deleted file mode 100644
index 945fe32c316c..000000000000
--- a/unittests/Transforms/Utils/MemorySSA.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-//===- MemorySSA.cpp - Unit tests for MemorySSA ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "llvm/Transforms/Utils/MemorySSA.h"
-#include "llvm/Analysis/AliasAnalysis.h"
-#include "llvm/Analysis/BasicAliasAnalysis.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/LLVMContext.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-
-const static char DLString[] = "e-i64:64-f80:128-n8:16:32:64-S128";
-
-/// There's a lot of common setup between these tests. This fixture helps reduce
-/// that. Tests should mock up a function, store it in F, and then call
-/// setupAnalyses().
-class MemorySSATest : public testing::Test {
-protected:
- // N.B. Many of these members depend on each other (e.g. the Module depends on
- // the Context, etc.). So, order matters here (and in TestAnalyses).
- LLVMContext C;
- Module M;
- IRBuilder<> B;
- DataLayout DL;
- TargetLibraryInfoImpl TLII;
- TargetLibraryInfo TLI;
- Function *F;
-
- // Things that we need to build after the function is created.
- struct TestAnalyses {
- DominatorTree DT;
- AssumptionCache AC;
- AAResults AA;
- BasicAAResult BAA;
- // We need to defer MSSA construction until AA is *entirely* set up, which
- // requires calling addAAResult. Hence, we just use a pointer here.
- std::unique_ptr<MemorySSA> MSSA;
- MemorySSAWalker *Walker;
-
- TestAnalyses(MemorySSATest &Test)
- : DT(*Test.F), AC(*Test.F), AA(Test.TLI),
- BAA(Test.DL, Test.TLI, AC, &DT) {
- AA.addAAResult(BAA);
- MSSA = make_unique<MemorySSA>(*Test.F, &AA, &DT);
- Walker = MSSA->getWalker();
- }
- };
-
- std::unique_ptr<TestAnalyses> Analyses;
-
- void setupAnalyses() {
- assert(F);
- Analyses.reset(new TestAnalyses(*this));
- }
-
-public:
- MemorySSATest()
- : M("MemorySSATest", C), B(C), DL(DLString), TLI(TLII), F(nullptr) {}
-};
-
-TEST_F(MemorySSATest, CreateALoad) {
- // We create a diamond where there is a store on one side, and then after
- // building MemorySSA, create a load after the merge point, and use it to test
- // updating by creating an access for the load.
- F = Function::Create(
- FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- BasicBlock *Entry(BasicBlock::Create(C, "", F));
- BasicBlock *Left(BasicBlock::Create(C, "", F));
- BasicBlock *Right(BasicBlock::Create(C, "", F));
- BasicBlock *Merge(BasicBlock::Create(C, "", F));
- B.SetInsertPoint(Entry);
- B.CreateCondBr(B.getTrue(), Left, Right);
- B.SetInsertPoint(Left);
- Argument *PointerArg = &*F->arg_begin();
- B.CreateStore(B.getInt8(16), PointerArg);
- BranchInst::Create(Merge, Left);
- BranchInst::Create(Merge, Right);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- // Add the load
- B.SetInsertPoint(Merge);
- LoadInst *LoadInst = B.CreateLoad(PointerArg);
-
- // MemoryPHI should already exist.
- MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
- EXPECT_NE(MP, nullptr);
-
- // Create the load memory acccess
- MemoryUse *LoadAccess = cast<MemoryUse>(
- MSSA.createMemoryAccessInBB(LoadInst, MP, Merge, MemorySSA::Beginning));
- MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
- EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
- MSSA.verifyMemorySSA();
-}
-
-TEST_F(MemorySSATest, MoveAStore) {
- // We create a diamond where there is a in the entry, a store on one side, and
- // a load at the end. After building MemorySSA, we test updating by moving
- // the store from the side block to the entry block.
- F = Function::Create(
- FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- BasicBlock *Entry(BasicBlock::Create(C, "", F));
- BasicBlock *Left(BasicBlock::Create(C, "", F));
- BasicBlock *Right(BasicBlock::Create(C, "", F));
- BasicBlock *Merge(BasicBlock::Create(C, "", F));
- B.SetInsertPoint(Entry);
- Argument *PointerArg = &*F->arg_begin();
- StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
- B.CreateCondBr(B.getTrue(), Left, Right);
- B.SetInsertPoint(Left);
- StoreInst *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
- BranchInst::Create(Merge, Left);
- BranchInst::Create(Merge, Right);
- B.SetInsertPoint(Merge);
- B.CreateLoad(PointerArg);
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
-
- // Move the store
- SideStore->moveBefore(Entry->getTerminator());
- MemoryAccess *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
- MemoryAccess *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
- MemoryAccess *NewStoreAccess = MSSA.createMemoryAccessAfter(
- SideStore, EntryStoreAccess, EntryStoreAccess);
- EntryStoreAccess->replaceAllUsesWith(NewStoreAccess);
- MSSA.removeMemoryAccess(SideStoreAccess);
- MSSA.verifyMemorySSA();
-}
-
-TEST_F(MemorySSATest, RemoveAPhi) {
- // We create a diamond where there is a store on one side, and then a load
- // after the merge point. This enables us to test a bunch of different
- // removal cases.
- F = Function::Create(
- FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- BasicBlock *Entry(BasicBlock::Create(C, "", F));
- BasicBlock *Left(BasicBlock::Create(C, "", F));
- BasicBlock *Right(BasicBlock::Create(C, "", F));
- BasicBlock *Merge(BasicBlock::Create(C, "", F));
- B.SetInsertPoint(Entry);
- B.CreateCondBr(B.getTrue(), Left, Right);
- B.SetInsertPoint(Left);
- Argument *PointerArg = &*F->arg_begin();
- StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg);
- BranchInst::Create(Merge, Left);
- BranchInst::Create(Merge, Right);
- B.SetInsertPoint(Merge);
- LoadInst *LoadInst = B.CreateLoad(PointerArg);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- // Before, the load will be a use of a phi<store, liveonentry>.
- MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LoadInst));
- MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst));
- MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
- EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
- // Kill the store
- MSSA.removeMemoryAccess(StoreAccess);
- MemoryPhi *MP = cast<MemoryPhi>(DefiningAccess);
- // Verify the phi ended up as liveonentry, liveonentry
- for (auto &Op : MP->incoming_values())
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(cast<MemoryAccess>(Op.get())));
- // Replace the phi uses with the live on entry def
- MP->replaceAllUsesWith(MSSA.getLiveOnEntryDef());
- // Verify the load is now defined by liveOnEntryDef
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess()));
- // Remove the PHI
- MSSA.removeMemoryAccess(MP);
- MSSA.verifyMemorySSA();
-}
-
-TEST_F(MemorySSATest, RemoveMemoryAccess) {
- // We create a diamond where there is a store on one side, and then a load
- // after the merge point. This enables us to test a bunch of different
- // removal cases.
- F = Function::Create(
- FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- BasicBlock *Entry(BasicBlock::Create(C, "", F));
- BasicBlock *Left(BasicBlock::Create(C, "", F));
- BasicBlock *Right(BasicBlock::Create(C, "", F));
- BasicBlock *Merge(BasicBlock::Create(C, "", F));
- B.SetInsertPoint(Entry);
- B.CreateCondBr(B.getTrue(), Left, Right);
- B.SetInsertPoint(Left);
- Argument *PointerArg = &*F->arg_begin();
- StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg);
- BranchInst::Create(Merge, Left);
- BranchInst::Create(Merge, Right);
- B.SetInsertPoint(Merge);
- LoadInst *LoadInst = B.CreateLoad(PointerArg);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- // Before, the load will be a use of a phi<store, liveonentry>. It should be
- // the same after.
- MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LoadInst));
- MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst));
- MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
- EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
- // The load is currently clobbered by one of the phi arguments, so the walker
- // should determine the clobbering access as the phi.
- EXPECT_EQ(DefiningAccess, Walker->getClobberingMemoryAccess(LoadInst));
- MSSA.removeMemoryAccess(StoreAccess);
- MSSA.verifyMemorySSA();
- // After the removeaccess, let's see if we got the right accesses
- // The load should still point to the phi ...
- EXPECT_EQ(DefiningAccess, LoadAccess->getDefiningAccess());
- // but we should now get live on entry for the clobbering definition of the
- // load, since it will walk past the phi node since every argument is the
- // same.
- // XXX: This currently requires either removing the phi or resetting optimized
- // on the load
-
- EXPECT_FALSE(
- MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst)));
- // If we reset optimized, we get live on entry.
- LoadAccess->resetOptimized();
- EXPECT_TRUE(
- MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst)));
- // The phi should now be a two entry phi with two live on entry defs.
- for (const auto &Op : DefiningAccess->operands()) {
- MemoryAccess *Operand = cast<MemoryAccess>(&*Op);
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(Operand));
- }
-
- // Now we try to remove the single valued phi
- MSSA.removeMemoryAccess(DefiningAccess);
- MSSA.verifyMemorySSA();
- // Now the load should be a load of live on entry.
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess()));
-}
-
-// We had a bug with caching where the walker would report MemoryDef#3's clobber
-// (below) was MemoryDef#1.
-//
-// define void @F(i8*) {
-// %A = alloca i8, i8 1
-// ; 1 = MemoryDef(liveOnEntry)
-// store i8 0, i8* %A
-// ; 2 = MemoryDef(1)
-// store i8 1, i8* %A
-// ; 3 = MemoryDef(2)
-// store i8 2, i8* %A
-// }
-TEST_F(MemorySSATest, TestTripleStore) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "", F));
- Type *Int8 = Type::getInt8Ty(C);
- Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
- StoreInst *S1 = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
- StoreInst *S2 = B.CreateStore(ConstantInt::get(Int8, 1), Alloca);
- StoreInst *S3 = B.CreateStore(ConstantInt::get(Int8, 2), Alloca);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- unsigned I = 0;
- for (StoreInst *V : {S1, S2, S3}) {
- // Everything should be clobbered by its defining access
- MemoryAccess *DefiningAccess = MSSA.getMemoryAccess(V)->getDefiningAccess();
- MemoryAccess *WalkerClobber = Walker->getClobberingMemoryAccess(V);
- EXPECT_EQ(DefiningAccess, WalkerClobber)
- << "Store " << I << " doesn't have the correct clobbering access";
- // EXPECT_EQ expands such that if we increment I above, it won't get
- // incremented except when we try to print the error message.
- ++I;
- }
-}
-
-// ...And fixing the above bug made it obvious that, when walking, MemorySSA's
-// walker was caching the initial node it walked. This was fine (albeit
-// mostly redundant) unless the initial node being walked is a clobber for the
-// query. In that case, we'd cache that the node clobbered itself.
-TEST_F(MemorySSATest, TestStoreAndLoad) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "", F));
- Type *Int8 = Type::getInt8Ty(C);
- Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
- Instruction *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
- Instruction *LI = B.CreateLoad(Alloca);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LI);
- EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SI));
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SI)));
-}
-
-// Another bug (related to the above two fixes): It was noted that, given the
-// following code:
-// ; 1 = MemoryDef(liveOnEntry)
-// store i8 0, i8* %1
-//
-// ...A query to getClobberingMemoryAccess(MemoryAccess*, MemoryLocation) would
-// hand back the store (correctly). A later call to
-// getClobberingMemoryAccess(const Instruction*) would also hand back the store
-// (incorrectly; it should return liveOnEntry).
-//
-// This test checks that repeated calls to either function returns what they're
-// meant to.
-TEST_F(MemorySSATest, TestStoreDoubleQuery) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "", F));
- Type *Int8 = Type::getInt8Ty(C);
- Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
- StoreInst *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- MemoryAccess *StoreAccess = MSSA.getMemoryAccess(SI);
- MemoryLocation StoreLoc = MemoryLocation::get(SI);
- MemoryAccess *Clobber =
- Walker->getClobberingMemoryAccess(StoreAccess, StoreLoc);
- MemoryAccess *LiveOnEntry = Walker->getClobberingMemoryAccess(SI);
-
- EXPECT_EQ(Clobber, StoreAccess);
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry));
-
- // Try again (with entries in the cache already) for good measure...
- Clobber = Walker->getClobberingMemoryAccess(StoreAccess, StoreLoc);
- LiveOnEntry = Walker->getClobberingMemoryAccess(SI);
- EXPECT_EQ(Clobber, StoreAccess);
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry));
-}
-
-// Bug: During phi optimization, the walker wouldn't cache to the proper result
-// in the farthest-walked BB.
-//
-// Specifically, it would assume that whatever we walked to was a clobber.
-// "Whatever we walked to" isn't a clobber if we hit a cache entry.
-//
-// ...So, we need a test case that looks like:
-// A
-// / \
-// B |
-// \ /
-// C
-//
-// Where, when we try to optimize a thing in 'C', a blocker is found in 'B'.
-// The walk must determine that the blocker exists by using cache entries *while
-// walking* 'B'.
-TEST_F(MemorySSATest, PartialWalkerCacheWithPhis) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "A", F));
- Type *Int8 = Type::getInt8Ty(C);
- Constant *One = ConstantInt::get(Int8, 1);
- Constant *Zero = ConstantInt::get(Int8, 0);
- Value *AllocA = B.CreateAlloca(Int8, One, "a");
- Value *AllocB = B.CreateAlloca(Int8, One, "b");
- BasicBlock *IfThen = BasicBlock::Create(C, "B", F);
- BasicBlock *IfEnd = BasicBlock::Create(C, "C", F);
-
- B.CreateCondBr(UndefValue::get(Type::getInt1Ty(C)), IfThen, IfEnd);
-
- B.SetInsertPoint(IfThen);
- Instruction *FirstStore = B.CreateStore(Zero, AllocA);
- B.CreateStore(Zero, AllocB);
- Instruction *ALoad0 = B.CreateLoad(AllocA, "");
- Instruction *BStore = B.CreateStore(Zero, AllocB);
- // Due to use optimization/etc. we make a store to A, which is removed after
- // we build MSSA. This helps keep the test case simple-ish.
- Instruction *KillStore = B.CreateStore(Zero, AllocA);
- Instruction *ALoad = B.CreateLoad(AllocA, "");
- B.CreateBr(IfEnd);
-
- B.SetInsertPoint(IfEnd);
- Instruction *BelowPhi = B.CreateStore(Zero, AllocA);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- // Kill `KillStore`; it exists solely so that the load after it won't be
- // optimized to FirstStore.
- MSSA.removeMemoryAccess(MSSA.getMemoryAccess(KillStore));
- KillStore->eraseFromParent();
- auto *ALoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(ALoad));
- EXPECT_EQ(ALoadMA->getDefiningAccess(), MSSA.getMemoryAccess(BStore));
-
- // Populate the cache for the store to AllocB directly after FirstStore. It
- // should point to something in block B (so something in D can't be optimized
- // to it).
- MemoryAccess *Load0Clobber = Walker->getClobberingMemoryAccess(ALoad0);
- EXPECT_EQ(MSSA.getMemoryAccess(FirstStore), Load0Clobber);
-
- // If the bug exists, this will introduce a bad cache entry for %a on BStore.
- // It will point to the store to %b after FirstStore. This only happens during
- // phi optimization.
- MemoryAccess *BottomClobber = Walker->getClobberingMemoryAccess(BelowPhi);
- MemoryAccess *Phi = MSSA.getMemoryAccess(IfEnd);
- EXPECT_EQ(BottomClobber, Phi);
-
- // This query will first check the cache for {%a, BStore}. It should point to
- // FirstStore, not to the store after FirstStore.
- MemoryAccess *UseClobber = Walker->getClobberingMemoryAccess(ALoad);
- EXPECT_EQ(UseClobber, MSSA.getMemoryAccess(FirstStore));
-}
-
-// Test that our walker properly handles loads with the invariant group
-// attribute. It's a bit hacky, since we add the invariant attribute *after*
-// building MSSA. Otherwise, the use optimizer will optimize it for us, which
-// isn't what we want.
-// FIXME: It may be easier/cleaner to just add an 'optimize uses?' flag to MSSA.
-TEST_F(MemorySSATest, WalkerInvariantLoadOpt) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "", F));
- Type *Int8 = Type::getInt8Ty(C);
- Constant *One = ConstantInt::get(Int8, 1);
- Value *AllocA = B.CreateAlloca(Int8, One, "");
-
- Instruction *Store = B.CreateStore(One, AllocA);
- Instruction *Load = B.CreateLoad(AllocA);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- auto *LoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(Load));
- auto *StoreMA = cast<MemoryDef>(MSSA.getMemoryAccess(Store));
- EXPECT_EQ(LoadMA->getDefiningAccess(), StoreMA);
-
- // ...At the time of writing, no cache should exist for LoadMA. Be a bit
- // flexible to future changes.
- Walker->invalidateInfo(LoadMA);
- Load->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(C, {}));
-
- MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LoadMA);
- EXPECT_EQ(LoadClobber, MSSA.getLiveOnEntryDef());
-}
-
-// Test loads get reoptimized properly by the walker.
-TEST_F(MemorySSATest, WalkerReopt) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "", F));
- Type *Int8 = Type::getInt8Ty(C);
- Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
- Instruction *SIA = B.CreateStore(ConstantInt::get(Int8, 0), AllocaA);
- Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
- Instruction *SIB = B.CreateStore(ConstantInt::get(Int8, 0), AllocaB);
- Instruction *LIA = B.CreateLoad(AllocaA);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker *Walker = Analyses->Walker;
-
- MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LIA);
- MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LIA));
- EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SIA));
- EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SIA)));
- MSSA.removeMemoryAccess(LoadAccess);
-
- // Create the load memory access pointing to an unoptimized place.
- MemoryUse *NewLoadAccess = cast<MemoryUse>(MSSA.createMemoryAccessInBB(
- LIA, MSSA.getMemoryAccess(SIB), LIA->getParent(), MemorySSA::End));
- // This should it cause it to be optimized
- EXPECT_EQ(Walker->getClobberingMemoryAccess(NewLoadAccess), LoadClobber);
- EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber);
-}
-
-// Test out MemorySSA::spliceMemoryAccessAbove.
-TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
- F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
- GlobalValue::ExternalLinkage, "F", &M);
- B.SetInsertPoint(BasicBlock::Create(C, "", F));
-
- Type *Int8 = Type::getInt8Ty(C);
- Value *A = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
- Value *B_ = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
- Value *C = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "C");
-
- StoreInst *StoreA0 = B.CreateStore(ConstantInt::get(Int8, 0), A);
- StoreInst *StoreB = B.CreateStore(ConstantInt::get(Int8, 0), B_);
- LoadInst *LoadB = B.CreateLoad(B_);
- StoreInst *StoreA1 = B.CreateStore(ConstantInt::get(Int8, 4), A);
- // splice this above StoreB
- StoreInst *StoreC = B.CreateStore(ConstantInt::get(Int8, 4), C);
- StoreInst *StoreA2 = B.CreateStore(ConstantInt::get(Int8, 4), A);
- LoadInst *LoadC = B.CreateLoad(C);
-
- setupAnalyses();
- MemorySSA &MSSA = *Analyses->MSSA;
- MemorySSAWalker &Walker = *Analyses->Walker;
-
- StoreC->moveBefore(StoreB);
- MSSA.spliceMemoryAccessAbove(cast<MemoryDef>(MSSA.getMemoryAccess(StoreB)),
- MSSA.getMemoryAccess(StoreC));
-
- MSSA.verifyMemorySSA();
-
- EXPECT_EQ(MSSA.getMemoryAccess(StoreB)->getDefiningAccess(),
- MSSA.getMemoryAccess(StoreC));
- EXPECT_EQ(MSSA.getMemoryAccess(StoreC)->getDefiningAccess(),
- MSSA.getMemoryAccess(StoreA0));
- EXPECT_EQ(MSSA.getMemoryAccess(StoreA2)->getDefiningAccess(),
- MSSA.getMemoryAccess(StoreA1));
- EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadB),
- MSSA.getMemoryAccess(StoreB));
- EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadC),
- MSSA.getMemoryAccess(StoreC));
-
- // exercise block numbering
- EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreC),
- MSSA.getMemoryAccess(StoreB)));
- EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1),
- MSSA.getMemoryAccess(StoreA2)));
-}