Skip to content

Commit ed4718e

Browse files
committed
[ObjC][ARC] Use operand bundle 'clang.arc.attachedcall' instead of
explicitly emitting retainRV or claimRV calls in the IR Background: This fixes a longstanding problem where llvm breaks ARC's autorelease optimization (see the link below) by separating calls from the marker instructions or retainRV/claimRV calls. The backend changes are in https://reviews.llvm.org/D92569. https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-runtime-objc-autoreleasereturnvalue What this patch does to fix the problem: - The front-end adds operand bundle "clang.arc.attachedcall" to calls, which indicates the call is implicitly followed by a marker instruction and an implicit retainRV/claimRV call that consumes the call result. In addition, it emits a call to @llvm.objc.clang.arc.noop.use, which consumes the call result, to prevent the middle-end passes from changing the return type of the called function. This is currently done only when the target is arm64 and the optimization level is higher than -O0. - ARC optimizer temporarily emits retainRV/claimRV calls after the calls with the operand bundle in the IR and removes the inserted calls after processing the function. - ARC contract pass emits retainRV/claimRV calls after the call with the operand bundle. It doesn't remove the operand bundle on the call since the backend needs it to emit the marker instruction. The retainRV and claimRV calls are emitted late in the pipeline to prevent optimization passes from transforming the IR in a way that makes it harder for the ARC middle-end passes to figure out the def-use relationship between the call and the retainRV/claimRV calls (which is the cause of PR31925). - The function inliner removes an autoreleaseRV call in the callee if nothing in the callee prevents it from being paired up with the retainRV/claimRV call in the caller. It then inserts a release call if claimRV is attached to the call since autoreleaseRV+claimRV is equivalent to a release. If it cannot find an autoreleaseRV call, it tries to transfer the operand bundle to a function call in the callee. This is important since the ARC optimizer can remove the autoreleaseRV returning the callee result, which makes it impossible to pair it up with the retainRV/claimRV call in the caller. If that fails, it simply emits a retain call in the IR if retainRV is attached to the call and does nothing if claimRV is attached to it. - SCCP refrains from replacing the return value of a call with a constant value if the call has the operand bundle. This ensures the call always has at least one user (the call to @llvm.objc.clang.arc.noop.use). - This patch also fixes a bug in replaceUsesOfNonProtoConstant where multiple operand bundles of the same kind were being added to a call. Future work: - Use the operand bundle on x86-64. - Fix the auto upgrader to convert call+retainRV/claimRV pairs into calls with the operand bundles. rdar://71443534 Differential Revision: https://reviews.llvm.org/D92808
1 parent 81b1d3d commit ed4718e

40 files changed

+1191
-162
lines changed

clang/lib/CodeGen/CGObjC.cpp

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/Basic/Diagnostic.h"
2424
#include "clang/CodeGen/CGFunctionInfo.h"
2525
#include "llvm/ADT/STLExtras.h"
26+
#include "llvm/Analysis/ObjCARCUtil.h"
2627
#include "llvm/BinaryFormat/MachO.h"
2728
#include "llvm/IR/DataLayout.h"
2829
#include "llvm/IR/InlineAsm.h"
@@ -2078,6 +2079,15 @@ void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
20782079
EmitNounwindRuntimeCall(fn, values);
20792080
}
20802081

2082+
/// Emit a call to "clang.arc.noop.use", which consumes the result of a call
2083+
/// that has operand bundle "clang.arc.attachedcall".
2084+
void CodeGenFunction::EmitARCNoopIntrinsicUse(ArrayRef<llvm::Value *> values) {
2085+
llvm::Function *&fn = CGM.getObjCEntrypoints().clang_arc_noop_use;
2086+
if (!fn)
2087+
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_noop_use);
2088+
EmitNounwindRuntimeCall(fn, values);
2089+
}
2090+
20812091
static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM, llvm::Value *RTF) {
20822092
if (auto *F = dyn_cast<llvm::Function>(RTF)) {
20832093
// If the target runtime doesn't naturally support ARC, emit weak
@@ -2304,10 +2314,11 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
23042314
// with this marker yet, so leave a breadcrumb for the ARC
23052315
// optimizer to pick up.
23062316
} else {
2307-
const char *markerKey = "clang.arc.retainAutoreleasedReturnValueMarker";
2308-
if (!CGF.CGM.getModule().getModuleFlag(markerKey)) {
2317+
const char *retainRVMarkerKey = llvm::objcarc::getRVMarkerModuleFlagStr();
2318+
if (!CGF.CGM.getModule().getModuleFlag(retainRVMarkerKey)) {
23092319
auto *str = llvm::MDString::get(CGF.getLLVMContext(), assembly);
2310-
CGF.CGM.getModule().addModuleFlag(llvm::Module::Error, markerKey, str);
2320+
CGF.CGM.getModule().addModuleFlag(llvm::Module::Error,
2321+
retainRVMarkerKey, str);
23112322
}
23122323
}
23132324
}
@@ -2317,22 +2328,55 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
23172328
CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker));
23182329
}
23192330

