Make adding nocapture a bit stronger. FreeInst is nocapture. Also,
authorNick Lewycky <nicholas@mxc.ca>
Fri, 2 Jan 2009 03:46:56 +0000 (03:46 +0000)
committerNick Lewycky <nicholas@mxc.ca>
Fri, 2 Jan 2009 03:46:56 +0000 (03:46 +0000)
functions that don't write can't leak a pointer except through
the return value, so a void readonly function is implicitly nocapture.

Test these, and add a test that verifies that f1 calling f2 with an
otherwise dead pointer gets both of them marked nocapture.

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

lib/Transforms/IPO/FunctionAttrs.cpp
test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll

index fcdede2fa35e57b0085c02c8edba6a9ded83a705..3c9570bd508f9cf37a094d6e79d33b8ff1f29e0c 100644 (file)
@@ -208,10 +208,20 @@ bool FunctionAttrs::isCaptured(Function &F, Value *V) {
       continue;
     }
 
+    if (isa<FreeInst>(I)) {
+      // Freeing a pointer does not cause it to escape.
+      continue;
+    }
+
     CallSite CS = CallSite::get(I);
     if (CS.getInstruction()) {
-      // Does not escape if only passed via 'nocapture' arguments.  Note
-      // that calling a function pointer does not in itself cause that
+      // Does not escape if the callee is readonly and doesn't return a
+      // copy through its own return value.
+      if (CS.onlyReadsMemory() && I->getType() == Type::VoidTy)
+        continue;
+
+      // Does not escape if passed via 'nocapture' arguments.  Note that
+      // calling a function pointer does not in itself cause that
       // function pointer to escape.  This is a subtle point considering
       // that (for example) the callee might return its own address.  It
       // is analogous to saying that loading a value from a pointer does
@@ -264,6 +274,20 @@ bool FunctionAttrs::AddNoCaptureAttrs(const std::vector<CallGraphNode *> &SCC) {
       // External node - skip it;
       continue;
 
+    // If the function is readonly and doesn't return any value, we 
+    // know that the pointer value can't escape. Mark all of its pointer 
+    // arguments nocapture.
+    if (F->onlyReadsMemory() && F->getReturnType() == Type::VoidTy) {
+      for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end();
+           A != E; ++A)
+        if (isa<PointerType>(A->getType()) && !A->hasNoCaptureAttr()) {
+          A->addAttr(Attribute::NoCapture);
+          ++NumNoCapture;
+          Changed = true;
+        }
+      continue;
+    }
+
     // Definitions with weak linkage may be overridden at linktime with
     // something that writes memory, so treat them like declarations.
     if (F->isDeclaration() || F->mayBeOverridden())
@@ -273,7 +297,7 @@ bool FunctionAttrs::AddNoCaptureAttrs(const std::vector<CallGraphNode *> &SCC) {
       if (isa<PointerType>(A->getType()) && !A->hasNoCaptureAttr() &&
           !isCaptured(*F, A)) {
         A->addAttr(Attribute::NoCapture);
-        NumNoCapture++;
+        ++NumNoCapture;
         Changed = true;
       }
   }
index 61c607dc007ef603ecac57b42572ca714ccb960b..758f0dd3addf622fbc0d4196ebb485c62e07e7c5 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | not grep {nocapture *%%q}
-; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep {nocapture *%%p} | count 3
+; RUN: llvm-as < %s | opt -functionattrs | llvm-dis | grep {nocapture *%%p} | count 8
 @g = global i32* null          ; <i32**> [#uses=1]
 
 define i32* @c1(i32* %q) {
@@ -62,3 +62,25 @@ define void @nc3(void ()* %p) {
        call void %p()
        ret void
 }
+
+declare void @external(i8*) readonly
+define void @nc4(i8* %p) {
+       call void @external(i8* %p)
+       ret void
+}
+
+define void @nc5(void (i8*)* %f, i8* %p) {
+       call void %f(i8* %p) readonly
+       call void %f(i8* nocapture %p)
+       ret void
+}
+
+define void @nc6(i8* %p) {
+       call void @nc7(i8* %p)
+       ret void
+}
+
+define void @nc7(i8* %p) {
+       call void @nc6(i8* %p)
+       ret void
+}