summaryrefslogtreecommitdiff
path: root/unittests/Transforms/Utils
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/Transforms/Utils')
-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
4 files changed, 72 insertions, 544 deletions
diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt
index c0f37418e4928..0fc19ef09fb01 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 216bd32c50d2a..403c9c06c18a2 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 b6b1b1665ab1f..e337b9f547a89 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 945fe32c316c2..0000000000000
--- 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)));
-}