Index: include/llvm/IR/CallSite.h
===================================================================
--- include/llvm/IR/CallSite.h
+++ include/llvm/IR/CallSite.h
@@ -333,6 +333,14 @@
     CALLSITE_DELEGATE_GETTER(getOperandBundle(Index));
   }
 
+  bool isOperandBundleUse(const Use &U) const {
+    CALLSITE_DELEGATE_GETTER(isOperandBundleUse(U));
+  }
+
+  bool isCapturingOperandBundleUse(const Use &U) const {
+    CALLSITE_DELEGATE_GETTER(isCapturingOperandBundleUse(U));
+  }
+
 #undef CALLSITE_DELEGATE_GETTER
 #undef CALLSITE_DELEGATE_SETTER
 
Index: include/llvm/IR/InstrTypes.h
===================================================================
--- include/llvm/IR/InstrTypes.h
+++ include/llvm/IR/InstrTypes.h
@@ -17,6 +17,7 @@
 #define LLVM_IR_INSTRTYPES_H
 
 #include "llvm/ADT/Twine.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/OperandTraits.h"
@@ -1197,21 +1198,50 @@
   /// \brief Return the operand bundle at a specific index.
   OperandBundleUse getOperandBundle(unsigned Index) const {
     assert(Index < getNumOperandBundles() && "Index out of bounds!");
-    auto *BOI = bundle_op_info_begin() + Index;
-    auto op_begin = static_cast<const InstrTy *>(this)->op_begin();
-    ArrayRef<Use> Inputs(op_begin + BOI->Begin, op_begin + BOI->End);
-    return OperandBundleUse(BOI->Tag->getKey(), Inputs);
+    return bundleOpInfoToOpBundleUse(bundle_op_info_begin()[Index]);
   }
 
   /// \brief Return the operand bundle at a specific index.
   OperandBundleUse getOperandBundle(unsigned Index) {
     assert(Index < getNumOperandBundles() && "Index out of bounds!");
-    auto *BOI = bundle_op_info_begin() + Index;
-    auto op_begin = static_cast<InstrTy *>(this)->op_begin();
-    ArrayRef<Use> Inputs(op_begin + BOI->Begin, op_begin + BOI->End);
-    return OperandBundleUse(BOI->Tag->getKey(), Inputs);
+    return bundleOpInfoToOpBundleUse(bundle_op_info_begin()[Index]);
+  }
+
+  /// \brief Return the operand bundle containing U, and None if U is not
+  /// contained in an operand bundle.
+  Optional<OperandBundleUse> getContainingOperandBundle(const Use &U) const {
+    if (!hasOperandBundles())
+      return None;
+
+    unsigned UseIndex = &U - static_cast<const InstrTy *>(this)->op_begin();
+    assert(UseIndex < static_cast<const InstrTy *>(this)->getNumOperands() &&
+           "U not a Use for this User!");
+
+    for (auto &BOI : bundle_op_infos())
+      if (UseIndex <= BOI.Begin && UseIndex < BOI.End)
+        return bundleOpInfoToOpBundleUse(BOI);
+
+    return None;
+  }
+
+  /// \brief Return true if the use U is an operand bundle use.
+  bool isOperandBundleUse(const Use &U) const {
+    return getContainingOperandBundle(U).hasValue();
+  }
+
+  /// \brief Return true if U captured by via an operand bundle.
+  bool isCapturingOperandBundleUse(const Use &U) const {
+    return isOperandBundleUse(U);
   }
 
+  /// \brief Return true if this operand bundle user has operand bundles that
+  /// may read from the heap.
+  bool hasReadingOperandBundles() const { return hasOperandBundles(); }
+
+  /// \brief Return true if this operand bundle user has operand bundles that
+  /// may write to the heap.
+  bool hasClobberingOperandBundles() const { return hasOperandBundles(); }
+
 protected:
   /// \brief Used to keep track of an operand bundle.  See the main comment on
   /// OperandBundleUser above.
@@ -1229,6 +1259,13 @@
     uint32_t End;
   };
 
+  /// \brief Helper function create an OperandBundleUse out of an BundleOpInfo.
+  OperandBundleUse bundleOpInfoToOpBundleUse(const BundleOpInfo &BOI) const {
+    auto op_begin = static_cast<const InstrTy *>(this)->op_begin();
+    ArrayRef<Use> Inputs(op_begin + BOI.Begin, op_begin + BOI.End);
+    return OperandBundleUse(BOI.Tag->getKey(), Inputs);
+  }
+
   typedef BundleOpInfo *bundle_op_iterator;
   typedef const BundleOpInfo *const_bundle_op_iterator;
 
Index: include/llvm/IR/Instructions.h
===================================================================
--- include/llvm/IR/Instructions.h
+++ include/llvm/IR/Instructions.h
@@ -1739,9 +1739,21 @@
   }
 
 private:
