diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3385,24 +3385,40 @@ // Mark any parameters that are known to be non-null with the nonnull // attribute. This is helpful for inlining calls to functions with null // checks on their arguments. - SmallVector ArgNos; + // Likewise mark parameters that are known not captured from parent attributes + // as nocapture. + SmallVector ArgNosNonNull, ArgNosNoCapture; + SmallPtrSet NoCaptureParentArguments; unsigned ArgNo = 0; + if (auto *BB = Call.getParent()) + if (auto *PF = BB->getParent()) + for (unsigned I = 0; I < PF->arg_size(); ++I) + if (PF->getArg(I)->hasNoCaptureAttr()) + NoCaptureParentArguments.insert(PF->getArg(I)); for (Value *V : Call.args()) { if (V->getType()->isPointerTy() && !Call.paramHasAttr(ArgNo, Attribute::NonNull) && isKnownNonZero(V, DL, 0, &AC, &Call, &DT)) - ArgNos.push_back(ArgNo); + ArgNosNonNull.push_back(ArgNo); + if (!Call.paramHasAttr(ArgNo, Attribute::NoCapture) && + NoCaptureParentArguments.contains(V)) + ArgNosNoCapture.push_back(ArgNo); + ArgNo++; } assert(ArgNo == Call.arg_size() && "Call arguments not processed correctly."); - if (!ArgNos.empty()) { + if (!ArgNosNonNull.empty() || !ArgNosNoCapture.empty()) { AttributeList AS = Call.getAttributes(); LLVMContext &Ctx = Call.getContext(); - AS = AS.addParamAttribute(Ctx, ArgNos, - Attribute::get(Ctx, Attribute::NonNull)); + if (!ArgNosNonNull.empty()) + AS = AS.addParamAttribute(Ctx, ArgNosNonNull, + Attribute::get(Ctx, Attribute::NonNull)); + if (!ArgNosNoCapture.empty()) + AS = AS.addParamAttribute(Ctx, ArgNosNoCapture, + Attribute::get(Ctx, Attribute::NoCapture)); Call.setAttributes(AS); Changed = true; } diff --git a/llvm/test/Analysis/BasicAA/nocapture.ll b/llvm/test/Analysis/BasicAA/nocapture.ll --- a/llvm/test/Analysis/BasicAA/nocapture.ll +++ b/llvm/test/Analysis/BasicAA/nocapture.ll @@ -18,9 +18,9 @@ define i32 @test4(ptr noalias nocapture %p) nounwind { ; CHECK: call void @test3 ; CHECK: store i32 0, ptr %p +; CHECK: %x = load ptr, ptr %q ; CHECK: store i32 1, ptr %x -; CHECK: %y = load i32, ptr %p -; CHECK: ret i32 %y +; CHECK: ret i32 0 entry: %q = alloca ptr ; Here test3 might store %p to %q. This doesn't violate %p's nocapture diff --git a/llvm/test/Transforms/InstCombine/nocapture-attribute.ll b/llvm/test/Transforms/InstCombine/nocapture-attribute.ll --- a/llvm/test/Transforms/InstCombine/nocapture-attribute.ll +++ b/llvm/test/Transforms/InstCombine/nocapture-attribute.ll @@ -17,7 +17,7 @@ define void @a0_nocapture_a1_a2_maybe_capture(ptr nocapture %a0, ptr %a1, ptr %a2) { ; CHECK-LABEL: define void @a0_nocapture_a1_a2_maybe_capture ; CHECK-SAME: (ptr nocapture [[A0:%.*]], ptr [[A1:%.*]], ptr [[A2:%.*]]) { -; CHECK-NEXT: tail call void @ptrs_maybe_capture(ptr [[A0]], ptr [[A1]], ptr [[A2]]) +; CHECK-NEXT: tail call void @ptrs_maybe_capture(ptr nocapture [[A0]], ptr [[A1]], ptr [[A2]]) ; CHECK-NEXT: ret void ; tail call void @ptrs_maybe_capture(ptr %a0, ptr %a1, ptr %a2) @@ -27,7 +27,7 @@ define void @a2_nocapture2x_a1_maybe_capture(ptr %a0, ptr %a1, ptr nocapture %a2) { ; CHECK-LABEL: define void @a2_nocapture2x_a1_maybe_capture ; CHECK-SAME: (ptr [[A0:%.*]], ptr [[A1:%.*]], ptr nocapture [[A2:%.*]]) { -; CHECK-NEXT: tail call void @ptrs_maybe_capture(ptr [[A2]], ptr [[A1]], ptr [[A2]]) +; CHECK-NEXT: tail call void @ptrs_maybe_capture(ptr nocapture [[A2]], ptr [[A1]], ptr nocapture [[A2]]) ; CHECK-NEXT: ret void ; tail call void @ptrs_maybe_capture(ptr %a2, ptr %a1, ptr %a2) @@ -37,7 +37,7 @@ define void @a0_a1_a2_nocapture(ptr nocapture %a0, ptr nocapture %a1, ptr nocapture %a2) { ; CHECK-LABEL: define void @a0_a1_a2_nocapture ; CHECK-SAME: (ptr nocapture [[A0:%.*]], ptr nocapture [[A1:%.*]], ptr nocapture [[A2:%.*]]) { -; CHECK-NEXT: tail call void @ptrs_maybe_capture(ptr [[A0]], ptr [[A1]], ptr [[A2]]) +; CHECK-NEXT: tail call void @ptrs_maybe_capture(ptr nocapture [[A0]], ptr nocapture [[A1]], ptr nocapture [[A2]]) ; CHECK-NEXT: ret void ; tail call void @ptrs_maybe_capture(ptr %a0, ptr %a1, ptr %a2)