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