[llvm-commits] [llvm] r70876 - in /llvm/trunk: lib/Analysis/CaptureTracking.cpp test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll

Duncan Sands baldrick at free.fr
Mon May 4 09:50:30 PDT 2009


Author: baldrick
Date: Mon May  4 11:50:29 2009
New Revision: 70876

URL: http://llvm.org/viewvc/llvm-project?rev=70876&view=rev
Log:
Teach capture tracking that readonly functions can
only capture their arguments by returning them or
throwing an exception or not based on the argument
value.  Patch essentially by Frits van Bommel.

Modified:
    llvm/trunk/lib/Analysis/CaptureTracking.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll

Modified: llvm/trunk/lib/Analysis/CaptureTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CaptureTracking.cpp?rev=70876&r1=70875&r2=70876&view=diff

==============================================================================
--- llvm/trunk/lib/Analysis/CaptureTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/CaptureTracking.cpp Mon May  4 11:50:29 2009
@@ -49,11 +49,7 @@
     switch (I->getOpcode()) {
     case Instruction::Call:
     case Instruction::Invoke: {
-      CallSite CS = CallSite::get(I);
-      // Not captured if the callee is readonly and doesn't return a copy
-      // through its return value.
-      if (CS.onlyReadsMemory() && I->getType() == Type::VoidTy)
-        break;
+      CallSite CS(I);
 
       // Not captured if only passed via 'nocapture' arguments.  Note that
       // calling a function pointer does not in itself cause the pointer to
@@ -62,46 +58,69 @@
       // that loading a value from a pointer does not cause the pointer to be
       // captured, even though the loaded value might be the pointer itself
       // (think of self-referential objects).
+      bool MayBeCaptured = false;
       CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
       for (CallSite::arg_iterator A = B; A != E; ++A)
-        if (A->get() == V && !CS.paramHasAttr(A - B + 1, Attribute::NoCapture))
-          // The parameter is not marked 'nocapture' - captured.
-          return true;
-      // Only passed via 'nocapture' arguments, or is the called function - not
-      // captured.
+        if (A->get() == V && !CS.paramHasAttr(A-B+1, Attribute::NoCapture)) {
+          // The parameter is not marked 'nocapture' - handled by generic code
+          // below.
+          MayBeCaptured = true;
+          break;
+        }
+      if (!MayBeCaptured)
+        // Only passed via 'nocapture' arguments, or is the called function -
+        // not captured.
+        continue;
+      if (!CS.doesNotThrow())
+        // Even a readonly function can leak bits by throwing an exception or
+        // not depending on the input value.
+        return true;
+      // Fall through to the generic code.
       break;
     }
     case Instruction::Free:
       // Freeing a pointer does not cause it to be captured.
-      break;
+      continue;
     case Instruction::Load:
       // Loading from a pointer does not cause it to be captured.
-      break;
+      continue;
     case Instruction::Ret:
       if (ReturnCaptures)
         return true;
-      break;
+      continue;
     case Instruction::Store:
       if (V == I->getOperand(0))
         // Stored the pointer - it may be captured.
         return true;
       // Storing to the pointee does not cause the pointer to be captured.
-      break;
-    case Instruction::BitCast:
-    case Instruction::GetElementPtr:
-    case Instruction::PHI:
-    case Instruction::Select:
-      // The original value is not captured via this if the new value isn't.
-      for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end();
-           UI != UE; ++UI) {
-        Use *U = &UI.getUse();
-        if (Visited.insert(U))
-          Worklist.push_back(U);
-      }
-      break;
-    default:
-      // Something else - be conservative and say it is captured.
+      continue;
+    }
+
+    // If it may write to memory and isn't one of the special cases above,
+    // be conservative and assume the pointer is captured.
+    if (I->mayWriteToMemory())
       return true;
+
+    // If the instruction doesn't write memory, it can only capture by
+    // having its own value depend on the input value.
+    const Type* Ty = I->getType();
+    if (Ty == Type::VoidTy)
+      // The value of an instruction can't be a copy if it can't contain any
+      // information.
+      continue;
+    if (!isa<PointerType>(Ty))
+      // At the moment, we don't track non-pointer values, so be conservative
+      // and assume the pointer is captured.
+      // FIXME: Track these too.  This would need to be done very carefully as
+      // it is easy to leak bits via control flow if integer values are allowed.
+      return true;
+
+    // The original value is not captured via this if the new value isn't.
+    for (Instruction::use_iterator UI = I->use_begin(), UE = I->use_end();
+         UI != UE; ++UI) {
+      Use *U = &UI.getUse();
+      if (Visited.insert(U))
+        Worklist.push_back(U);
     }
   }
 

Modified: llvm/trunk/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll?rev=70876&r1=70875&r2=70876&view=diff

==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/2008-12-31-NoCapture.ll Mon May  4 11:50:29 2009
@@ -39,6 +39,16 @@
 	ret i1 %val
 }
 
+declare void @throw_if_bit_set(i8*, i8) readonly
+define i1 @c6(i8* %q, i8 %bit) {
+	invoke void @throw_if_bit_set(i8* %q, i8 %bit)
+		to label %ret0 unwind label %ret1
+ret0:
+	ret i1 0
+ret1:
+	ret i1 1
+}
+
 define i32 @nc1(i32* %q, i32* %p, i1 %b) {
 e:
 	br label %l
@@ -63,14 +73,20 @@
 	ret void
 }
 
-declare void @external(i8*) readonly
+declare void @external(i8*) readonly nounwind
 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)
+define void @nc5(void (i8*)* %p, i8* %r) {
+	call void %p(i8* %r)
+	call void %p(i8* nocapture %r)
+	ret void
+}
+
+declare i8* @external_identity(i8*) readonly nounwind
+define void @nc6(i8* %p) {
+	call i8* @external_identity(i8* %p)
 	ret void
 }





More information about the llvm-commits mailing list