diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -79,6 +79,10 @@
   cl::Hidden,
   cl::desc("Convert noalias attributes to metadata during inlining."));
 
+static cl::opt<bool> UpdateReturnAttributes(
+    "update-return-attrs", cl::init(true), cl::Hidden,
+    cl::desc("Update return attributes on calls within inlined body"));
+
 static cl::opt<bool>
 PreserveAlignmentAssumptions("preserve-alignment-assumptions-during-inlining",
   cl::init(true), cl::Hidden,
@@ -1135,6 +1139,38 @@
   }
 }
 
+static void AddReturnAttributes(CallSite CS, ValueToValueMapTy &VMap) {
+  if (!UpdateReturnAttributes)
+    return;
+  AttrBuilder AB(CS.getAttributes(), AttributeList::ReturnIndex);
+  if (AB.empty())
+    return;
+
+  auto *CalledFunction = CS.getCalledFunction();
+  auto &Context = CalledFunction->getContext();
+  for (auto &BB : *CalledFunction) {
+    auto *RI = dyn_cast<ReturnInst>(BB.getTerminator());
+    if (!RI)
+      continue;
+    auto *RetVal = dyn_cast<CallBase>(RI->getOperand(0));
+    if (!RetVal)
+     	continue;
+    ValueToValueMapTy::iterator VMI = VMap.find(RetVal);
+    // Sanity check that the cloned instruction exists and is a call.
+    if (VMI == VMap.end() || !VMI->second)
+      continue;
+    auto *NewRetVal = dyn_cast<CallBase>(VMI->second);
+	  if (!NewRetVal)
+			continue;
+    // Add to the existing attributes.
+    // Should we check for conflicting attributes?
+    AttributeList AL = NewRetVal->getAttributes();
+    AttributeList NewAL = AL.addAttributes(Context, AttributeList::ReturnIndex, AB);
+	  NewRetVal->setAttributes(NewAL);
+  }
+
+}
+
 /// If the inlined function has non-byval align arguments, then
 /// add @llvm.assume-based alignment assumptions to preserve this information.
 static void AddAlignmentAssumptions(CallSite CS, InlineFunctionInfo &IFI) {
@@ -1795,6 +1831,10 @@
     // Add noalias metadata if necessary.
     AddAliasScopeMetadata(CS, VMap, DL, CalleeAAR);
 
+    // Clone return attributes on the callsite into the calls within the inlined
+    // function which feed into its return value.
+    AddReturnAttributes(CS, VMap);
+
     // Propagate llvm.mem.parallel_loop_access if necessary.
     PropagateParallelLoopAccessMetadata(CS, VMap);
 
diff --git a/llvm/test/Transforms/Inline/ret_attr_update.ll b/llvm/test/Transforms/Inline/ret_attr_update.ll
new file mode 100644
--- /dev/null
+++ b/llvm/test/Transforms/Inline/ret_attr_update.ll
@@ -0,0 +1,62 @@
+; RUN: opt < %s -inline-threshold=0 -always-inline -S | FileCheck %s
+; RUN: opt < %s -passes=always-inline -S | FileCheck %s
+
+declare i8* @foo(i8*)
+declare i8* @bar(i8*)
+declare i8* @baz(i8*)
+
+define i8* @callee(i8 *%p) alwaysinline {
+; CHECK: @callee(
+; CHECK: call i8* @foo(i8* noalias %p)
+  %r = call i8* @foo(i8* noalias %p)
+  ret i8* %r
+}
+
+define i8* @caller(i8* %ptr, i64 %x) {
+; CHECK-LABEL: @caller
+; CHECK: call nonnull i8* @foo(i8* noalias
+  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
+  %p = call nonnull i8* @callee(i8* %gep)
+  ret i8* %p
+}
+
+define internal i8* @callee_with_multiple_returns(i8* %p, i1 %cond) alwaysinline {
+; CHECK-NOT: callee_with_multiple_returns
+  br i1 %cond, label %pass, label %fail
+
+pass:
+  %r = call nonnull i8* @foo(i8* %p)
+  ret i8* %r
+
+fail:
+  %vfail = call i8* @baz(i8* %p)
+  ret i8* %vfail
+
+Unreachable:
+  %val = call i8* @bar(i8* %p)
+  ret i8* %val
+}
+
+define i8* @caller2(i8* %ptr, i64 %x, i1 %cond) {
+; CHECK-LABEL: @caller
+; CHECK: call noalias nonnull i8* @foo
+; CHECK: call noalias i8* @baz
+; CHECK-NOT: @bar
+  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
+  %p = call noalias i8* @callee_with_multiple_returns(i8* %gep, i1 %cond)
+  ret i8* %p
+}
+
+define internal i8* @callee3(i8 *%p) alwaysinline {
+; CHECK-NOT: callee3
+  %r = call i8* @foo(i8* noalias %p)
+  ret i8* %r
+}
+
+define i8* @caller3(i8* %ptr, i64 %x) {
+; CHECK-LABEL: caller3
+; CHECK: call dereferenceable_or_null(12) i8* @foo
+  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
+  %p = call dereferenceable_or_null(12) i8* @callee3(i8* %gep)
+  ret i8* %p
+}