1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

[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
This commit is contained in:
Akira Hatanaka 2021-06-28 11:02:30 -07:00
parent 609f5d997c
commit 252bda7ebd
5 changed files with 42 additions and 9 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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"}

View File

@ -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 }