Skip to content

Commit 4b794c8

Browse files
[ObjC] Support objc_claimAutoreleasedReturnValue (#139720)
This adds basic support for objc_claimAutoreleasedReturnValue, which is mostly equivalent to objc_retainAutoreleasedReturnValue, with the difference that it doesn't require the marker nop to be emitted between it and the call it was attached to. To achieve that, this also teaches the AArch64 attachedcall bundle lowering to pick whether the marker should be emitted or not based on whether the attachedcall target is claimARV or retainARV. Co-authored-by: Ahmed Bougacha <[email protected]>
1 parent e4b6cc3 commit 4b794c8

File tree

7 files changed

+60
-12
lines changed

7 files changed

+60
-12
lines changed

llvm/include/llvm/Analysis/ObjCARCUtil.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@ inline std::optional<Function *> getAttachedARCFunction(const CallBase *CB) {
4848
return cast<Function>(B->Inputs[0]);
4949
}
5050

51+
/// This function determines whether the clang_arc_attachedcall should be
52+
/// emitted with or without the marker.
53+
/// Concretely, this is the difference between:
54+
/// objc_retainAutoreleasedReturnValue
55+
/// and
56+
/// objc_claimAutoreleasedReturnValue
57+
/// retainRV (and unsafeClaimRV) requires a marker, but claimRV does not.
58+
inline bool attachedCallOpBundleNeedsMarker(const CallBase *CB) {
59+
// FIXME: do this on ARCRuntimeEntryPoints, and do the todo above ARCInstKind
60+
if (std::optional<Function *> Fn = getAttachedARCFunction(CB))
61+
if ((*Fn)->getName() == "objc_claimAutoreleasedReturnValue")
62+
return false;
63+
return true;
64+
}
65+
5166
/// Check whether the function is retainRV/unsafeClaimRV.
5267
inline bool isRetainOrClaimRV(ARCInstKind Kind) {
5368
return Kind == ARCInstKind::RetainRV || Kind == ARCInstKind::UnsafeClaimRV;

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,10 +785,12 @@ def int_objc_loadWeakRetained : Intrinsic<[llvm_ptr_ty],
785785
def int_objc_moveWeak : Intrinsic<[],
786786
[llvm_ptr_ty,
787787
llvm_ptr_ty]>;
788+
788789
def int_objc_release : Intrinsic<[], [llvm_ptr_ty]>;
789790
def int_objc_retain : Intrinsic<[llvm_ptr_ty],
790791
[llvm_ptr_ty],
791792
[Returned<ArgIndex<0>>]>;
793+
792794
def int_objc_retainAutorelease : Intrinsic<[llvm_ptr_ty],
793795
[llvm_ptr_ty],
794796
[Returned<ArgIndex<0>>]>;
@@ -797,6 +799,11 @@ def int_objc_retainAutoreleaseReturnValue : Intrinsic<[llvm_ptr_ty],
797799
[Returned<ArgIndex<0>>]>;
798800
def int_objc_retainAutoreleasedReturnValue : Intrinsic<[llvm_ptr_ty],
799801
[llvm_ptr_ty]>;
802+
def int_objc_unsafeClaimAutoreleasedReturnValue : Intrinsic<[llvm_ptr_ty],
803+
[llvm_ptr_ty]>;
804+
def int_objc_claimAutoreleasedReturnValue : Intrinsic<[llvm_ptr_ty],
805+
[llvm_ptr_ty]>;
806+
800807
def int_objc_retainBlock : Intrinsic<[llvm_ptr_ty],
801808
[llvm_ptr_ty]>;
802809
def int_objc_storeStrong : Intrinsic<[],
@@ -810,8 +817,6 @@ def int_objc_clang_arc_use : Intrinsic<[],
810817
def int_objc_clang_arc_noop_use : DefaultAttrsIntrinsic<[],
811818
[llvm_vararg_ty],
812819
[IntrInaccessibleMemOnly]>;
813-
def int_objc_unsafeClaimAutoreleasedReturnValue : Intrinsic<[llvm_ptr_ty],
814-
[llvm_ptr_ty]>;
815820
def int_objc_retainedObject : Intrinsic<[llvm_ptr_ty],
816821
[llvm_ptr_ty]>;
817822
def int_objc_unretainedObject : Intrinsic<[llvm_ptr_ty],

llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,7 @@ static bool lowerObjCCall(Function &F, const char *NewFn,
160160
auto *CB = cast<CallBase>(U.getUser());
161161

162162
if (CB->getCalledFunction() != &F) {
163-
objcarc::ARCInstKind Kind = objcarc::getAttachedARCFunctionKind(CB);
164-
(void)Kind;
165-
assert((Kind == objcarc::ARCInstKind::RetainRV ||
166-
Kind == objcarc::ARCInstKind::UnsafeClaimRV) &&
163+
assert(objcarc::getAttachedARCFunction(CB) == &F &&
167164
"use expected to be the argument of operand bundle "
168165
"\"clang.arc.attachedcall\"");
169166
U.set(FCache.getCallee());
@@ -529,6 +526,9 @@ bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {
529526
case Intrinsic::objc_retainAutoreleasedReturnValue:
530527
Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
531528
break;
529+
case Intrinsic::objc_claimAutoreleasedReturnValue:
530+
Changed |= lowerObjCCall(F, "objc_claimAutoreleasedReturnValue");
531+
break;
532532
case Intrinsic::objc_retainBlock:
533533
Changed |= lowerObjCCall(F, "objc_retainBlock");
534534
break;

llvm/lib/IR/Verifier.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7283,11 +7283,13 @@ void Verifier::verifyAttachedCallBundle(const CallBase &Call,
72837283

72847284
if (IID) {
72857285
Check((IID == Intrinsic::objc_retainAutoreleasedReturnValue ||
7286+
IID == Intrinsic::objc_claimAutoreleasedReturnValue ||
72867287
IID == Intrinsic::objc_unsafeClaimAutoreleasedReturnValue),
72877288
"invalid function argument", Call);
72887289
} else {
72897290
StringRef FnName = Fn->getName();
72907291
Check((FnName == "objc_retainAutoreleasedReturnValue" ||
7292+
FnName == "objc_claimAutoreleasedReturnValue" ||
72917293
FnName == "objc_unsafeClaimAutoreleasedReturnValue"),
72927294
"invalid function argument", Call);
72937295
}

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9545,10 +9545,10 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
95459545
Ops.insert(Ops.begin() + 1, GA);
95469546

95479547
// We may or may not need to emit both the marker and the retain/claim call.
9548-
// Do what the frontend tells us: if the rvmarker module flag is present,
9549-
// emit the marker. Always emit the call regardless.
95509548
// Tell the pseudo expansion using an additional boolean op.
9551-
SDValue DoEmitMarker = DAG.getTargetConstant(true, DL, MVT::i32);
9549+
bool ShouldEmitMarker = objcarc::attachedCallOpBundleNeedsMarker(CLI.CB);
9550+
SDValue DoEmitMarker =
9551+
DAG.getTargetConstant(ShouldEmitMarker, DL, MVT::i32);
95529552
Ops.insert(Ops.begin() + 2, DoEmitMarker);
95539553
} else if (CallConv == CallingConv::ARM64EC_Thunk_X64) {
95549554
Opc = AArch64ISD::CALL_ARM64EC_TO_X64;

llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,10 +1366,8 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
13661366
++CalleeOpNo;
13671367

13681368
// We may or may not need to emit both the marker and the retain/claim call.
1369-
// Do what the frontend tells us: if the rvmarker module flag is present,
1370-
// emit the marker. Always emit the call regardless.
13711369
// Tell the pseudo expansion using an additional boolean op.
1372-
MIB.addImm(true);
1370+
MIB.addImm(objcarc::attachedCallOpBundleNeedsMarker(Info.CB));
13731371
++CalleeOpNo;
13741372
} else if (Info.CFIType) {
13751373
MIB->setCFIType(MF, Info.CFIType->getZExtValue());

llvm/test/CodeGen/AArch64/call-rv-marker.ll

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,35 @@ define dso_local void @rv_marker_multiarg(i64 %a, i64 %b, i64 %c) {
544544
ret void
545545
}
546546

547+
define dso_local ptr @rv_marker_claim() {
548+
; SELDAG-LABEL: rv_marker_claim:
549+
; SELDAG: ; %bb.0: ; %entry
550+
; SELDAG-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill
551+
; SELDAG-NEXT: .cfi_def_cfa_offset 16
552+
; SELDAG-NEXT: .cfi_offset w30, -8
553+
; SELDAG-NEXT: .cfi_offset w29, -16
554+
; SELDAG-NEXT: bl _foo1
555+
; SELDAG-NEXT: bl _objc_claimAutoreleasedReturnValue
556+
; SELDAG-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
557+
; SELDAG-NEXT: ret
558+
;
559+
; GISEL-LABEL: rv_marker_claim:
560+
; GISEL: ; %bb.0: ; %entry
561+
; GISEL-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill
562+
; GISEL-NEXT: .cfi_def_cfa_offset 16
563+
; GISEL-NEXT: .cfi_offset w30, -8
564+
; GISEL-NEXT: .cfi_offset w29, -16
565+
; GISEL-NEXT: bl _foo1
566+
; GISEL-NEXT: bl _objc_claimAutoreleasedReturnValue
567+
; GISEL-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
568+
; GISEL-NEXT: ret
569+
entry:
570+
%call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_claimAutoreleasedReturnValue) ]
571+
ret ptr %call
572+
}
573+
547574
declare ptr @objc_retainAutoreleasedReturnValue(ptr)
575+
declare ptr @objc_claimAutoreleasedReturnValue(ptr)
548576
declare ptr @objc_unsafeClaimAutoreleasedReturnValue(ptr)
549577
declare i32 @__gxx_personality_v0(...)
550578
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:

0 commit comments

Comments
 (0)