+  bool isFnAttrDisallowedByOpBundle(StringRef S) const { return false; }
+
+  bool isFnAttrDisallowedByOpBundle(Attribute::AttrKind A) const {
+    return ((hasReadingOperandBundles() && A == Attribute::ReadNone) ||
+            (hasClobberingOperandBundles() &&
+             (A == Attribute::ReadOnly || A == Attribute::ReadNone)));
+  }
+
   template <typename AttrKind> bool hasFnAttrImpl(AttrKind A) const {
     if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A))
       return true;
+
+    if (isFnAttrDisallowedByOpBundle(A))
+      return false;
+
     if (const Function *F = getCalledFunction())
       return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, A);
     return false;
Index: lib/Analysis/CaptureTracking.cpp
===================================================================
--- lib/Analysis/CaptureTracking.cpp
+++ lib/Analysis/CaptureTracking.cpp
@@ -240,6 +240,13 @@
     case Instruction::Call:
     case Instruction::Invoke: {
       CallSite CS(I);
+
+      if (CS.isCapturingOperandBundleUse(*U)) {
+        if (Tracker->captured(U))
+          return;
+        break;
+      }
+
       // Not captured if the callee is readonly, doesn't return a copy through
       // its return value and doesn't unwind (a readonly function can leak bits
       // by throwing an exception or not depending on the input value).
Index: lib/IR/Instructions.cpp
===================================================================
--- lib/IR/Instructions.cpp
+++ lib/IR/Instructions.cpp
@@ -563,6 +563,12 @@
 bool InvokeInst::hasFnAttrImpl(Attribute::AttrKind A) const {
   if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A))
     return true;
+
+  if ((hasReadingOperandBundles() && A == Attribute::ReadNone) ||
+      (hasClobberingOperandBundles() &&
+       (A == Attribute::ReadOnly || A == Attribute::ReadNone)))
+    return false;
+
   if (const Function *F = getCalledFunction())
     return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, A);
   return false;
Index: lib/Transforms/IPO/FunctionAttrs.cpp
===================================================================
--- lib/Transforms/IPO/FunctionAttrs.cpp
+++ lib/Transforms/IPO/FunctionAttrs.cpp
@@ -125,7 +125,10 @@
     // Some instructions can be ignored even if they read or write memory.
     // Detect these now, skipping to the next instruction if one is found.
     CallSite CS(cast<Value>(I));
-    if (CS) {
+
+    // If the call or invoke has operand bundles, we let the generic
+    // mayWriteToMemory / mayReadFromMemory based handling kick in.
+    if (CS && !CS.hasOperandBundles()) {
       // Ignore calls to functions in the same SCC.
       if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction()))
         continue;
@@ -429,8 +432,9 @@
     case Instruction::Call:
     case Instruction::Invoke: {
       bool Captures = true;
+      CallSite CS(I);
 
-      if (I->getType()->isVoidTy())
+      if (I->getType()->isVoidTy() && !CS.isCapturingOperandBundleUse(*U))
         Captures = false;
 
       auto AddUsersToWorklistIfCapturing = [&] {
@@ -440,14 +444,13 @@
               Worklist.push_back(&UU);
       };
 
-      CallSite CS(I);
       if (CS.doesNotAccessMemory()) {
         AddUsersToWorklistIfCapturing();
         continue;
       }
 
       Function *F = CS.getCalledFunction();
-      if (!F) {
+      if (!F || CS.isOperandBundleUse(*U)) {
         if (CS.onlyReadsMemory()) {
           IsRead = true;
           AddUsersToWorklistIfCapturing();
Index: test/Transforms/FunctionAttrs/operand-bundles.ll
===================================================================
--- /dev/null
+++ test/Transforms/FunctionAttrs/operand-bundles.ll
@@ -0,0 +1,12 @@
+; RUN: opt -functionattrs -S < %s | FileCheck %s
+
+declare void @readnone_callee() readnone
+
+; %ptr should not be marked readnone or nocapture.
+
+; CHECK: define void @f(i32* %ptr) {
+define void @f(i32* %ptr) {
+ entry:
+  call void @readnone_callee() [ "foo"(i32* %ptr) ]
+  ret void
+}
Index: test/Transforms/PruneEH/operand-bundles.ll
===================================================================
--- /dev/null
+++ test/Transforms/PruneEH/operand-bundles.ll
@@ -0,0 +1,12 @@
+; RUN: opt -prune-eh -S < %s | FileCheck %s
+
+declare void @readnone_callee() nounwind
+
+; CHECK: define void @f(i32* %ptr) #0 {
+define void @f(i32* %ptr) {
+ entry:
+  call void @readnone_callee() [ "foo"(i32* %ptr) ]
+  ret void
+}
+
+; CHECK: attributes #0 = { nounwind }