[IR] Take operand bundles into account for call argument readonly/writeonly
authorNikita Popov <npopov@redhat.com>
Thu, 27 Oct 2022 10:45:08 +0000 (12:45 +0200)
committerNikita Popov <npopov@redhat.com>
Tue, 1 Nov 2022 08:30:03 +0000 (09:30 +0100)
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

llvm/lib/IR/Instructions.cpp
llvm/test/Analysis/BasicAA/deoptimize.ll
llvm/test/Transforms/FunctionAttrs/readattrs.ll
llvm/test/Transforms/FunctionAttrs/writeonly.ll

index f3bcd53..8682a93 100644 (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 {
index b8f9f97..6836cc4 100644 (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"() ]
 
index a982832..1833d8b 100644 (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
 ;
index e4d1347..40ca265 100644 (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
 ;