diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -344,9 +344,25 @@ if (Attrs.hasParamAttr(ArgNo, Kind)) return true; - if (const Function *F = getCalledFunction()) - return F->getAttributes().hasParamAttr(ArgNo, Kind); - return false; + + const Function *F = getCalledFunction(); + if (!F) + return false; + + if (!F->getAttributes().hasParamAttr(ArgNo, Kind)) + return false; + + // Take into account mod/ref by operand bundles. + switch (Kind) { + case Attribute::ReadNone: + return !hasReadingOperandBundles() && !hasClobberingOperandBundles(); + case Attribute::ReadOnly: + return !hasClobberingOperandBundles(); + case Attribute::WriteOnly: + return !hasReadingOperandBundles(); + default: + return true; + } } bool CallBase::hasFnAttrOnCalledFunction(Attribute::AttrKind Kind) const { diff --git a/llvm/test/Analysis/BasicAA/deoptimize.ll b/llvm/test/Analysis/BasicAA/deoptimize.ll --- a/llvm/test/Analysis/BasicAA/deoptimize.ll +++ b/llvm/test/Analysis/BasicAA/deoptimize.ll @@ -21,7 +21,7 @@ ; Check that global G1 is reported as Ref by memcpy/memmove calls. define i32 @test_memcpy_with_deopt() { ; CHECK-LABEL: Function: test_memcpy_with_deopt: -; CHECK: Just Mod: Ptr: i8* %A <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] +; CHECK: Both ModRef: Ptr: i8* %A <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] ; CHECK: Just Ref: Ptr: i8* %B <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] ; CHECK: Just Ref: Ptr: i32* @G1 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] @@ -40,7 +40,7 @@ define i32 @test_memmove_with_deopt() { ; CHECK-LABEL: Function: test_memmove_with_deopt: -; CHECK: Just Mod: Ptr: i8* %A <-> call void @llvm.memmove.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] +; CHECK: Both ModRef: Ptr: i8* %A <-> call void @llvm.memmove.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] ; CHECK: Just Ref: Ptr: i8* %B <-> call void @llvm.memmove.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] ; CHECK: Just Ref: Ptr: i32* @G1 <-> call void @llvm.memmove.p0i8.p0i8.i64(i8* %A, i8* %B, i64 -1, i1 false) [ "deopt"() ] diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll --- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll +++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll @@ -326,9 +326,10 @@ declare void @readnone_param(ptr nocapture readnone %p) declare void @readonly_param(ptr nocapture readonly %p) +; FIXME: While this can't be readnone, this could be readonly. define void @op_bundle_readnone_deopt(ptr %p) { ; CHECK-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt -; CHECK-SAME: (ptr nocapture readnone [[P:%.*]]) { +; CHECK-SAME: (ptr nocapture [[P:%.*]]) { ; CHECK-NEXT: call void @readnone_param(ptr [[P]]) [ "deopt"() ] ; CHECK-NEXT: ret void ; @@ -338,7 +339,7 @@ define void @op_bundle_readnone_unknown(ptr %p) { ; CHECK-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown -; CHECK-SAME: (ptr nocapture readnone [[P:%.*]]) { +; CHECK-SAME: (ptr nocapture [[P:%.*]]) { ; CHECK-NEXT: call void @readnone_param(ptr [[P]]) [ "unknown"() ] ; CHECK-NEXT: ret void ; @@ -358,7 +359,7 @@ define void @op_bundle_readonly_unknown(ptr %p) { ; CHECK-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown -; CHECK-SAME: (ptr nocapture readonly [[P:%.*]]) { +; CHECK-SAME: (ptr nocapture [[P:%.*]]) { ; CHECK-NEXT: call void @readonly_param(ptr [[P]]) [ "unknown"() ] ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/FunctionAttrs/writeonly.ll b/llvm/test/Transforms/FunctionAttrs/writeonly.ll --- a/llvm/test/Transforms/FunctionAttrs/writeonly.ll +++ b/llvm/test/Transforms/FunctionAttrs/writeonly.ll @@ -180,7 +180,7 @@ define void @direct3c(ptr %p) { ; CHECK-LABEL: define {{[^@]+}}@direct3c -; CHECK-SAME: (ptr nocapture writeonly [[P:%.*]]) { +; CHECK-SAME: (ptr nocapture [[P:%.*]]) { ; CHECK-NEXT: call void @direct3_callee(ptr [[P]]) [ "may-read"() ] ; CHECK-NEXT: ret void ;