Integrate the readonly/readnone logic more deeply
authorDuncan Sands <baldrick@free.fr>
Sat, 1 Dec 2007 07:51:45 +0000 (07:51 +0000)
committerDuncan Sands <baldrick@free.fr>
Sat, 1 Dec 2007 07:51:45 +0000 (07:51 +0000)
into alias analysis.  This meant updating the API
which now has versions of the getModRefBehavior,
doesNotAccessMemory and onlyReadsMemory methods
which take a callsite parameter.  These should be
used unless the callsite is not known, since in
general they can do a better job than the versions
that take a function.  Also, users should no longer
call the version of getModRefBehavior that takes
both a function and a callsite.  To reduce the
chance of misuse it is now protected.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44487 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/llvm/Analysis/AliasAnalysis.h
lib/Analysis/AliasAnalysis.cpp
lib/Analysis/AliasAnalysisCounter.cpp
lib/Analysis/AliasSetTracker.cpp
lib/Analysis/BasicAliasAnalysis.cpp
lib/Analysis/IPA/GlobalsModRef.cpp
lib/Analysis/LoadValueNumbering.cpp
lib/Analysis/MemoryDependenceAnalysis.cpp
lib/Transforms/Scalar/ADCE.cpp
lib/Transforms/Scalar/DeadStoreElimination.cpp
lib/Transforms/Scalar/GVN.cpp
lib/Transforms/Scalar/LICM.cpp

index 42094167052a613c1b6a949ad89902123bf5e2ea..0aff4f2c9d237848e703f224ab55c6b65d5f140b 100644 (file)
@@ -186,40 +186,57 @@ public:
     };
   };
 
-  /// 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.
-  virtual ModRefBehavior getModRefBehavior(Function *F, CallSite CS,
-                                     std::vector<PointerAccessInfo> *Info = 0);
-
-  /// doesNotAccessMemory - If the specified function is known to never read or
-  /// write memory, return true.  If the function only reads from known-constant
-  /// memory, it is also legal to return true.  Functions that unwind the stack
-  /// are not legal for this predicate.
+  /// getModRefBehavior - Return the behavior when calling the given call site.
+  ModRefBehavior getModRefBehavior(CallSite CS,
+                                   std::vector<PointerAccessInfo> *Info = 0);
+
+  /// getModRefBehavior - Return the behavior when calling the given function.
+  /// For use when the call site is not known.
+  ModRefBehavior getModRefBehavior(Function *F,
+                                   std::vector<PointerAccessInfo> *Info = 0);
+
+  /// doesNotAccessMemory - If the specified call is known to never read or
+  /// write memory, return true.  If the call only reads from known-constant
+  /// memory, it is also legal to return true.  Calls that unwind the stack
+  /// are legal for this predicate.
   ///
-  /// Many optimizations (such as CSE and LICM) can be performed on calls to it,
-  /// without worrying about aliasing properties, and many functions have this
-  /// property (e.g. 'sin' and 'cos').
+  /// Many optimizations (such as CSE and LICM) can be performed on such calls
+  /// without worrying about aliasing properties, and many calls have this
+  /// property (e.g. calls to 'sin' and 'cos').
   ///
   /// This property corresponds to the GCC 'const' attribute.
   ///
+  bool doesNotAccessMemory(CallSite CS) {
+    return getModRefBehavior(CS) == DoesNotAccessMemory;
+  }
+
+  /// doesNotAccessMemory - If the specified function is known to never read or
+  /// write memory, return true.  For use when the call site is not known.
+  ///
   bool doesNotAccessMemory(Function *F) {
-    return getModRefBehavior(F, CallSite()) == DoesNotAccessMemory;
+    return getModRefBehavior(F) == DoesNotAccessMemory;
   }
 
-  /// onlyReadsMemory - If the specified function is known to only read from
-  /// non-volatile memory (or not access memory at all), return true.  Functions
-  /// that unwind the stack are not legal for this predicate.
+  /// onlyReadsMemory - If the specified call is known to only read from
+  /// non-volatile memory (or not access memory at all), return true.  Calls
+  /// that unwind the stack are legal for this predicate.
   ///
   /// This property allows many common optimizations to be performed in the
   /// absence of interfering store instructions, such as CSE of strlen calls.
   ///
   /// This property corresponds to the GCC 'pure' attribute.
   ///
