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