Partially address a README by having functionattrs consider calls to
authorDuncan Sands <baldrick@free.fr>
Wed, 6 Jan 2010 08:45:52 +0000 (08:45 +0000)
committerDuncan Sands <baldrick@free.fr>
Wed, 6 Jan 2010 08:45:52 +0000 (08:45 +0000)
memcpy, memset and other intrinsics that only access their arguments
to be readnone if the intrinsic's arguments all point to local memory.
This improves the testcase in the README to readonly, but it could in
theory be made readnone, however this would involve more sophisticated
analysis that looks through the memcpy.

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

include/llvm/Analysis/AliasAnalysis.h
lib/Analysis/AliasAnalysis.cpp
lib/Target/README.txt
lib/Transforms/IPO/FunctionAttrs.cpp
test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll
utils/TableGen/IntrinsicEmitter.cpp

index 2d43bddf7e0ba6272c1a3dc0c5d145c6dd6ee38f..9f411350a791cbfe93f7e3333a9a638c537f80f2 100644 (file)
@@ -197,6 +197,10 @@ public:
   virtual ModRefBehavior getModRefBehavior(Function *F,
                                    std::vector<PointerAccessInfo> *Info = 0);
 
+  /// getModRefBehavior - Return the modref behavior of the intrinsic with the
+  /// given id.
+  static ModRefBehavior getModRefBehavior(unsigned iid);
+
   /// 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
index dee9b535871a0c02d397a48b7fafb69e6f8a188f..371dcafa9f3163434d75f4cc1f93e40013ee0af1 100644 (file)
@@ -116,13 +116,16 @@ AliasAnalysis::getModRefBehavior(Function *F,
       return DoesNotAccessMemory;
     if (F->onlyReadsMemory())
       return OnlyReadsMemory;
-    if (unsigned id = F->getIntrinsicID()) {
+    if (unsigned id = F->getIntrinsicID())
+      return getModRefBehavior(id);
+  }
+  return UnknownModRefBehavior;
+}
+
+AliasAnalysis::ModRefBehavior AliasAnalysis::getModRefBehavior(unsigned iid) {
 #define GET_INTRINSIC_MODREF_BEHAVIOR
 #include "llvm/Intrinsics.gen"
 #undef GET_INTRINSIC_MODREF_BEHAVIOR
-    }
-  }
-  return UnknownModRefBehavior;
 }
 
 AliasAnalysis::ModRefResult
index 22dadfeb3dd5e920cfaaa90b90456b913be05809..38c3daa9383845a6d4884b91bc703eb3dff7556a 100644 (file)
@@ -1678,8 +1678,8 @@ And functionattrs doesn't realize that the p.0 load points to function local
 memory.
 
 Also, functionattrs doesn't know about memcpy/memset.  This function should be
-marked readnone, since it only twiddles local memory, but functionattrs doesn't
-handle memset/memcpy/memmove aggressively:
+marked readnone rather than readonly, since it only twiddles local memory, but
+functionattrs doesn't handle memset/memcpy/memmove aggressively:
 
 struct X { int *p; int *q; };
 int foo() {
index a16d335ef50ff27e50e33914e788c7640029f2e9..0bff2b94e9d2d31f4a5c6b22e200878eb5a27eaf 100644 (file)
@@ -136,6 +136,21 @@ bool FunctionAttrs::AddReadAttrs(const std::vector<CallGraphNode *> &SCC) {
         // Ignore calls to functions in the same SCC.
         if (SCCNodes.count(CS.getCalledFunction()))
           continue;
+        // Ignore intrinsics that only access local memory.
+        if (unsigned id = CS.getCalledFunction()->getIntrinsicID())
+          if (AliasAnalysis::getModRefBehavior(id) ==
+              AliasAnalysis::AccessesArguments) {
+            // Check that all pointer arguments point to local memory.
+            for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
+                 CI != CE; ++CI) {
+              Value *Arg = *CI;
+              if (isa<PointerType>(Arg->getType()) && !PointsToLocalMemory(Arg))
+                // Writes memory.  Just give up.
+                return false;
+            }
+            // Only reads and writes local memory.
+            continue;
+          }
       } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
         // Ignore loads from local memory.
         if (PointsToLocalMemory(LI->getPointerOperand()))
index 09eb4687ac2633d7be3d6bebf1ef01b2e12d4395..460780d8ea56fd8fb22a280d4446cc925ce57660 100644 (file)
@@ -1,6 +1,8 @@
-; RUN: opt < %s -functionattrs -S | grep readnone | count 2
+; RUN: opt < %s -functionattrs -S | grep readonly | count 3
 
-declare i32 @g(i32*) readnone
+%struct.X = type { i32*, i32* }
+
+declare i32 @g(i32*) readonly
 
 define i32 @f() {
        %x = alloca i32         ; <i32*> [#uses=2]
@@ -8,3 +10,30 @@ define i32 @f() {
        %y = call i32 @g(i32* %x)               ; <i32> [#uses=1]
        ret i32 %y
 }
+
+define i32 @foo() nounwind {
+entry:
+  %y = alloca %struct.X                           ; <%struct.X*> [#uses=2]
+  %x = alloca %struct.X                           ; <%struct.X*> [#uses=2]
+  %j = alloca i32                                 ; <i32*> [#uses=2]
+  %i = alloca i32                                 ; <i32*> [#uses=2]
+  %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
+  store i32 0, i32* %i, align 4
+  store i32 1, i32* %j, align 4
+  %0 = getelementptr inbounds %struct.X* %y, i32 0, i32 0 ; <i32**> [#uses=1]
+  store i32* %i, i32** %0, align 8
+  %1 = getelementptr inbounds %struct.X* %x, i32 0, i32 1 ; <i32**> [#uses=1]
+  store i32* %j, i32** %1, align 8
+  %x1 = bitcast %struct.X* %x to i8*              ; <i8*> [#uses=2]
+  %y2 = bitcast %struct.X* %y to i8*              ; <i8*> [#uses=1]
+  call void @llvm.memcpy.i64(i8* %x1, i8* %y2, i64 8, i32 1)
+  %2 = bitcast i8* %x1 to i32**                   ; <i32**> [#uses=1]
+  %3 = load i32** %2, align 8                     ; <i32*> [#uses=1]
+  %4 = load i32* %3, align 4                      ; <i32> [#uses=1]
+  br label %return
+
+return:                                           ; preds = %entry
+  ret i32 %4
+}
+
+declare void @llvm.memcpy.i64(i8* nocapture, i8* nocapture, i64, i32) nounwind
index 23919d97f2bf1903daa4ea237b8e39c5bdb76943..c5df9e411c6882f24f98931f44ba29a8af94c0d4 100644 (file)
@@ -522,7 +522,7 @@ void IntrinsicEmitter::
 EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
   OS << "// Determine intrinsic alias analysis mod/ref behavior.\n";
   OS << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n";
-  OS << "switch (id) {\n";
+  OS << "switch (iid) {\n";
   OS << "default:\n    return UnknownModRefBehavior;\n";
   for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
     if (Ints[i].ModRef == CodeGenIntrinsic::WriteMem)