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/InstIterator.h" 18 #include "llvm/IR/Instructions.h" 19 #include "llvm/IR/LLVMContext.h" 20 #include "llvm/IR/LegacyPassManager.h" 21 #include "llvm/IR/Module.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; 36 AATestPass() : FunctionPass(ID) { 37 initializeAATestPassPass(*PassRegistry::getPassRegistry()); 38 } 39 40 void getAnalysisUsage(AnalysisUsage &AU) const override { 41 AU.addRequired<AAResultsWrapperPass>(); 42 AU.setPreservesAll(); 43 } 44 45 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, MemoryLocation::UnknownSize, P2, 59 MemoryLocation::UnknownSize); 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 82 explicit TestCustomAAResult(std::function<void()> CB) 83 : AAResultBase(), CB(std::move(CB)) {} 84 TestCustomAAResult(TestCustomAAResult &&Arg) 85 : AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {} 86 87 bool invalidate(Function &, const PreservedAnalyses &) { return false; } 88 89 AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { 90 CB(); 91 return MayAlias; 92 } 93 }; 94 } 95 96 namespace { 97 /// A wrapper pass for the legacy pass manager to use with the above custom AA 98 /// result. 99 class TestCustomAAWrapperPass : public ImmutablePass { 100 std::function<void()> CB; 101 std::unique_ptr<TestCustomAAResult> Result; 102 103 public: 104 static char ID; 105 106 explicit TestCustomAAWrapperPass( 107 std::function<void()> CB = std::function<void()>()) 108 : ImmutablePass(ID), CB(std::move(CB)) { 109 initializeTestCustomAAWrapperPassPass(*PassRegistry::getPassRegistry()); 110 } 111 112 void getAnalysisUsage(AnalysisUsage &AU) const override { 113 AU.setPreservesAll(); 114 AU.addRequired<TargetLibraryInfoWrapperPass>(); 115 } 116 117 bool doInitialization(Module &M) override { 118 Result.reset(new TestCustomAAResult(std::move(CB))); 119 return true; 120 } 121 122 bool doFinalization(Module &M) override { 123 Result.reset(); 124 return true; 125 } 126 127 TestCustomAAResult &getResult() { return *Result; } 128 const TestCustomAAResult &getResult() const { return *Result; } 129 }; 130 } 131 132 char TestCustomAAWrapperPass::ID = 0; 133 INITIALIZE_PASS_BEGIN(TestCustomAAWrapperPass, "test-custom-aa", 134 "Test Custom AA Wrapper Pass", false, true) 135 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 136 INITIALIZE_PASS_END(TestCustomAAWrapperPass, "test-custom-aa", 137 "Test Custom AA Wrapper Pass", false, true) 138 139 namespace { 140 141 class AliasAnalysisTest : public testing::Test { 142 protected: 143 LLVMContext C; 144 Module M; 145 TargetLibraryInfoImpl TLII; 146 TargetLibraryInfo TLI; 147 std::unique_ptr<AssumptionCache> AC; 148 std::unique_ptr<BasicAAResult> BAR; 149 std::unique_ptr<AAResults> AAR; 150 151 AliasAnalysisTest() : M("AliasAnalysisTest", C), TLI(TLII) {} 152 153 AAResults &getAAResults(Function &F) { 154 // Reset the Function AA results first to clear out any references. 155 AAR.reset(new AAResults(TLI)); 156 157 // Build the various AA results and register them. 158 AC.reset(new AssumptionCache(F)); 159 BAR.reset(new BasicAAResult(M.getDataLayout(), TLI, *AC)); 160 AAR->addAAResult(*BAR); 161 162 return *AAR; 163 } 164 }; 165 166 TEST_F(AliasAnalysisTest, getModRefInfo) { 167 // Setup function. 168 FunctionType *FTy = 169 FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false); 170 auto *F = cast<Function>(M.getOrInsertFunction("f", FTy)); 171 auto *BB = BasicBlock::Create(C, "entry", F); 172 auto IntType = Type::getInt32Ty(C); 173 auto PtrType = Type::getInt32PtrTy(C); 174 auto *Value = ConstantInt::get(IntType, 42); 175 auto *Addr = ConstantPointerNull::get(PtrType); 176 177 auto *Store1 = new StoreInst(Value, Addr, BB); 178 auto *Load1 = new LoadInst(Addr, "load", BB); 179 auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB); 180 auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB); 181 auto *CmpXChg1 = new AtomicCmpXchgInst( 182 Addr, ConstantInt::get(IntType, 0), ConstantInt::get(IntType, 1), 183 AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, CrossThread, BB); 184 auto *AtomicRMW = 185 new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), 186 AtomicOrdering::Monotonic, CrossThread, 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()), MRI_Mod); 194 EXPECT_EQ(AA.getModRefInfo(Store1), MRI_Mod); 195 EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), MRI_Ref); 196 EXPECT_EQ(AA.getModRefInfo(Load1), MRI_Ref); 197 EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), MRI_NoModRef); 198 EXPECT_EQ(AA.getModRefInfo(Add1), MRI_NoModRef); 199 EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), MRI_ModRef); 200 EXPECT_EQ(AA.getModRefInfo(VAArg1), MRI_ModRef); 201 EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), MRI_ModRef); 202 EXPECT_EQ(AA.getModRefInfo(CmpXChg1), MRI_ModRef); 203 EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), MRI_ModRef); 204 EXPECT_EQ(AA.getModRefInfo(AtomicRMW), MRI_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