253 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- AliasAnalysisTest.cpp - Mixed TBAA unit tests --------------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/Analysis/AliasAnalysis.h"
 | 
						|
#include "llvm/ADT/SetVector.h"
 | 
						|
#include "llvm/Analysis/AssumptionCache.h"
 | 
						|
#include "llvm/Analysis/BasicAliasAnalysis.h"
 | 
						|
#include "llvm/Analysis/TargetLibraryInfo.h"
 | 
						|
#include "llvm/AsmParser/Parser.h"
 | 
						|
#include "llvm/IR/Constants.h"
 | 
						|
#include "llvm/IR/InstIterator.h"
 | 
						|
#include "llvm/IR/Instructions.h"
 | 
						|
#include "llvm/IR/LLVMContext.h"
 | 
						|
#include "llvm/IR/LegacyPassManager.h"
 | 
						|
#include "llvm/IR/Module.h"
 | 
						|
#include "llvm/Support/SourceMgr.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
// Set up some test passes.
 | 
						|
namespace llvm {
 | 
						|
void initializeAATestPassPass(PassRegistry&);
 | 
						|
void initializeTestCustomAAWrapperPassPass(PassRegistry&);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
struct AATestPass : FunctionPass {
 | 
						|
  static char ID;
 | 
						|
  AATestPass() : FunctionPass(ID) {
 | 
						|
    initializeAATestPassPass(*PassRegistry::getPassRegistry());
 | 
						|
  }
 | 
						|
 | 
						|
  void getAnalysisUsage(AnalysisUsage &AU) const override {
 | 
						|
    AU.addRequired<AAResultsWrapperPass>();
 | 
						|
    AU.setPreservesAll();
 | 
						|
  }
 | 
						|
 | 
						|
  bool runOnFunction(Function &F) override {
 | 
						|
    AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
 | 
						|
 | 
						|
    SetVector<Value *> Pointers;
 | 
						|
    for (Argument &A : F.args())
 | 
						|
      if (A.getType()->isPointerTy())
 | 
						|
        Pointers.insert(&A);
 | 
						|
    for (Instruction &I : instructions(F))
 | 
						|
      if (I.getType()->isPointerTy())
 | 
						|
        Pointers.insert(&I);
 | 
						|
 | 
						|
    for (Value *P1 : Pointers)
 | 
						|
      for (Value *P2 : Pointers)
 | 
						|
        (void)AA.alias(P1, MemoryLocation::UnknownSize, P2,
 | 
						|
                       MemoryLocation::UnknownSize);
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
};
 | 
						|
}
 | 
						|
 | 
						|
char AATestPass::ID = 0;
 | 
						|
INITIALIZE_PASS_BEGIN(AATestPass, "aa-test-pas", "Alias Analysis Test Pass",
 | 
						|
                      false, true)
 | 
						|
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
 | 
						|
INITIALIZE_PASS_END(AATestPass, "aa-test-pass", "Alias Analysis Test Pass",
 | 
						|
                    false, true)
 | 
						|
 | 
						|
namespace {
 | 
						|
/// A test customizable AA result. It merely accepts a callback to run whenever
 | 
						|
/// it receives an alias query. Useful for testing that a particular AA result
 | 
						|
/// is reached.
 | 
						|
struct TestCustomAAResult : AAResultBase<TestCustomAAResult> {
 | 
						|
  friend AAResultBase<TestCustomAAResult>;
 | 
						|
 | 
						|
  std::function<void()> CB;
 | 
						|
 | 
						|
  explicit TestCustomAAResult(std::function<void()> CB)
 | 
						|
      : AAResultBase(), CB(std::move(CB)) {}
 | 
						|
  TestCustomAAResult(TestCustomAAResult &&Arg)
 | 
						|
      : AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {}
 | 
						|
 | 
						|
  bool invalidate(Function &, const PreservedAnalyses &) { return false; }
 | 
						|
 | 
						|
  AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
 | 
						|
    CB();
 | 
						|
    return MayAlias;
 | 
						|
  }
 | 
						|
};
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
/// A wrapper pass for the legacy pass manager to use with the above custom AA
 | 
						|
/// result.
 | 
						|
class TestCustomAAWrapperPass : public ImmutablePass {
 | 
						|
  std::function<void()> CB;
 | 
						|
  std::unique_ptr<TestCustomAAResult> Result;
 | 
						|
 | 
						|
public:
 | 
						|
  static char ID;
 | 
						|
 | 
						|
  explicit TestCustomAAWrapperPass(
 | 
						|
      std::function<void()> CB = std::function<void()>())
 | 
						|
      : ImmutablePass(ID), CB(std::move(CB)) {
 | 
						|
    initializeTestCustomAAWrapperPassPass(*PassRegistry::getPassRegistry());
 | 
						|
  }
 | 
						|
 | 
						|
  void getAnalysisUsage(AnalysisUsage &AU) const override {
 | 
						|
    AU.setPreservesAll();
 | 
						|
    AU.addRequired<TargetLibraryInfoWrapperPass>();
 | 
						|
  }
 | 
						|
 | 
						|
  bool doInitialization(Module &M) override {
 | 
						|
    Result.reset(new TestCustomAAResult(std::move(CB)));
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  bool doFinalization(Module &M) override {
 | 
						|
    Result.reset();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  TestCustomAAResult &getResult() { return *Result; }
 | 
						|
  const TestCustomAAResult &getResult() const { return *Result; }
 | 
						|
};
 | 
						|
}
 | 
						|
 | 
						|
char TestCustomAAWrapperPass::ID = 0;
 | 
						|
INITIALIZE_PASS_BEGIN(TestCustomAAWrapperPass, "test-custom-aa",
 | 
						|
                "Test Custom AA Wrapper Pass", false, true)
 | 
						|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
 | 
						|
INITIALIZE_PASS_END(TestCustomAAWrapperPass, "test-custom-aa",
 | 
						|
                "Test Custom AA Wrapper Pass", false, true)
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
class AliasAnalysisTest : public testing::Test {
 | 
						|
protected:
 | 
						|
  LLVMContext C;
 | 
						|
  Module M;
 | 
						|
  TargetLibraryInfoImpl TLII;
 | 
						|
  TargetLibraryInfo TLI;
 | 
						|
  std::unique_ptr<AssumptionCache> AC;
 | 
						|
  std::unique_ptr<BasicAAResult> BAR;
 | 
						|
  std::unique_ptr<AAResults> AAR;
 | 
						|
 | 
						|
  AliasAnalysisTest() : M("AliasAnalysisTest", C), TLI(TLII) {}
 | 
						|
 | 
						|
  AAResults &getAAResults(Function &F) {
 | 
						|
    // Reset the Function AA results first to clear out any references.
 | 
						|
    AAR.reset(new AAResults(TLI));
 | 
						|
 | 
						|
    // Build the various AA results and register them.
 | 
						|
    AC.reset(new AssumptionCache(F));
 | 
						|
    BAR.reset(new BasicAAResult(M.getDataLayout(), TLI, *AC));
 | 
						|
    AAR->addAAResult(*BAR);
 | 
						|
 | 
						|
    return *AAR;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
TEST_F(AliasAnalysisTest, getModRefInfo) {
 | 
						|
  // Setup function.
 | 
						|
  FunctionType *FTy =
 | 
						|
      FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false);
 | 
						|
  auto *F = cast<Function>(M.getOrInsertFunction("f", FTy));
 | 
						|
  auto *BB = BasicBlock::Create(C, "entry", F);
 | 
						|
  auto IntType = Type::getInt32Ty(C);
 | 
						|
  auto PtrType = Type::getInt32PtrTy(C);
 | 
						|
  auto *Value = ConstantInt::get(IntType, 42);
 | 
						|
  auto *Addr = ConstantPointerNull::get(PtrType);
 | 
						|
 | 
						|
  auto *Store1 = new StoreInst(Value, Addr, BB);
 | 
						|
  auto *Load1 = new LoadInst(Addr, "load", BB);
 | 
						|
  auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB);
 | 
						|
  auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB);
 | 
						|
  auto *CmpXChg1 = new AtomicCmpXchgInst(
 | 
						|
      Addr, ConstantInt::get(IntType, 0), ConstantInt::get(IntType, 1),
 | 
						|
      AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, CrossThread, BB);
 | 
						|
  auto *AtomicRMW =
 | 
						|
      new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1),
 | 
						|
                        AtomicOrdering::Monotonic, CrossThread, BB);
 | 
						|
 | 
						|
  ReturnInst::Create(C, nullptr, BB);
 | 
						|
 | 
						|
  auto &AA = getAAResults(*F);
 | 
						|
 | 
						|
  // Check basic results
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(Store1, MemoryLocation()), MRI_Mod);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(Store1), MRI_Mod);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), MRI_Ref);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(Load1), MRI_Ref);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), MRI_NoModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(Add1), MRI_NoModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), MRI_ModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(VAArg1), MRI_ModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), MRI_ModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(CmpXChg1), MRI_ModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), MRI_ModRef);
 | 
						|
  EXPECT_EQ(AA.getModRefInfo(AtomicRMW), MRI_ModRef);
 | 
						|
}
 | 
						|
 | 
						|
