[llvm] f85b9d6 - [ObjC][ARC] Ignore operand bundle "clang.arc.attachedcall" on a call if

Akira Hatanaka via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 28 11:02:50 PDT 2021


Author: Akira Hatanaka
Date: 2021-06-28T11:02:30-07:00
New Revision: f85b9d644398767f6b5cb046f952ed7dbd7dfc7a

URL: https://github.com/llvm/llvm-project/commit/f85b9d644398767f6b5cb046f952ed7dbd7dfc7a
DIFF: https://github.com/llvm/llvm-project/commit/f85b9d644398767f6b5cb046f952ed7dbd7dfc7a.diff

LOG: [ObjC][ARC] Ignore operand bundle "clang.arc.attachedcall" on a call if
the call's return type is void

Instead of trying hard to prevent global optimization passes such as
deadargelim from changing the return type to void, just ignore the
bundle if the return type is void. clang currently emits calls to
@llvm.objc.clang.arc.noop.use, which consumes the function call result,
immediately after the function call to prevent changes to the return
type, but optimization passes can delete the call to
@llvm.objc.clang.arc.noop.use if the function call doesn't return, which
enables deadargelim to change the return type.

rdar://76671438

Differential Revision: https://reviews.llvm.org/D103062

Added: 
    

Modified: 
    llvm/docs/LangRef.rst
    llvm/include/llvm/Analysis/ObjCARCUtil.h
    llvm/lib/IR/Verifier.cpp
    llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
    llvm/test/Verifier/operand-bundles.ll

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 1986f232cc3e3..083ece600448f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2406,8 +2406,10 @@ A ``"clang.arc.attachedcall`` operand bundle on a call indicates the call is
 implicitly followed by a marker instruction and a call to an ObjC runtime
 function that uses the result of the call. If the argument passed to the operand
 bundle is 0, ``@objc_retainAutoreleasedReturnValue`` is called. If 1 is passed,
-``@objc_unsafeClaimAutoreleasedReturnValue`` is called. A call with this bundle
-implicitly uses its return value.
+``@objc_unsafeClaimAutoreleasedReturnValue`` is called. The return value of a
+call with this bundle is used by a call to ``@llvm.objc.clang.arc.noop.use``
+unless the called function's return type is void, in which case the operand
+bundle is ignored.
 
 The operand bundle is needed to ensure the call is immediately followed by the
 marker instruction or the ObjC runtime call in the final output.

diff  --git a/llvm/include/llvm/Analysis/ObjCARCUtil.h b/llvm/include/llvm/Analysis/ObjCARCUtil.h
index 5d04ebadf0851..2566bfbcf61cc 100644
--- a/llvm/include/llvm/Analysis/ObjCARCUtil.h
+++ b/llvm/include/llvm/Analysis/ObjCARCUtil.h
@@ -31,7 +31,21 @@ getAttachedCallOperandBundleEnum(bool IsRetain) {
   return IsRetain ? RVOB_Retain : RVOB_Claim;
 }
 
+inline bool hasAttachedCallOpBundle(const CallBase *CB) {
+  // Ignore the bundle if the return type is void. Global optimization passes
+  // can turn the called function's return type to void. That should happen only
+  // if the call doesn't return and the call to @llvm.objc.clang.arc.noop.use
+  // no longer consumes the function return or is deleted. In that case, it's
+  // not necessary to emit the marker instruction or calls to the ARC runtime
+  // functions.
+  return !CB->getFunctionType()->getReturnType()->isVoidTy() &&
+         CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall)
+             .hasValue();
+}
+
 inline bool hasAttachedCallOpBundle(const CallBase *CB, bool IsRetain) {
+  assert(hasAttachedCallOpBundle(CB) &&
+         "call doesn't have operand bundle clang_arc_attachedcall");
   auto B = CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall);
   if (!B.hasValue())
     return false;
@@ -39,11 +53,6 @@ inline bool hasAttachedCallOpBundle(const CallBase *CB, bool IsRetain) {
          getAttachedCallOperandBundleEnum(IsRetain);
 }
 
-inline bool hasAttachedCallOpBundle(const CallBase *CB) {
-  return CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall)
-      .hasValue();
-}
-
 } // end namespace objcarc
 } // end namespace llvm
 

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 468c935e3bbf2..24f5d51381803 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3353,9 +3353,11 @@ void Verifier::visitCallBase(CallBase &Call) {
   }
 
   if (FoundAttachedCallBundle)
-    Assert(FTy->getReturnType()->isPointerTy(),
+    Assert((FTy->getReturnType()->isPointerTy() ||
+            (Call.doesNotReturn() && FTy->getReturnType()->isVoidTy())),
            "a call with operand bundle \"clang.arc.attachedcall\" must call a "
-           "function returning a pointer",
+           "function returning a pointer or a non-returning function that has "
+           "a void return type",
            Call);
 
   // Verify that each inlinable callsite of a debug-info-bearing function in a

diff  --git a/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll b/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
index 3a817327c3638..18bc00b62db8d 100644
--- a/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
+++ b/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
@@ -55,9 +55,22 @@ cleanup:
   ret i8* %retval.0
 }
 
+; CHECK-LABEL: define void @test3(
+; CHECK: call void @foo2() #[[ATTR1:.*]] [ "clang.arc.attachedcall"(i64 0) ]
+; CHECK-NEXT: ret void
+
+define void @test3() {
+  call void @foo2() #0 [ "clang.arc.attachedcall"(i64 0) ]
+  ret void
+}
+
 declare i8* @foo()
+declare void @foo2()
 declare i32 @__gxx_personality_v0(...)
 
 !llvm.module.flags = !{!0}
 
+; CHECK: attributes #[[ATTR1]] = { noreturn }
+attributes #0 = { noreturn }
+
 !0 = !{i32 1, !"clang.arc.retainAutoreleasedReturnValueMarker", !"mov\09fp, fp\09\09// marker for objc_retainAutoreleaseReturnValue"}

diff  --git a/llvm/test/Verifier/operand-bundles.ll b/llvm/test/Verifier/operand-bundles.ll
index 4ef0e647988af..d7d7b4f0f7820 100644
--- a/llvm/test/Verifier/operand-bundles.ll
+++ b/llvm/test/Verifier/operand-bundles.ll
@@ -4,6 +4,7 @@
 declare void @g()
 declare %0* @foo0()
 declare i8 @foo1()
+declare void @noreturn_func()
 
 ; Operand bundles uses are like regular uses, and need to be dominated
 ; by their defs.
@@ -69,9 +70,15 @@ define void @f_clang_arc_attachedcall() {
 ; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i64 0), "clang.arc.attachedcall"(i64 0) ]
 ; CHECK-NEXT: must call a function returning a pointer
 ; CHECK-NEXT: call i8 @foo1() [ "clang.arc.attachedcall"(i64 0) ]
+; CHECK-NEXT: or a non-returning function
+; CHECK-NEXT: call void @g() [ "clang.arc.attachedcall"(i64 0) ]
 
   call %0* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
   call %0* @foo0() [ "clang.arc.attachedcall"(i64 0), "clang.arc.attachedcall"(i64 0) ]
   call i8 @foo1() [ "clang.arc.attachedcall"(i64 0) ]
+  call void @noreturn_func() #0 [ "clang.arc.attachedcall"(i64 0) ]
+  call void @g() [ "clang.arc.attachedcall"(i64 0) ]
   ret void
 }
+
+attributes #0 = { noreturn }


        


More information about the llvm-commits mailing list