2331+
static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value,
2332+
bool IsRetainRV,
2333+
CodeGenFunction &CGF) {
2334+
emitAutoreleasedReturnValueMarker(CGF);
2335+
2336+
// Add operand bundle "clang.arc.attachedcall" to the call instead of emitting
2337+
// retainRV or claimRV calls in the IR. We currently do this only when the
2338+
// optimization level isn't -O0 since global-isel, which is currently run at
2339+
// -O0, doesn't know about the operand bundle.
2340+
2341+
// FIXME: Do this when the target isn't aarch64.
2342+
if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 &&
2343+
CGF.CGM.getTarget().getTriple().isAArch64()) {
2344+
llvm::Value *bundleArgs[] = {llvm::ConstantInt::get(
2345+
CGF.Int64Ty,
2346+
llvm::objcarc::getAttachedCallOperandBundleEnum(IsRetainRV))};
2347+
llvm::OperandBundleDef OB("clang.arc.attachedcall", bundleArgs);
2348+
auto *oldCall = cast<llvm::CallBase>(value);
2349+
llvm::CallBase *newCall = llvm::CallBase::addOperandBundle(
2350+
oldCall, llvm::LLVMContext::OB_clang_arc_attachedcall, OB, oldCall);
2351+
newCall->copyMetadata(*oldCall);
2352+
oldCall->replaceAllUsesWith(newCall);
2353+
oldCall->eraseFromParent();
2354+
CGF.EmitARCNoopIntrinsicUse(newCall);
2355+
return newCall;
2356+
}
2357+
2358+
bool isNoTail =
2359+
CGF.CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail();
2360+
llvm::CallInst::TailCallKind tailKind =
2361+
isNoTail ? llvm::CallInst::TCK_NoTail : llvm::CallInst::TCK_None;
2362+
ObjCEntrypoints &EPs = CGF.CGM.getObjCEntrypoints();
2363+
llvm::Function *&EP = IsRetainRV
2364+
? EPs.objc_retainAutoreleasedReturnValue
2365+
: EPs.objc_unsafeClaimAutoreleasedReturnValue;
2366+
llvm::Intrinsic::ID IID =
2367+
IsRetainRV ? llvm::Intrinsic::objc_retainAutoreleasedReturnValue
2368+
: llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue;
2369+
return emitARCValueOperation(CGF, value, nullptr, EP, IID, tailKind);
2370+
}
2371+
23202372
/// Retain the given object which is the result of a function call.
23212373
/// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
23222374
///
23232375
/// Yes, this function name is one character away from a different
23242376
/// call with completely different semantics.
23252377
llvm::Value *
23262378
CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
2327-
emitAutoreleasedReturnValueMarker(*this);
2328-
llvm::CallInst::TailCallKind tailKind =
2329-
CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail()
2330-
? llvm::CallInst::TCK_NoTail
2331-
: llvm::CallInst::TCK_None;
2332-
return emitARCValueOperation(
2333-
*this, value, nullptr,
2334-
CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
2335-
llvm::Intrinsic::objc_retainAutoreleasedReturnValue, tailKind);
2379+
return emitOptimizedARCReturnCall(value, true, *this);
23362380
}
23372381

23382382
/// Claim a possibly-autoreleased return value at +0. This is only
@@ -2344,15 +2388,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
23442388
/// call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
23452389
llvm::Value *
23462390
CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
2347-
emitAutoreleasedReturnValueMarker(*this);
2348-
llvm::CallInst::TailCallKind tailKind =
2349-
CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail()
2350-
? llvm::CallInst::TCK_NoTail
2351-
: llvm::CallInst::TCK_None;
2352-
return emitARCValueOperation(
2353-
*this, value, nullptr,
2354-
CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
2355-
llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue, tailKind);
2391+
return emitOptimizedARCReturnCall(value, false, *this);
23562392
}
23572393

23582394
/// Release the given object.

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4202,6 +4202,8 @@ class CodeGenFunction : public CodeGenTypeCache {
42024202

42034203
void EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values);
42044204

