[IR] Take operand bundles into account for call argument readonly/writeonly

We currently only take operand bundle effects into account when
querying the function-level memory attributes. However, I believe
that we also need to do the same for parameter attributes. For
example, a call with deopt bundle to a function with readnone
parameter attribute cannot treat that parameter as readnone,
because the deopt bundle may read it.

Differential Revision: https://reviews.llvm.org/D136834
This commit is contained in:
Nikita Popov 2022-10-27 12:45:08 +02:00
parent bcedeefa40
commit 6aa672f141
4 changed files with 26 additions and 9 deletions

View File

@ -344,9 +344,25 @@ bool CallBase::paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
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 {

View File

@ -21,7 +21,7 @@ define void @test1(i8* %p) {
; 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_memcpy_with_deopt() {
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"() ]

View File

@ -326,9 +326,10 @@ exit:
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_deopt(ptr %p) {
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_deopt(ptr %p) {
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
;

View File

@ -180,7 +180,7 @@ define void @direct3b(ptr %p) {
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
;