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(std::function<void()> CB) 84 : AAResultBase(), CB(std::move(CB)) {} 85 TestCustomAAResult(TestCustomAAResult &&Arg) 86 : AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {} 87 88 bool invalidate(Function &, const PreservedAnalyses &) { return false; } 89 90 AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { 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 107 explicit TestCustomAAWrapperPass( 108 std::function<void()> CB = std::function<void()>()) 109 : ImmutablePass(ID), CB(std::move(CB)) { 110 initializeTestCustomAAWrapperPassPass(*PassRegistry::getPassRegistry()); 111 } 112 113 void getAnalysisUsage(AnalysisUsage &AU) const override { 114 AU.setPreservesAll(); 115 AU.addRequired<TargetLibraryInfoWrapperPass>(); 116 } 117 118 bool doInitialization(Module &M) override { 119 Result.reset(new TestCustomAAResult(std::move(CB))); 120 return true; 121 } 122 123 bool doFinalization(Module &M) override { 124 Result.reset(); 125 return true; 126 } 127 128 TestCustomAAResult &getResult() { return *Result; } 129 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 152 AliasAnalysisTest() : M("AliasAnalysisTest", C), TLI(TLII) {} 153 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(), TLI, *AC)); 161 AAR->addAAResult(*BAR); 162 163 return *AAR; 164 } 165 }; 166 167 TEST_F(AliasAnalysisTest, getModRefInfo) { 168 // Setup function. 169 FunctionType *FTy = 170 FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false); 171 auto *F = cast<Function>(M.getOrInsertFunction("f", FTy)); 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 178 auto *Store1 = new StoreInst(Value, Addr, BB); 179 auto *Load1 = new LoadInst(Addr, "load", BB); 180 auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB); 181 auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB); 182 auto *CmpXChg1 = new AtomicCmpXchgInst( 183 Addr, ConstantInt::get(IntType, 0), ConstantInt::get(IntType, 1), 184 AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, CrossThread, BB); 185 auto *AtomicRMW = 186 new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), 187 AtomicOrdering::Monotonic, CrossThread, BB); 188 189 ReturnInst::Create(C, nullptr, BB); 190 191 auto &AA = getAAResults(*F); 192 193 // Check basic results 194 EXPECT_EQ(AA.getModRefInfo(Store1, MemoryLocation()), MRI_Mod); 195 EXPECT_EQ(AA.getModRefInfo(Store1), MRI_Mod); 196 EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), MRI_Ref); 197 EXPECT_EQ(AA.getModRefInfo(Load1), MRI_Ref); 198 EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), MRI_NoModRef); 199 EXPECT_EQ(AA.getModRefInfo(Add1), MRI_NoModRef); 200 EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), MRI_ModRef); 201 EXPECT_EQ(AA.getModRefInfo(VAArg1), MRI_ModRef); 202 EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), MRI_ModRef); 203 EXPECT_EQ(AA.getModRefInfo(CmpXChg1), MRI_ModRef); 204 EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), MRI_ModRef); 205 EXPECT_EQ(AA.getModRefInfo(AtomicRMW), MRI_ModRef); 206 } 207 208 class AAPassInfraTest : public testing::Test { 209 protected: 210 LLVMContext &C; 211 SMDiagnostic Err; 212 std::unique_ptr<Module> M; 213 214 public: 215 AAPassInfraTest() 216 : C(getGlobalContext()), 217 M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n" 218 "entry:\n" 219 " %lx = load i32, i32* %x\n" 220 " %ly = load i32, i32* %y\n" 221 " %sum = add i32 %lx, %ly\n" 222 " ret i32 %sum\n" 223 "}\n", 224 Err, C)) { 225 assert(M && "Failed to build the module!"); 226 } 227 }; 228 229 TEST_F(AAPassInfraTest, injectExternalAA) { 230 legacy::PassManager PM; 231 232 // Register our custom AA's wrapper pass manually. 233 bool IsCustomAAQueried = false; 234 PM.add(new TestCustomAAWrapperPass([&] { IsCustomAAQueried = true; })); 235 236 // Now add the external AA wrapper with a lambda which queries for the 237 // wrapper around our custom AA and adds it to the results. 238 PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) { 239 if (auto *WrapperPass = P.getAnalysisIfAvailable<TestCustomAAWrapperPass>()) 240 AAR.addAAResult(WrapperPass->getResult()); 241 })); 242 243 // And run a pass that will make some alias queries. This will automatically 244 // trigger the rest of the alias analysis stack to be run. It is analagous to 245 // building a full pass pipeline with any of the existing pass manager 246 // builders. 247 PM.add(new AATestPass()); 248 PM.run(*M); 249 250 // Finally, ensure that our custom AA was indeed queried. 251 EXPECT_TRUE(IsCustomAAQueried); 252 } 253 254 } // end anonymous namspace 255