+  bool onlyReadsMemory(CallSite CS) {
+    ModRefBehavior MRB = getModRefBehavior(CS);
+    return MRB == DoesNotAccessMemory || MRB == OnlyReadsMemory;
+  }
+
+  /// onlyReadsMemory - If the specified function is known to only read from
+  /// non-volatile memory (or not access memory at all), return true.  For use
+  /// when the call site is not known.
+  ///
   bool onlyReadsMemory(Function *F) {
-    /// FIXME: If the analysis returns more precise info, we can reduce it to
-    /// this.
-    ModRefBehavior MRB = getModRefBehavior(F, CallSite());
+    ModRefBehavior MRB = getModRefBehavior(F);
     return MRB == DoesNotAccessMemory || MRB == OnlyReadsMemory;
   }
 
@@ -250,6 +267,14 @@ public:
   ///
   virtual bool hasNoModRefInfoForCalls() const;
 
+protected:
+  /// 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.
+  virtual ModRefBehavior getModRefBehavior(Function *F, CallSite CS,
+                                     std::vector<PointerAccessInfo> *Info = 0);
+
+public:
   /// Convenience functions...
   ModRefResult getModRefInfo(LoadInst *L, Value *P, unsigned Size);
   ModRefResult getModRefInfo(StoreInst *S, Value *P, unsigned Size);
index 2a3ac5ae17c8fee7b65f09998c92d49de8524bbd..9e1ae2a0d2016bf33ff953eb18e268ca4eba9e87 100644 (file)
@@ -27,6 +27,7 @@
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Pass.h"
 #include "llvm/BasicBlock.h"
+#include "llvm/Function.h"
 #include "llvm/Instructions.h"
 #include "llvm/Type.h"
 #include "llvm/Target/TargetData.h"
@@ -112,16 +113,40 @@ AliasAnalysis::getModRefInfo(StoreInst *S, Value *P, unsigned Size) {
   return pointsToConstantMemory(P) ? NoModRef : Mod;
 }
 
+AliasAnalysis::ModRefBehavior
+AliasAnalysis::getModRefBehavior(CallSite CS,
+                                 std::vector<PointerAccessInfo> *Info) {
+  if (CS.paramHasAttr(0, ParamAttr::ReadNone))
+    // Can't do better than this.
+    return DoesNotAccessMemory;
+  ModRefBehavior MRB = UnknownModRefBehavior;
+  if (Function *F = CS.getCalledFunction())
+    MRB = getModRefBehavior(F, CS, Info);
+  if (MRB != DoesNotAccessMemory && CS.paramHasAttr(0, ParamAttr::ReadOnly))
+    return OnlyReadsMemory;
+  return MRB;
+}
+
+AliasAnalysis::ModRefBehavior
+AliasAnalysis::getModRefBehavior(Function *F,
+                                 std::vector<PointerAccessInfo> *Info) {
+  if (F->paramHasAttr(0, ParamAttr::ReadNone))
+    // Can't do better than this.
+    return DoesNotAccessMemory;
+  ModRefBehavior MRB = getModRefBehavior(F, CallSite(), Info);
+  if (MRB != DoesNotAccessMemory && F->paramHasAttr(0, ParamAttr::ReadOnly))
+    return OnlyReadsMemory;
+  return MRB;
+}
+
 AliasAnalysis::ModRefResult
 AliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
   ModRefResult Mask = ModRef;
-  if (Function *F = CS.getCalledFunction()) {
-    ModRefBehavior MRB = getModRefBehavior(F, CallSite());
-    if (MRB == OnlyReadsMemory)
-      Mask = Ref;
-    else if (MRB == DoesNotAccessMemory)
-      return NoModRef;
-  }
+  ModRefBehavior MRB = getModRefBehavior(CS);
+  if (MRB == OnlyReadsMemory)
+    Mask = Ref;
+  else if (MRB == DoesNotAccessMemory)
+    return NoModRef;
 
   if (!AA) return Mask;
 