4205+
void EmitARCNoopIntrinsicUse(ArrayRef<llvm::Value *> values);
4206+
42054207
static Destroyer destroyARCStrongImprecise;
42064208
static Destroyer destroyARCStrongPrecise;
42074209
static Destroyer destroyARCWeak;

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4535,7 +4535,6 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
45354535

45364536
llvm::Type *newRetTy = newFn->getReturnType();
45374537
SmallVector<llvm::Value*, 4> newArgs;
4538-
SmallVector<llvm::OperandBundleDef, 1> newBundles;
45394538

45404539
for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end();
45414540
ui != ue; ) {
@@ -4592,6 +4591,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
45924591
newArgs.append(callSite->arg_begin(), callSite->arg_begin() + argNo);
45934592

45944593
// Copy over any operand bundles.
4594+
SmallVector<llvm::OperandBundleDef, 1> newBundles;
45954595
callSite->getOperandBundlesAsDefs(newBundles);
45964596

45974597
llvm::CallBase *newCall;

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ struct ObjCEntrypoints {
210210

211211
/// void clang.arc.use(...);
212212
llvm::Function *clang_arc_use;
213+
214+
/// void clang.arc.noop.use(...);
215+
llvm::Function *clang_arc_noop_use;
213216
};
214217

215218
/// This class records statistics on instrumentation based profiling.

clang/test/CodeGenObjC/arc-rv-attr.m

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK
2+
3+
@class A;
4+
5+
A *makeA(void);
6+
7+
void test_assign() {
8+
__unsafe_unretained id x;
9+
x = makeA();
10+
}
11+
// CHECK-LABEL: define{{.*}} void @test_assign()
12+
// CHECK: [[X:%.*]] = alloca i8*
13+
// CHECK: [[T0:%.*]] = call [[A:.*]]* @makeA() [ "clang.arc.attachedcall"(i64 1) ]
14+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
15+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
16+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
17+
// CHECK-NEXT: bitcast
18+
// CHECK-NEXT: lifetime.end
19+
// CHECK-NEXT: ret void
20+
21+
void test_assign_assign() {
22+
__unsafe_unretained id x, y;
23+
x = y = makeA();
24+
}
25+
// CHECK-LABEL: define{{.*}} void @test_assign_assign()
26+
// CHECK: [[X:%.*]] = alloca i8*
27+
// CHECK: [[Y:%.*]] = alloca i8*
28+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 1) ]
29+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
30+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
31+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
32+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
33+
// CHECK-NEXT: bitcast
34+
// CHECK-NEXT: lifetime.end
35+
// CHECK-NEXT: bitcast
36+
// CHECK-NEXT: lifetime.end
37+
// CHECK-NEXT: ret void
38+
39+
void test_strong_assign_assign() {
40+
__strong id x;
41+
__unsafe_unretained id y;
42+
x = y = makeA();
43+
}
44+
// CHECK-LABEL: define{{.*}} void @test_strong_assign_assign()
45+
// CHECK: [[X:%.*]] = alloca i8*
46+
// CHECK: [[Y:%.*]] = alloca i8*
47+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 0) ]
48+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
49+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
50+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
51+
// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]]
52+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
53+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]]
54+
// CHECK-NEXT: bitcast
55+
// CHECK-NEXT: lifetime.end
56+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
57+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
58+
// CHECK-NEXT: bitcast
59+
// CHECK-NEXT: lifetime.end
60+
// CHECK-NEXT: ret void
61+
62+
void test_assign_strong_assign() {
63+
__unsafe_unretained id x;
64+
__strong id y;
65+
x = y = makeA();
66+
}
67+
// CHECK-LABEL: define{{.*}} void @test_assign_strong_assign()
68+
// CHECK: [[X:%.*]] = alloca i8*
69+
// CHECK: [[Y:%.*]] = alloca i8*
70+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 0) ]
71+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
72+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
73+
// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[Y]]
74+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
75+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]]
76+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
77+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
78+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
79+
// CHECK-NEXT: bitcast
80+
// CHECK-NEXT: lifetime.end
81+
// CHECK-NEXT: bitcast
82+
// CHECK-NEXT: lifetime.end
83+
// CHECK-NEXT: ret void
84+
85+
void test_init() {
86+
__unsafe_unretained id x = makeA();
87+
}
88+
// CHECK-LABEL: define{{.*}} void @test_init()
89+
// CHECK: [[X:%.*]] = alloca i8*
90+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 1) ]
91+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
92+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
93+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
94+
// CHECK-NEXT: bitcast
95+
// CHECK-NEXT: lifetime.end
96+
// CHECK-NEXT: ret void
97+
98+
void test_init_assignment() {
99+
__unsafe_unretained id x;
100+
__unsafe_unretained id y = x = makeA();
101+
}
102+
// CHECK-LABEL: define{{.*}} void @test_init_assignment()
103+
// CHECK: [[X:%.*]] = alloca i8*
104+
// CHECK: [[Y:%.*]] = alloca i8*
105+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 1) ]
106+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
107+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
108+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
109+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
110+
// CHECK-NEXT: bitcast
111+
// CHECK-NEXT: lifetime.end
112+
// CHECK-NEXT: bitcast
113+
// CHECK-NEXT: lifetime.end
114+
// CHECK-NEXT: ret void
115+
116+
void test_strong_init_assignment() {
117+
__unsafe_unretained id x;
118+
__strong id y = x = makeA();
119+
}
120+
// CHECK-LABEL: define{{.*}} void @test_strong_init_assignment()
121+
// CHECK: [[X:%.*]] = alloca i8*
122+
// CHECK: [[Y:%.*]] = alloca i8*
123+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 0) ]
124+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
125+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
126+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
127+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
128+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
129+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
130+
// CHECK-NEXT: bitcast
131+
// CHECK-NEXT: lifetime.end
132+
// CHECK-NEXT: bitcast
133+
// CHECK-NEXT: lifetime.end
134+
// CHECK-NEXT: ret void
135+
136+
void test_init_strong_assignment() {
137+
__strong id x;
138+
__unsafe_unretained id y = x = makeA();
139+
}
140+
// CHECK-LABEL: define{{.*}} void @test_init_strong_assignment()
141+
// CHECK: [[X:%.*]] = alloca i8*
142+
// CHECK: [[Y:%.*]] = alloca i8*
143+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 0) ]
144+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
145+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
146+
// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]]
147+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
148+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]])
149+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
150+
// CHECK-NEXT: bitcast
151+
// CHECK-NEXT: lifetime.end
152+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
153+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
154+
// CHECK-NEXT: bitcast
155+
// CHECK-NEXT: lifetime.end
156+
// CHECK-NEXT: ret void
157+
158+
void test_ignored() {
159+
makeA();
160+
}
161+
// CHECK-LABEL: define{{.*}} void @test_ignored()
162+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 1) ]
163+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
164+
// CHECK-NEXT: ret void
165+
166+
void test_cast_to_void() {
167+
(void) makeA();
168+
}
169+
// CHECK-LABEL: define{{.*}} void @test_cast_to_void()
170+
// CHECK: [[T0:%.*]] = call [[A]]* @makeA() [ "clang.arc.attachedcall"(i64 1) ]
171+
// CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use({{.*}} [[T0]])
172+
// CHECK-NEXT: ret void
173+
174+
// This is always at the end of the module.
175+
176+
// CHECK-OPTIMIZED: !llvm.module.flags = !{!0,
177+
// CHECK-OPTIMIZED: !0 = !{i32 1, !"clang.arc.retainAutoreleasedReturnValueMarker", !"mov{{.*}}marker for objc_retainAutoreleaseReturnValue"}

