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:
parent
609f5d997c
commit
252bda7ebd
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"}
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user