[AA] Enhance the new AliasAnalysis infrastructure with an optional
[oota-llvm.git] / unittests / Analysis / AliasAnalysisTest.cpp
1 //===--- AliasAnalysisTest.cpp - Mixed TBAA unit tests --------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/Analysis/AliasAnalysis.h"
11 #include "llvm/ADT/SetVector.h"
12 #include "llvm/Analysis/AssumptionCache.h"
13 #include "llvm/Analysis/BasicAliasAnalysis.h"
14 #include "llvm/Analysis/TargetLibraryInfo.h"
15 #include "llvm/AsmParser/Parser.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/InstIterator.h"
19 #include "llvm/IR/LLVMContext.h"
20 #include "llvm/IR/LegacyPassManager.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/Support/CommandLine.h"
23 #include "llvm/Support/SourceMgr.h"
24 #include "gtest/gtest.h"
25
26 using namespace llvm;
27
28 // Set up some test passes.
29 namespace llvm {
30 void initializeAATestPassPass(PassRegistry&);
31 void initializeTestCustomAAWrapperPassPass(PassRegistry&);
32 }
33
34 namespace {
35 struct AATestPass : FunctionPass {
36   static char ID;
37   AATestPass() : FunctionPass(ID) {
38     initializeAATestPassPass(*PassRegistry::getPassRegistry());
39   }
40
41   void getAnalysisUsage(AnalysisUsage &AU) const override {
42     AU.addRequired<AAResultsWrapperPass>();
43     AU.setPreservesAll();
44   }
45
46   bool runOnFunction(Function &F) override {
47     AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
48
49     SetVector<Value *> Pointers;
50     for (Argument &A : F.args())
51       if (A.getType()->isPointerTy())
52         Pointers.insert(&A);
53     for (Instruction &I : instructions(F))
54       if (I.getType()->isPointerTy())
55         Pointers.insert(&I);
56
57     for (Value *P1 : Pointers)
58       for (Value *P2 : Pointers)
59         (void)AA.alias(P1, MemoryLocation::UnknownSize, P2,
60                        MemoryLocation::UnknownSize);
61
62     return false;
63   }
64 };
65 }
66
67 char AATestPass::ID = 0;
68 INITIALIZE_PASS_BEGIN(AATestPass, "aa-test-pas", "Alias Analysis Test Pass",
69                       false, true)
70 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
71 INITIALIZE_PASS_END(AATestPass, "aa-test-pass", "Alias Analysis Test Pass",
72                     false, true)
73
74 namespace {
75 /// A test customizable AA result. It merely accepts a callback to run whenever
76 /// it receives an alias query. Useful for testing that a particular AA result
77 /// is reached.
78 struct TestCustomAAResult : AAResultBase<TestCustomAAResult> {
79   friend AAResultBase<TestCustomAAResult>;
80
81   std::function<void()> CB;
82
83   explicit TestCustomAAResult(const TargetLibraryInfo &TLI,
84                               std::function<void()> CB)
85       : AAResultBase(TLI), CB(std::move(CB)) {}
86   TestCustomAAResult(TestCustomAAResult &&Arg)
87       : AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {}
88
89   bool invalidate(Function &, const PreservedAnalyses &) { return false; }
90
91   AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
92     CB();
93     return MayAlias;
94   }
95 };
96 }
97
98 namespace {
99 /// A wrapper pass for the legacy pass manager to use with the above custom AA
100 /// result.
101 class TestCustomAAWrapperPass : public ImmutablePass {
102   std::function<void()> CB;
103   std::unique_ptr<TestCustomAAResult> Result;
104
105 public:
106   static char ID;
107
108   explicit TestCustomAAWrapperPass(
109       std::function<void()> CB = std::function<void()>())
110       : ImmutablePass(ID), CB(std::move(CB)) {
111     initializeTestCustomAAWrapperPassPass(*PassRegistry::getPassRegistry());
112   }
113
114   void getAnalysisUsage(AnalysisUsage &AU) const override {
115     AU.setPreservesAll();
116     AU.addRequired<TargetLibraryInfoWrapperPass>();
117   }
118
119   bool doInitialization(Module &M) override {
120     Result.reset(new TestCustomAAResult(
121         getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(), std::move(CB)));
122     return true;
123   }
124
125   bool doFinalization(Module &M) override {
126     Result.reset();
127     return true;
128   }
129
130   TestCustomAAResult &getResult() { return *Result; }
131   const TestCustomAAResult &getResult() const { return *Result; }
132 };
133 }
134
135 char TestCustomAAWrapperPass::ID = 0;
136 INITIALIZE_PASS_BEGIN(TestCustomAAWrapperPass, "test-custom-aa",
137                 "Test Custom AA Wrapper Pass", false, true)
138 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
139 INITIALIZE_PASS_END(TestCustomAAWrapperPass, "test-custom-aa",
140                 "Test Custom AA Wrapper Pass", false, true)
141
142 namespace {
143
144 class AliasAnalysisTest : public testing::Test {
145 protected:
146   LLVMContext C;
147   Module M;
148   TargetLibraryInfoImpl TLII;
149   TargetLibraryInfo TLI;
150   std::unique_ptr<AssumptionCache> AC;
151   std::unique_ptr<BasicAAResult> BAR;
152   std::unique_ptr<AAResults> AAR;
153
154   AliasAnalysisTest() : M("AliasAnalysisTest", C), TLI(TLII) {}
155
156   AAResults &getAAResults(Function &F) {
157     // Reset the Function AA results first to clear out any references.
158     AAR.reset(new AAResults());
159
160     // Build the various AA results and register them.
161     AC.reset(new AssumptionCache(F));
162     BAR.reset(new BasicAAResult(M.getDataLayout(), TLI, *AC));
163     AAR->addAAResult(*BAR);
164
165     return *AAR;
166   }
167 };
168
169 TEST_F(AliasAnalysisTest, getModRefInfo) {
170   // Setup function.
171   FunctionType *FTy =
172       FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false);
173   auto *F = cast<Function>(M.getOrInsertFunction("f", FTy));
174   auto *BB = BasicBlock::Create(C, "entry", F);
175   auto IntType = Type::getInt32Ty(C);
176   auto PtrType = Type::getInt32PtrTy(C);
177   auto *Value = ConstantInt::get(IntType, 42);
178   auto *Addr = ConstantPointerNull::get(PtrType);
179
180   auto *Store1 = new StoreInst(Value, Addr, BB);
181   auto *Load1 = new LoadInst(Addr, "load", BB);
182   auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB);
183   auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB);
184   auto *CmpXChg1 = new AtomicCmpXchgInst(Addr, ConstantInt::get(IntType, 0),
185                                          ConstantInt::get(IntType, 1),
186                                          Monotonic, Monotonic, CrossThread, BB);
187   auto *AtomicRMW =
188       new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1),
189                         Monotonic, CrossThread, BB);
190
191   ReturnInst::Create(C, nullptr, BB);
192
193   auto &AA = getAAResults(*F);
194
195   // Check basic results
196   EXPECT_EQ(AA.getModRefInfo(Store1, MemoryLocation()), MRI_Mod);
197   EXPECT_EQ(AA.getModRefInfo(Store1), MRI_Mod);
198   EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), MRI_Ref);
199   EXPECT_EQ(AA.getModRefInfo(Load1), MRI_Ref);
200   EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), MRI_NoModRef);
201   EXPECT_EQ(AA.getModRefInfo(Add1), MRI_NoModRef);
202   EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), MRI_ModRef);
203   EXPECT_EQ(AA.getModRefInfo(VAArg1), MRI_ModRef);
204   EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), MRI_ModRef);
205   EXPECT_EQ(AA.getModRefInfo(CmpXChg1), MRI_ModRef);
206   EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), MRI_ModRef);
207   EXPECT_EQ(AA.getModRefInfo(AtomicRMW), MRI_ModRef);
208 }
209
210 class AAPassInfraTest : public testing::Test {
211 protected:
212   LLVMContext &C;
213   SMDiagnostic Err;
214   std::unique_ptr<Module> M;
215
216 public:
217   AAPassInfraTest()
218       : C(getGlobalContext()),
219         M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n"
220                               "entry:\n"
221                               "  %lx = load i32, i32* %x\n"
222                               "  %ly = load i32, i32* %y\n"
223                               "  %sum = add i32 %lx, %ly\n"
224                               "  ret i32 %sum\n"
225                               "}\n",
226                               Err, C)) {
227     assert(M && "Failed to build the module!");
228   }
229 };
230
231 TEST_F(AAPassInfraTest, injectExternalAA) {
232   legacy::PassManager PM;
233
234   // Register our custom AA's wrapper pass manually.
235   bool IsCustomAAQueried = false;
236   PM.add(new TestCustomAAWrapperPass([&] { IsCustomAAQueried = true; }));
237
238   // Now add the external AA wrapper with a lambda which queries for the
239   // wrapper around our custom AA and adds it to the results.
240   PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) {
241     if (auto *WrapperPass = P.getAnalysisIfAvailable<TestCustomAAWrapperPass>())
242       AAR.addAAResult(WrapperPass->getResult());
243   }));
244
245   // And run a pass that will make some alias queries. This will automatically
246   // trigger the rest of the alias analysis stack to be run. It is analagous to
247   // building a full pass pipeline with any of the existing pass manager
248   // builders.
249   PM.add(new AATestPass());
250   PM.run(*M);
251
252   // Finally, ensure that our custom AA was indeed queried.
253   EXPECT_TRUE(IsCustomAAQueried);
254 }
255
256 } // end anonymous namspace