clang/test/CodeGenObjC/arc-unsafeclaim.m

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
// Make sure it works on x86-32.
55
// RUN: %clang_cc1 -triple i386-apple-darwin11 -fobjc-runtime=macosx-fragile-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -check-prefix=CALL
66

7-
// Make sure it works on ARM.
7+
// Make sure it works on ARM64.
88
// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -check-prefix=CALL
9-
// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED -check-prefix=CALL
109

11-
// Make sure it works on ARM64.
10+
// Make sure it works on ARM.
1211
// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -check-prefix=CALL
1312
// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED -check-prefix=CALL
1413

llvm/docs/LangRef.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,19 @@ When lowered, any relocated value will be recorded in the corresponding
23252325
:ref:`stackmap entry <statepoint-stackmap-format>`. See the intrinsic description
23262326
for further details.
23272327

2328+
ObjC ARC Attached Call Operand Bundles
2329+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2330+
2331+
A ``"clang.arc.attachedcall`` operand bundle on a call indicates the call is
2332+
implicitly followed by a marker instruction and a call to an ObjC runtime
2333+
function that uses the result of the call. If the argument passed to the operand
2334+
bundle is 0, ``@objc_retainAutoreleasedReturnValue`` is called. If 1 is passed,
2335+
``@objc_unsafeClaimAutoreleasedReturnValue`` is called. A call with this bundle
2336+
implicitly uses its return value.
2337+
2338+
The operand bundle is needed to ensure the call is immediately followed by the
2339+
marker instruction or the ObjC runtime call in the final output.
2340+
23282341
.. _moduleasm:
23292342

23302343
Module-Level Inline Assembly

0 commit comments

Comments
 (0)