brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.8 KiB · a28d318 Raw
429 lines · cpp
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-exception6//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 25using namespace llvm;26 27// Set up some test passes.28namespace llvm {29void initializeAATestPassPass(PassRegistry&);30void initializeTestCustomAAWrapperPassPass(PassRegistry&);31}32 33namespace {34struct 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, LocationSize::beforeOrAfterPointer(), P2,59                       LocationSize::beforeOrAfterPointer());60 61    return false;62  }63};64}65 66char AATestPass::ID = 0;67INITIALIZE_PASS_BEGIN(AATestPass, "aa-test-pas", "Alias Analysis Test Pass",68                      false, true)69INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)70INITIALIZE_PASS_END(AATestPass, "aa-test-pass", "Alias Analysis Test Pass",71                    false, true)72 73namespace {74/// A test customizable AA result. It merely accepts a callback to run whenever75/// it receives an alias query. Useful for testing that a particular AA result76/// is reached.77struct TestCustomAAResult : AAResultBase {78  std::function<void()> CB;79 80  explicit TestCustomAAResult(std::function<void()> CB)81      : AAResultBase(), CB(std::move(CB)) {}82  TestCustomAAResult(TestCustomAAResult &&Arg)83      : AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {}84 85  bool invalidate(Function &, const PreservedAnalyses &) { return false; }86 87  AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB,88                    AAQueryInfo &AAQI, const Instruction *) {89    CB();90    return AliasResult::MayAlias;91  }92};93}94 95namespace {96/// A wrapper pass for the legacy pass manager to use with the above custom AA97/// result.98class TestCustomAAWrapperPass : public ImmutablePass {99  std::function<void()> CB;100  std::unique_ptr<TestCustomAAResult> Result;101 102public: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 131char TestCustomAAWrapperPass::ID = 0;132INITIALIZE_PASS_BEGIN(TestCustomAAWrapperPass, "test-custom-aa",133                "Test Custom AA Wrapper Pass", false, true)134INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)135INITIALIZE_PASS_END(TestCustomAAWrapperPass, "test-custom-aa",136                "Test Custom AA Wrapper Pass", false, true)137 138namespace {139 140class AliasAnalysisTest : public testing::Test {141protected: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()151      : M("AliasAnalysisTest", C), TLII(M.getTargetTriple()), 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(), F, TLI, *AC));160    AAR->addAAResult(*BAR);161 162    return *AAR;163  }164};165 166TEST_F(AliasAnalysisTest, getModRefInfo) {167  // Setup function.168  FunctionType *FTy =169      FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false);170  auto *F = Function::Create(FTy, Function::ExternalLinkage, "f", M);171  auto *BB = BasicBlock::Create(C, "entry", F);172  auto IntType = Type::getInt32Ty(C);173  auto PtrType = PointerType::get(C, 0);174  auto *Value = ConstantInt::get(IntType, 42);175  auto *Addr = ConstantPointerNull::get(PtrType);176  auto Alignment = Align(IntType->getBitWidth() / 8);177 178  auto *Store1 = new StoreInst(Value, Addr, BB);179  auto *Load1 = new LoadInst(IntType, 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      Alignment, AtomicOrdering::Monotonic, AtomicOrdering::Monotonic,185      SyncScope::System, BB);186  auto *AtomicRMW = new AtomicRMWInst(187      AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), Alignment,188      AtomicOrdering::Monotonic, SyncScope::System, BB);189 190  FunctionType *FooBarTy = FunctionType::get(Type::getVoidTy(C), {}, false);191  Function::Create(FooBarTy, Function::ExternalLinkage, "foo", &M);192  auto *BarF = Function::Create(FooBarTy, Function::ExternalLinkage, "bar", &M);193  BarF->setDoesNotAccessMemory();194 195  const Instruction *Foo = CallInst::Create(M.getFunction("foo"), {}, BB);196  const Instruction *Bar = CallInst::Create(M.getFunction("bar"), {}, BB);197 198  ReturnInst::Create(C, nullptr, BB);199 200  auto &AA = getAAResults(*F);201 202  // Check basic results203  EXPECT_EQ(AA.getModRefInfo(Store1, MemoryLocation()), ModRefInfo::Mod);204  EXPECT_EQ(AA.getModRefInfo(Store1, std::nullopt), ModRefInfo::Mod);205  EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), ModRefInfo::Ref);206  EXPECT_EQ(AA.getModRefInfo(Load1, std::nullopt), ModRefInfo::Ref);207  EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), ModRefInfo::NoModRef);208  EXPECT_EQ(AA.getModRefInfo(Add1, std::nullopt), ModRefInfo::NoModRef);209  EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), ModRefInfo::ModRef);210  EXPECT_EQ(AA.getModRefInfo(VAArg1, std::nullopt), ModRefInfo::ModRef);211  EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), ModRefInfo::ModRef);212  EXPECT_EQ(AA.getModRefInfo(CmpXChg1, std::nullopt), ModRefInfo::ModRef);213  EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), ModRefInfo::ModRef);214  EXPECT_EQ(AA.getModRefInfo(AtomicRMW, std::nullopt), ModRefInfo::ModRef);215  EXPECT_EQ(AA.getModRefInfo(Store1, Load1), ModRefInfo::ModRef);216  EXPECT_EQ(AA.getModRefInfo(Store1, Store1), ModRefInfo::ModRef);217  EXPECT_EQ(AA.getModRefInfo(Store1, Add1), ModRefInfo::NoModRef);218  EXPECT_EQ(AA.getModRefInfo(Store1, Foo), ModRefInfo::ModRef);219  EXPECT_EQ(AA.getModRefInfo(Store1, Bar), ModRefInfo::NoModRef);220  EXPECT_EQ(AA.getModRefInfo(Foo, Bar), ModRefInfo::NoModRef);221  EXPECT_EQ(AA.getModRefInfo(Foo, Foo), ModRefInfo::ModRef);222}223 224static Instruction *getInstructionByName(Function &F, StringRef Name) {225  for (auto &I : instructions(F))226    if (I.getName() == Name)227      return &I;228  llvm_unreachable("Expected to find instruction!");229}230 231TEST_F(AliasAnalysisTest, BatchAAPhiCycles) {232  LLVMContext C;233  SMDiagnostic Err;234  std::unique_ptr<Module> M = parseAssemblyString(R"(235    define void @f(ptr noalias %a, i1 %c) {236    entry:237      br label %loop238 239    loop:240      %phi = phi ptr [ null, %entry ], [ %a2, %loop ]241      %offset1 = phi i64 [ 0, %entry ], [ %offset2, %loop]242      %offset2 = add i64 %offset1, 1243      %a1 = getelementptr i8, ptr %a, i64 %offset1244      %a2 = getelementptr i8, ptr %a, i64 %offset2245      %s1 = select i1 %c, ptr %a1, ptr %phi246      %s2 = select i1 %c, ptr %a2, ptr %a1247      br label %loop248    }249  )", Err, C);250 251  Function *F = M->getFunction("f");252  Instruction *Phi = getInstructionByName(*F, "phi");253  Instruction *A1 = getInstructionByName(*F, "a1");254  Instruction *A2 = getInstructionByName(*F, "a2");255  Instruction *S1 = getInstructionByName(*F, "s1");256  Instruction *S2 = getInstructionByName(*F, "s2");257  MemoryLocation PhiLoc(Phi, LocationSize::precise(1));258  MemoryLocation A1Loc(A1, LocationSize::precise(1));259  MemoryLocation A2Loc(A2, LocationSize::precise(1));260  MemoryLocation S1Loc(S1, LocationSize::precise(1));261  MemoryLocation S2Loc(S2, LocationSize::precise(1));262 263  auto &AA = getAAResults(*F);264  EXPECT_EQ(AliasResult::NoAlias, AA.alias(A1Loc, A2Loc));265  EXPECT_EQ(AliasResult::MayAlias, AA.alias(PhiLoc, A1Loc));266  EXPECT_EQ(AliasResult::MayAlias, AA.alias(S1Loc, S2Loc));267 268  BatchAAResults BatchAA(AA);269  EXPECT_EQ(AliasResult::NoAlias, BatchAA.alias(A1Loc, A2Loc));270  EXPECT_EQ(AliasResult::MayAlias, BatchAA.alias(PhiLoc, A1Loc));271  EXPECT_EQ(AliasResult::MayAlias, BatchAA.alias(S1Loc, S2Loc));272 273  BatchAAResults BatchAA2(AA);274  EXPECT_EQ(AliasResult::NoAlias, BatchAA2.alias(A1Loc, A2Loc));275  EXPECT_EQ(AliasResult::MayAlias, BatchAA2.alias(S1Loc, S2Loc));276  EXPECT_EQ(AliasResult::MayAlias, BatchAA2.alias(PhiLoc, A1Loc));277}278 279TEST_F(AliasAnalysisTest, BatchAAPhiAssumption) {280  LLVMContext C;281  SMDiagnostic Err;282  std::unique_ptr<Module> M = parseAssemblyString(R"(283    define void @f(ptr %a.base, ptr %b.base, i1 %c) {284    entry:285      br label %loop286 287    loop:288      %a = phi ptr [ %a.next, %loop ], [ %a.base, %entry ]289      %b = phi ptr [ %b.next, %loop ], [ %b.base, %entry ]290      %a.next = getelementptr i8, ptr %a, i64 1291      %b.next = getelementptr i8, ptr %b, i64 1292      br label %loop293    }294  )", Err, C);295 296  Function *F = M->getFunction("f");297  Instruction *A = getInstructionByName(*F, "a");298  Instruction *B = getInstructionByName(*F, "b");299  Instruction *ANext = getInstructionByName(*F, "a.next");300  Instruction *BNext = getInstructionByName(*F, "b.next");301  MemoryLocation ALoc(A, LocationSize::precise(1));302  MemoryLocation BLoc(B, LocationSize::precise(1));303  MemoryLocation ANextLoc(ANext, LocationSize::precise(1));304  MemoryLocation BNextLoc(BNext, LocationSize::precise(1));305 306  auto &AA = getAAResults(*F);307  EXPECT_EQ(AliasResult::MayAlias, AA.alias(ALoc, BLoc));308  EXPECT_EQ(AliasResult::MayAlias, AA.alias(ANextLoc, BNextLoc));309 310  BatchAAResults BatchAA(AA);311  EXPECT_EQ(AliasResult::MayAlias, BatchAA.alias(ALoc, BLoc));312  EXPECT_EQ(AliasResult::MayAlias, BatchAA.alias(ANextLoc, BNextLoc));313}314 315// Check that two aliased GEPs with non-constant offsets are correctly316// analyzed and their relative offset can be requested from AA.317TEST_F(AliasAnalysisTest, PartialAliasOffset) {318  LLVMContext C;319  SMDiagnostic Err;320  std::unique_ptr<Module> M = parseAssemblyString(R"(321    define void @foo(ptr %arg, i32 %i) {322    bb:323      %i2 = zext i32 %i to i64324      %i3 = getelementptr inbounds float, ptr %arg, i64 %i2325      %i4 = bitcast ptr %i3 to ptr326      %L1 = load <2 x float>, ptr %i4, align 16327      %i7 = add nuw nsw i32 %i, 1328      %i8 = zext i32 %i7 to i64329      %i9 = getelementptr inbounds float, ptr %arg, i64 %i8330      %L2 = load float, ptr %i9, align 4331      ret void332    }333  )",334                                                  Err, C);335 336  if (!M)337    Err.print("PartialAliasOffset", errs());338 339  Function *F = M->getFunction("foo");340  const auto Loc1 = MemoryLocation::get(getInstructionByName(*F, "L1"));341  const auto Loc2 = MemoryLocation::get(getInstructionByName(*F, "L2"));342 343  auto &AA = getAAResults(*F);344 345  const auto AR = AA.alias(Loc1, Loc2);346  EXPECT_EQ(AR, AliasResult::PartialAlias);347  EXPECT_EQ(4, AR.getOffset());348}349 350// Check that swapping the order of parameters to `AA.alias()` changes offset351// sign and that the sign is such that FirstLoc + Offset == SecondLoc.352TEST_F(AliasAnalysisTest, PartialAliasOffsetSign) {353  LLVMContext C;354  SMDiagnostic Err;355  std::unique_ptr<Module> M = parseAssemblyString(R"(356    define void @f(ptr %p) {357      %L1 = load i64, ptr %p358      %p.i8 = bitcast ptr %p to ptr359      %q = getelementptr i8,  ptr %p.i8, i32 1360      %L2 = load i8, ptr %q361      ret void362    }363  )",364                                                  Err, C);365 366  if (!M)367    Err.print("PartialAliasOffsetSign", errs());368 369  Function *F = M->getFunction("f");370  const auto Loc1 = MemoryLocation::get(getInstructionByName(*F, "L1"));371  const auto Loc2 = MemoryLocation::get(getInstructionByName(*F, "L2"));372 373  auto &AA = getAAResults(*F);374 375  auto AR = AA.alias(Loc1, Loc2);376  EXPECT_EQ(AR, AliasResult::PartialAlias);377  EXPECT_EQ(1, AR.getOffset());378 379  AR = AA.alias(Loc2, Loc1);380  EXPECT_EQ(AR, AliasResult::PartialAlias);381  EXPECT_EQ(-1, AR.getOffset());382}383class AAPassInfraTest : public testing::Test {384protected:385  LLVMContext C;386  SMDiagnostic Err;387  std::unique_ptr<Module> M;388 389public:390  AAPassInfraTest()391      : M(parseAssemblyString("define i32 @f(ptr %x, ptr %y) {\n"392                              "entry:\n"393                              "  %lx = load i32, ptr %x\n"394                              "  %ly = load i32, ptr %y\n"395                              "  %sum = add i32 %lx, %ly\n"396                              "  ret i32 %sum\n"397                              "}\n",398                              Err, C)) {399    assert(M && "Failed to build the module!");400  }401};402 403TEST_F(AAPassInfraTest, injectExternalAA) {404  legacy::PassManager PM;405 406  // Register our custom AA's wrapper pass manually.407  bool IsCustomAAQueried = false;408  PM.add(new TestCustomAAWrapperPass([&] { IsCustomAAQueried = true; }));409 410  // Now add the external AA wrapper with a lambda which queries for the411  // wrapper around our custom AA and adds it to the results.412  PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) {413    if (auto *WrapperPass = P.getAnalysisIfAvailable<TestCustomAAWrapperPass>())414      AAR.addAAResult(WrapperPass->getResult());415  }));416 417  // And run a pass that will make some alias queries. This will automatically418  // trigger the rest of the alias analysis stack to be run. It is analagous to419  // building a full pass pipeline with any of the existing pass manager420  // builders.421  PM.add(new AATestPass());422  PM.run(*M);423 424  // Finally, ensure that our custom AA was indeed queried.425  EXPECT_TRUE(IsCustomAAQueried);426}427 428} // end anonymous namspace429