index eea2c9904d14c0edf1092297e89f464292be51ff..2fccff1b7299f77b5d67cd4b9f55fb5fad729041 100644 (file)
@@ -89,9 +89,15 @@ namespace {
     bool pointsToConstantMemory(const Value *P) {
       return getAnalysis<AliasAnalysis>().pointsToConstantMemory(P);
     }
+    bool doesNotAccessMemory(CallSite CS) {
+      return getAnalysis<AliasAnalysis>().doesNotAccessMemory(CS);
+    }
     bool doesNotAccessMemory(Function *F) {
       return getAnalysis<AliasAnalysis>().doesNotAccessMemory(F);
     }
+    bool onlyReadsMemory(CallSite CS) {
+      return getAnalysis<AliasAnalysis>().onlyReadsMemory(CS);
+    }
     bool onlyReadsMemory(Function *F) {
       return getAnalysis<AliasAnalysis>().onlyReadsMemory(F);
     }
index fcdd1b3399961d7f441cdb99ca6057a79f6c9fdc..1b20c7aebf32d223d3f0a3ea83ab70608f868008 100644 (file)
@@ -114,15 +114,13 @@ void AliasSet::addPointer(AliasSetTracker &AST, HashNodePair &Entry,
 void AliasSet::addCallSite(CallSite CS, AliasAnalysis &AA) {
   CallSites.push_back(CS);
 
-  if (Function *F = CS.getCalledFunction()) {
-    AliasAnalysis::ModRefBehavior Behavior = AA.getModRefBehavior(F, CS);
-    if (Behavior == AliasAnalysis::DoesNotAccessMemory)
-      return;
-    else if (Behavior == AliasAnalysis::OnlyReadsMemory) {
-      AliasTy = MayAlias;
-      AccessTy |= Refs;
-      return;
-    }
+  AliasAnalysis::ModRefBehavior Behavior = AA.getModRefBehavior(CS);
+  if (Behavior == AliasAnalysis::DoesNotAccessMemory)
+    return;
+  else if (Behavior == AliasAnalysis::OnlyReadsMemory) {
+    AliasTy = MayAlias;
+    AccessTy |= Refs;
+    return;
   }
 
   // FIXME: This should use mod/ref information to make this not suck so bad
@@ -166,9 +164,8 @@ bool AliasSet::aliasesPointer(const Value *Ptr, unsigned Size,
 }
 
 bool AliasSet::aliasesCallSite(CallSite CS, AliasAnalysis &AA) const {
-  if (Function *F = CS.getCalledFunction())
-    if (AA.doesNotAccessMemory(F))
-      return false;
+  if (AA.doesNotAccessMemory(CS))
+    return false;
 
   if (AA.hasNoModRefInfoForCalls())
     return true;
@@ -297,9 +294,8 @@ bool AliasSetTracker::add(FreeInst *FI) {
 
 
 bool AliasSetTracker::add(CallSite CS) {
-  if (Function *F = CS.getCalledFunction())
-    if (AA.doesNotAccessMemory(F))
-      return true; // doesn't alias anything
+  if (AA.doesNotAccessMemory(CS))
+    return true; // doesn't alias anything
 
   AliasSet *AS = findAliasSetForCallSite(CS);
   if (!AS) {
@@ -419,9 +415,8 @@ bool AliasSetTracker::remove(FreeInst *FI) {
 }
 
 bool AliasSetTracker::remove(CallSite CS) {
-  if (Function *F = CS.getCalledFunction())
-    if (AA.doesNotAccessMemory(F))
-      return false; // doesn't alias anything
+  if (AA.doesNotAccessMemory(CS))
+    return false; // doesn't alias anything
 
   AliasSet *AS = findAliasSetForCallSite(CS);
   if (!AS) return false;
@@ -455,13 +450,10 @@ void AliasSetTracker::deleteValue(Value *PtrVal) {
   // If this is a call instruction, remove the callsite from the appropriate
   // AliasSet.
   CallSite CS = CallSite::get(PtrVal);
-  if (CS.getInstruction()) {
-    Function *F = CS.getCalledFunction();
-    if (!F || !AA.doesNotAccessMemory(F)) {
+  if (CS.getInstruction())
+    if (!AA.doesNotAccessMemory(CS))
       if (AliasSet *AS = findAliasSetForCallSite(CS))
         AS->removeCallSite(CS);
-    }
-  }
 
   // First, look up the PointerRec for this pointer.
   hash_map<Value*, AliasSet::PointerRec>::iterator I = PointerMap.find(PtrVal);
index 575e9218eaa1a3cadde53be0efda6d238be44dbe..5ec9afaec98797d47b4d09a27b2073cdb3598b9a 100644 (file)
@@ -839,11 +839,6 @@ BasicAliasAnalysis::getModRefBehavior(Function *F, CallSite CS,
     return UnknownModRefBehavior;
   }
 
-  if (F->paramHasAttr(0, ParamAttr::ReadNone))
-    return DoesNotAccessMemory;
-  if (F->paramHasAttr(0, ParamAttr::ReadOnly))
-    return OnlyReadsMemory;
-
   return UnknownModRefBehavior;
 }
 
index dce4a1ee8a02c59dd71845908e6f6dcc8dd1c189..9e943dde5d038f52fe8cd26abf3b23f2a1526ff8 100644 (file)
@@ -394,7 +394,7 @@ void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &SCC) {
           // Okay, if we can't say anything about it, maybe some other alias
           // analysis can.
           ModRefBehavior MRB =
-            AliasAnalysis::getModRefBehavior(Callee, CallSite());
+            AliasAnalysis::getModRefBehavior(Callee);
           if (MRB != DoesNotAccessMemory) {
             // FIXME: could make this more aggressive for functions that just
             // read memory.  We should just say they read all globals.
index 3af92bc11cb26aee508566624347660c42dabcac..67d4dd22bbac1d8b467bc17634e3e37dd177000c 100644 (file)
@@ -148,7 +148,7 @@ void LoadVN::getCallEqualNumberNodes(CallInst *CI,
   Function *CF = CI->getCalledFunction();
   if (CF == 0) return;  // Indirect call.
   AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
-  AliasAnalysis::ModRefBehavior MRB = AA.getModRefBehavior(CF, CI);
+  AliasAnalysis::ModRefBehavior MRB = AA.getModRefBehavior(CI);
   if (MRB != AliasAnalysis::DoesNotAccessMemory &&
       MRB != AliasAnalysis::OnlyReadsMemory)
     return;  // Nothing we can do for now.
@@ -227,8 +227,7 @@ void LoadVN::getCallEqualNumberNodes(CallInst *CI,
               CantEqual = true;
               break;
             } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
-              if (CI->getCalledFunction() == 0 ||
-                  !AA.onlyReadsMemory(CI->getCalledFunction())) {
+              if (!AA.onlyReadsMemory(CI)) {
                 CantEqual = true;
                 break;
               }
index dd567aac95dc35c854963a226940f30b96158b74..8c5f216f539a12be0853d9cfdc6e2aca17444a27 100644 (file)
@@ -94,11 +94,9 @@ Instruction* MemoryDependenceAnalysis::getCallSiteDependency(CallSite C,
       
       // FreeInsts erase the entire structure
       pointerSize = ~0UL;
-    } else if (CallSite::get(QI).getInstruction() != 0 &&
-               cast<CallInst>(QI)->getCalledFunction()) {
+    } else if (isa<CallInst>(QI)) {
       AliasAnalysis::ModRefBehavior result =
-                   AA.getModRefBehavior(cast<CallInst>(QI)->getCalledFunction(),
-                                        CallSite::get(QI));
+                   AA.getModRefBehavior(CallSite::get(QI));
       if (result != AliasAnalysis::DoesNotAccessMemory &&
           result != AliasAnalysis::OnlyReadsMemory) {
         if (!start && !block) {
index e3bd3623ce281fa041697eccb6ad37449bf2f3bf..7f3733421003df2056c29e3eaa03ef40609381e4 100644 (file)
@@ -198,8 +198,7 @@ bool ADCE::doADCE() {
     for (BasicBlock::iterator II = BB->begin(), EI = BB->end(); II != EI; ) {
       Instruction *I = II++;
       if (CallInst *CI = dyn_cast<CallInst>(I)) {
-        Function *F = CI->getCalledFunction();
-        if (F && AA.onlyReadsMemory(F)) {
+        if (AA.onlyReadsMemory(CI)) {
           if (CI->use_empty()) {
             BB->getInstList().erase(CI);
             ++NumCallRemoved;
index b19077f1fcc91fdf7f54d6b0abfe620c589baaf1..8e69d9ad689c4677496da7686c73f8f0314b82bc 100644 (file)
@@ -306,8 +306,7 @@ bool DSE::handleEndBlock(BasicBlock& BB,
       // If this call does not access memory, it can't
       // be undeadifying any of our pointers.
       CallSite CS = CallSite::get(BBI);
-      if (CS.getCalledFunction() &&
-          AA.doesNotAccessMemory(CS.getCalledFunction()))
+      if (AA.doesNotAccessMemory(CS))
         continue;
       
       unsigned modRef = 0;
index 7799befb3c25327e0d1c33fcb16bd5a90a9bd03a..c3d59854c65540f91091a23957ae4a6724847a1a 100644 (file)
@@ -341,8 +341,7 @@ Expression::ExpressionOpcode
 
 uint32_t ValueTable::hash_operand(Value* v) {
   if (CallInst* CI = dyn_cast<CallInst>(v))
-    if (CI->getCalledFunction() &&
-        !AA->doesNotAccessMemory(CI->getCalledFunction()))
+    if (!AA->doesNotAccessMemory(CI))
       return nextValueNumber++;
   
   return lookup_or_add(v);
@@ -485,9 +484,7 @@ uint32_t ValueTable::lookup_or_add(Value* V) {
     return VI->second;
   
   if (CallInst* C = dyn_cast<CallInst>(V)) {
-    if (C->getCalledFunction() &&
-        (AA->doesNotAccessMemory(C->getCalledFunction()) ||
-         AA->onlyReadsMemory(C->getCalledFunction()))) {
+    if (AA->onlyReadsMemory(C)) { // includes doesNotAccessMemory
       Expression e = create_expression(C);
     
       DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
@@ -1051,8 +1048,7 @@ bool GVN::processInstruction(Instruction* I,
     
     if (CallInst* CI = dyn_cast<CallInst>(I)) {
       AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
-      if (CI->getCalledFunction() &&
-          !AA.doesNotAccessMemory(CI->getCalledFunction())) {
+      if (!AA.doesNotAccessMemory(CI)) {
         MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
         if (cast<Instruction>(repl)->getParent() != CI->getParent() ||
             MD.getDependency(CI) != MD.getDependency(cast<CallInst>(repl))) {
index c86b463948905b2f19571eafc54809e8c7940b1b..0c8cb4d02731abd44bc0375c58b62db3c8604a3d 100644 (file)
@@ -375,24 +375,22 @@ bool LICM::canSinkOrHoistInst(Instruction &I) {
     return !pointerInvalidatedByLoop(LI->getOperand(0), Size);
   } else if (CallInst *CI = dyn_cast<CallInst>(&I)) {
     // Handle obvious cases efficiently.
-    if (Function *Callee = CI->getCalledFunction()) {
-      AliasAnalysis::ModRefBehavior Behavior =AA->getModRefBehavior(Callee, CI);
-      if (Behavior == AliasAnalysis::DoesNotAccessMemory)
-        return true;
-      else if (Behavior == AliasAnalysis::OnlyReadsMemory) {
-        // If this call only reads from memory and there are no writes to memory
-        // in the loop, we can hoist or sink the call as appropriate.
-        bool FoundMod = false;
-        for (AliasSetTracker::iterator I = CurAST->begin(), E = CurAST->end();
-             I != E; ++I) {
-          AliasSet &AS = *I;
-          if (!AS.isForwardingAliasSet() && AS.isMod()) {
-            FoundMod = true;
-            break;
-          }
+    AliasAnalysis::ModRefBehavior Behavior = AA->getModRefBehavior(CI);
+    if (Behavior == AliasAnalysis::DoesNotAccessMemory)
+      return true;
+    else if (Behavior == AliasAnalysis::OnlyReadsMemory) {
+      // If this call only reads from memory and there are no writes to memory
+      // in the loop, we can hoist or sink the call as appropriate.
+      bool FoundMod = false;
+      for (AliasSetTracker::iterator I = CurAST->begin(), E = CurAST->end();
+           I != E; ++I) {
+        AliasSet &AS = *I;
+        if (!AS.isForwardingAliasSet() && AS.isMod()) {
+          FoundMod = true;
+          break;
         }
-        if (!FoundMod) return true;
       }
+      if (!FoundMod) return true;
     }
 
     // FIXME: This should use mod/ref information to see if we can hoist or sink