class AAPassInfraTest : public testing::Test {
 | 
						|
protected:
 | 
						|
  LLVMContext C;
 | 
						|
  SMDiagnostic Err;
 | 
						|
  std::unique_ptr<Module> M;
 | 
						|
 | 
						|
public:
 | 
						|
  AAPassInfraTest()
 | 
						|
      : M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n"
 | 
						|
                              "entry:\n"
 | 
						|
                              "  %lx = load i32, i32* %x\n"
 | 
						|
                              "  %ly = load i32, i32* %y\n"
 | 
						|
                              "  %sum = add i32 %lx, %ly\n"
 | 
						|
                              "  ret i32 %sum\n"
 | 
						|
                              "}\n",
 | 
						|
                              Err, C)) {
 | 
						|
    assert(M && "Failed to build the module!");
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
TEST_F(AAPassInfraTest, injectExternalAA) {
 | 
						|
  legacy::PassManager PM;
 | 
						|
 | 
						|
  // Register our custom AA's wrapper pass manually.
 | 
						|
  bool IsCustomAAQueried = false;
 | 
						|
  PM.add(new TestCustomAAWrapperPass([&] { IsCustomAAQueried = true; }));
 | 
						|
 | 
						|
  // Now add the external AA wrapper with a lambda which queries for the
 | 
						|
  // wrapper around our custom AA and adds it to the results.
 | 
						|
  PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) {
 | 
						|
    if (auto *WrapperPass = P.getAnalysisIfAvailable<TestCustomAAWrapperPass>())
 | 
						|
      AAR.addAAResult(WrapperPass->getResult());
 | 
						|
  }));
 | 
						|
 | 
						|
  // And run a pass that will make some alias queries. This will automatically
 | 
						|
  // trigger the rest of the alias analysis stack to be run. It is analagous to
 | 
						|
  // building a full pass pipeline with any of the existing pass manager
 | 
						|
  // builders.
 | 
						|
  PM.add(new AATestPass());
 | 
						|
  PM.run(*M);
 | 
						|
 | 
						|
  // Finally, ensure that our custom AA was indeed queried.
 | 
						|
  EXPECT_TRUE(IsCustomAAQueried);
 | 
						|
}
 | 
						|
 | 
						|
} // end anonymous namspace
 |