From 1571dfc8833299f060ecba12906960bc2bf1c963 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 10 Nov 2010 01:02:18 +0000 Subject: [PATCH] Make ModRefBehavior a lattice. Use this to clean up AliasAnalysis chaining and simplify FunctionAttrs' GetModRefBehavior logic. llvm-svn: 118660 --- include/llvm/Analysis/AliasAnalysis.h | 18 ++--- lib/Analysis/AliasAnalysis.cpp | 2 +- lib/Analysis/BasicAliasAnalysis.cpp | 14 ++-- lib/Analysis/IPA/GlobalsModRef.cpp | 29 ++++--- lib/Analysis/TypeBasedAliasAnalysis.cpp | 3 +- lib/Transforms/IPO/FunctionAttrs.cpp | 75 ++++++++----------- .../FunctionAttrs/2008-09-03-ReadNone.ll | 2 +- .../FunctionAttrs/2008-09-03-ReadOnly.ll | 2 +- 8 files changed, 71 insertions(+), 74 deletions(-) diff --git a/include/llvm/Analysis/AliasAnalysis.h b/include/llvm/Analysis/AliasAnalysis.h index 841513b7158..6b716ddee94 100644 --- a/include/llvm/Analysis/AliasAnalysis.h +++ b/include/llvm/Analysis/AliasAnalysis.h @@ -175,6 +175,9 @@ public: /// enum ModRefResult { NoModRef = 0, Ref = 1, Mod = 2, ModRef = 3 }; + /// These values define additional bits used to define the + /// ModRefBehavior values. + enum { Nowhere = 0, ArgumentPointees = 4, Anywhere = 8 | ArgumentPointees }; /// ModRefBehavior - Summary of how a function affects memory in the program. /// Loads from constant globals are not considered memory accesses for this @@ -187,20 +190,20 @@ public: /// This property corresponds to the GCC 'const' attribute. /// This property corresponds to the LLVM IR 'readnone' attribute. /// This property corresponds to the IntrNoMem LLVM intrinsic flag. - DoesNotAccessMemory, + DoesNotAccessMemory = Nowhere | NoModRef, /// AccessesArgumentsReadonly - This function loads through function /// arguments and does not perform any non-local stores or volatile /// loads. /// /// This property corresponds to the IntrReadArgMem LLVM intrinsic flag. - AccessesArgumentsReadonly, + AccessesArgumentsReadonly = ArgumentPointees | Ref, /// AccessesArguments - This function accesses function arguments in well /// known (possibly volatile) ways, but does not access any other memory. /// /// This property corresponds to the IntrReadWriteArgMem LLVM intrinsic flag. - AccessesArguments, + AccessesArguments = ArgumentPointees | ModRef, /// OnlyReadsMemory - This function does not perform any non-local stores or /// volatile loads, but may read from any memory location. @@ -208,11 +211,11 @@ public: /// This property corresponds to the GCC 'pure' attribute. /// This property corresponds to the LLVM IR 'readonly' attribute. /// This property corresponds to the IntrReadMem LLVM intrinsic flag. - OnlyReadsMemory, + OnlyReadsMemory = Anywhere | Ref, /// UnknownModRefBehavior - This indicates that the function could not be /// classified into one of the behaviors above. - UnknownModRefBehavior + UnknownModRefBehavior = Anywhere | ModRef }; /// getModRefBehavior - Return the behavior when calling the given call site. @@ -270,12 +273,9 @@ public: /// true. For use when the call site is not known. /// static bool onlyReadsMemory(ModRefBehavior MRB) { - return MRB == DoesNotAccessMemory || - MRB == AccessesArgumentsReadonly || - MRB == OnlyReadsMemory; + return !(MRB & Mod); } - /// getModRefInfo - Return information about whether or not an instruction may /// read or write the specified memory location. An instruction /// that doesn't read or write memory may be trivially LICM'd for example. diff --git a/lib/Analysis/AliasAnalysis.cpp b/lib/Analysis/AliasAnalysis.cpp index 7f9c9c169e0..363da9fcee6 100644 --- a/lib/Analysis/AliasAnalysis.cpp +++ b/lib/Analysis/AliasAnalysis.cpp @@ -179,7 +179,7 @@ AliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { // Otherwise, fall back to the next AA in the chain. But we can merge // in any result we've managed to compute. - return std::min(AA->getModRefBehavior(CS), Min); + return ModRefBehavior(AA->getModRefBehavior(CS) & Min); } AliasAnalysis::ModRefBehavior diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index 73114fe5aab..bf1b689587c 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -595,7 +595,7 @@ BasicAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { Min = OnlyReadsMemory; // The AliasAnalysis base class has some smarts, lets use them. - return std::min(AliasAnalysis::getModRefBehavior(CS), Min); + return ModRefBehavior(AliasAnalysis::getModRefBehavior(CS) & Min); } /// getModRefBehavior - Return the behavior when calling the given function. @@ -613,12 +613,14 @@ BasicAliasAnalysis::getModRefBehavior(const Function *F) { #undef GET_INTRINSIC_MODREF_BEHAVIOR } + ModRefBehavior Min = UnknownModRefBehavior; + // If the function declares it only reads memory, go with that. if (F->onlyReadsMemory()) - return OnlyReadsMemory; + Min = OnlyReadsMemory; // Otherwise be conservative. - return AliasAnalysis::getModRefBehavior(F); + return ModRefBehavior(AliasAnalysis::getModRefBehavior(F) & Min); } /// getModRefInfo - Check to see if the specified callsite can clobber the @@ -671,6 +673,8 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, return NoModRef; } + ModRefResult Min = ModRef; + // Finally, handle specific knowledge of intrinsics. const IntrinsicInst *II = dyn_cast(CS.getInstruction()); if (II != 0) @@ -686,7 +690,7 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, if (isNoAlias(Location(Dest, Len), Loc)) { if (isNoAlias(Location(Src, Len), Loc)) return NoModRef; - return Ref; + Min = Ref; } break; } @@ -745,7 +749,7 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, } // The AliasAnalysis base class has some smarts, lets use them. - return AliasAnalysis::getModRefInfo(CS, Loc); + return ModRefResult(AliasAnalysis::getModRefInfo(CS, Loc) & Min); } /// aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index 6e4fff7b529..456a80a972b 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -120,28 +120,33 @@ namespace { /// called from the specified call site. The call site may be null in which /// case the most generic behavior of this function should be returned. ModRefBehavior getModRefBehavior(const Function *F) { + ModRefBehavior Min = UnknownModRefBehavior; + if (FunctionRecord *FR = getFunctionInfo(F)) { if (FR->FunctionEffect == 0) - return DoesNotAccessMemory; + Min = DoesNotAccessMemory; else if ((FR->FunctionEffect & Mod) == 0) - return OnlyReadsMemory; + Min = OnlyReadsMemory; } - return AliasAnalysis::getModRefBehavior(F); + + return ModRefBehavior(AliasAnalysis::getModRefBehavior(F) & Min); } /// getModRefBehavior - Return the behavior of the specified function if /// called from the specified call site. The call site may be null in which /// case the most generic behavior of this function should be returned. ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { - const Function* F = CS.getCalledFunction(); - if (!F) return AliasAnalysis::getModRefBehavior(CS); - if (FunctionRecord *FR = getFunctionInfo(F)) { - if (FR->FunctionEffect == 0) - return DoesNotAccessMemory; - else if ((FR->FunctionEffect & Mod) == 0) - return OnlyReadsMemory; - } - return AliasAnalysis::getModRefBehavior(CS); + ModRefBehavior Min = UnknownModRefBehavior; + + if (const Function* F = CS.getCalledFunction()) + if (FunctionRecord *FR = getFunctionInfo(F)) { + if (FR->FunctionEffect == 0) + Min = DoesNotAccessMemory; + else if ((FR->FunctionEffect & Mod) == 0) + Min = OnlyReadsMemory; + } + + return ModRefBehavior(AliasAnalysis::getModRefBehavior(CS) & Min); } virtual void deleteValue(Value *V); diff --git a/lib/Analysis/TypeBasedAliasAnalysis.cpp b/lib/Analysis/TypeBasedAliasAnalysis.cpp index 16ff64e4cfb..46c9aa95a9b 100644 --- a/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -256,11 +256,12 @@ TypeBasedAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { if (TBAANode(M).TypeIsImmutable()) Min = OnlyReadsMemory; - return std::min(AliasAnalysis::getModRefBehavior(CS), Min); + return ModRefBehavior(AliasAnalysis::getModRefBehavior(CS) & Min); } AliasAnalysis::ModRefBehavior TypeBasedAliasAnalysis::getModRefBehavior(const Function *F) { + // Functions don't have metadata. Just chain to the next implementation. return AliasAnalysis::getModRefBehavior(F); } diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 8bdf5d75dad..3b1b13d378f 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -128,54 +128,41 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { // Ignore calls to functions in the same SCC. if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction())) continue; - switch (AA->getModRefBehavior(CS)) { - case AliasAnalysis::DoesNotAccessMemory: - // Ignore calls that don't access memory. - continue; - case AliasAnalysis::OnlyReadsMemory: - // Handle calls that only read from memory. - ReadsMemory = true; - continue; - case AliasAnalysis::AccessesArguments: - // Check whether all pointer arguments point to local memory, and - // ignore calls that only access local memory. - for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); - CI != CE; ++CI) { - Value *Arg = *CI; - if (Arg->getType()->isPointerTy()) { - AliasAnalysis::Location Loc(Arg, - AliasAnalysis::UnknownSize, - I->getMetadata(LLVMContext::MD_tbaa)); - if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) - // Writes memory. Just give up. - return false; - } - } - // Only reads and writes local memory. - continue; - case AliasAnalysis::AccessesArgumentsReadonly: - // Check whether all pointer arguments point to local memory, and - // ignore calls that only access local memory. - for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); - CI != CE; ++CI) { - Value *Arg = *CI; - if (Arg->getType()->isPointerTy()) { - AliasAnalysis::Location Loc(Arg, - AliasAnalysis::UnknownSize, - I->getMetadata(LLVMContext::MD_tbaa)); - if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) { - // Reads non-local memory. - ReadsMemory = true; - break; + AliasAnalysis::ModRefBehavior MRB = AA->getModRefBehavior(CS); + // If the call doesn't access arbitrary memory, we may be able to + // figure out something. + if (!(MRB & AliasAnalysis::Anywhere & + ~AliasAnalysis::ArgumentPointees)) { + // If the call accesses argument pointees, check each argument. + if (MRB & AliasAnalysis::AccessesArguments) + // Check whether all pointer arguments point to local memory, and + // ignore calls that only access local memory. + for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); + CI != CE; ++CI) { + Value *Arg = *CI; + if (Arg->getType()->isPointerTy()) { + AliasAnalysis::Location Loc(Arg, + AliasAnalysis::UnknownSize, + I->getMetadata(LLVMContext::MD_tbaa)); + if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) { + if (MRB & AliasAnalysis::Mod) + // Writes non-local memory. Give up. + return false; + if (MRB & AliasAnalysis::Ref) + // Ok, it reads non-local memory. + ReadsMemory = true; + } } } - } - // Only reads memory. continue; - default: - // Otherwise, be conservative. - break; } + // The call could access any memory. If that includes writes, give up. + if (MRB & AliasAnalysis::Mod) + return false; + // If it reads, note it. + if (MRB & AliasAnalysis::Ref) + ReadsMemory = true; + continue; } else if (LoadInst *LI = dyn_cast(I)) { // Ignore non-volatile loads from local memory. if (!LI->isVolatile()) { diff --git a/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll b/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll index 535a1d0fba6..946453f586e 100644 --- a/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll +++ b/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -functionattrs -S | grep readnone | count 4 +; RUN: opt < %s -basicaa -functionattrs -S | grep readnone | count 4 @x = global i32 0 declare i32 @e() readnone diff --git a/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll b/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll index b455fdd8c3e..22eca132041 100644 --- a/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll +++ b/test/Transforms/FunctionAttrs/2008-09-03-ReadOnly.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -functionattrs -S | grep readonly | count 2 +; RUN: opt < %s -basicaa -functionattrs -S | grep readonly | count 2 define i32 @f() { entry: