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