Skip to content

Commit 53176c1

Browse files
committed
[ObjC][ARC] Annotate calls with attributes instead of emitting retainRV
or claimRV calls in the IR Background: This patch makes changes to the front-end and middle-end that are needed to fix 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 annotates calls with attribute "clang.arc.rv"="retain" or "clang.arc.rv"="claim", which indicates the call is implicitly followed by a marker instruction and a retainRV/claimRV call that consumes the call result. 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 annotated calls in the IR and removes the inserted calls after processing the function. - ARC contract pass emits retainRV/claimRV calls after the annotated calls. It doesn't remove the attribute on the call since the backend needs it to emit the marker instruction. The retainRV/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 the autoreleaseRV call in the callee that returns the result if nothing in the callee prevents it from being paired up with the calls annotated with "clang.arc.rv"="retain/claim" in the caller. If the call is annotated with "claim", a release call is inserted since autoreleaseRV+claimRV is equivalent to a release. If it cannot find an autoreleaseRV call, it tries to transfer the attributes to a function call in the callee. This is important since ARC optimizer can remove the autoreleaseRV call returning the callee result, which makes it impossible to pair it up with the retainRV or claimRV call in the caller. If that fails, it simply emits a retain call in the IR if the call is annotated with "retain" and does nothing if it's annotated with "claim". - This patch teaches dead argument elimination pass not to change the return type of a function if any of the calls to the function are annotated with attribute "clang.arc.rv". This is necessary since the pass can incorrectly determine nothing in the IR uses the function return, which can happen since the front-end no longer explicitly emits retainRV/claimRV calls in the IR, and change its return type to 'void'. Future work: - Use the attribute on x86-64. - Fix the auto upgrader to convert call+retainRV/claimRV pairs into calls annotated with the attributes. rdar://71443534 Differential Revision: https://reviews.llvm.org/D92808
1 parent 9d9ceb3 commit 53176c1

File tree

22 files changed

+938
-119
lines changed

22 files changed

+938
-119
lines changed

clang/lib/CodeGen/CGObjC.cpp

Lines changed: 44 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/ObjCARCRVAttr.h"
2627
#include "llvm/BinaryFormat/MachO.h"
2728
#include "llvm/IR/DataLayout.h"
2829
#include "llvm/IR/InlineAsm.h"
@@ -2304,10 +2305,11 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
23042305
// with this marker yet, so leave a breadcrumb for the ARC
23052306
// optimizer to pick up.
23062307
} else {
2307-
const char *markerKey = "clang.arc.retainAutoreleasedReturnValueMarker";
2308-
if (!CGF.CGM.getModule().getModuleFlag(markerKey)) {
2308+
const char *retainRVMarkerKey = llvm::objcarc::getRVMarkerModuleFlagStr();
2309+
if (!CGF.CGM.getModule().getModuleFlag(retainRVMarkerKey)) {
23092310
auto *str = llvm::MDString::get(CGF.getLLVMContext(), assembly);
2310-
CGF.CGM.getModule().addModuleFlag(llvm::Module::Error, markerKey, str);
2311+
CGF.CGM.getModule().addModuleFlag(llvm::Module::Error,
2312+
retainRVMarkerKey, str);
23112313
}
23122314
}
23132315
}
@@ -2317,22 +2319,51 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
23172319
CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker));
23182320
}
23192321

2322+
static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value,
2323+
bool IsRetainRV,
2324+
CodeGenFunction &CGF) {
2325+
emitAutoreleasedReturnValueMarker(CGF);
2326+
2327+
// Annotate the call with attributes instead of emitting retainRV or claimRV
2328+
// calls in the IR. We currently do this only when the optimization level
2329+
// isn't -O0 since global-isel, which is currently run at -O0, doesn't know
2330+
// about the attributes.
2331+
2332+
// FIXME: Do this when the target isn't aarch64.
2333+
if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 &&
2334+
CGF.CGM.getTarget().getTriple().isAArch64()) {
2335+
auto *callBase = cast<llvm::CallBase>(value);
2336+
llvm::AttributeList attrs = callBase->getAttributes();
2337+
attrs = attrs.addAttribute(CGF.getLLVMContext(),
2338+
llvm::AttributeList::ReturnIndex,
2339+
llvm::objcarc::getRVAttrKeyStr(),
2340+
llvm::objcarc::getRVAttrValStr(IsRetainRV));
2341+
callBase->setAttributes(attrs);
2342+
return callBase;
2343+
}
2344+
2345+
bool isNoTail =
2346+
CGF.CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail();
2347+
llvm::CallInst::TailCallKind tailKind =
2348+
isNoTail ? llvm::CallInst::TCK_NoTail : llvm::CallInst::TCK_None;
2349+
ObjCEntrypoints &EPs = CGF.CGM.getObjCEntrypoints();
2350+
llvm::Function *&EP = IsRetainRV
2351+
? EPs.objc_retainAutoreleasedReturnValue
2352+
: EPs.objc_unsafeClaimAutoreleasedReturnValue;
2353+
llvm::Intrinsic::ID IID =
2354+
IsRetainRV ? llvm::Intrinsic::objc_retainAutoreleasedReturnValue
2355+
: llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue;
2356+
return emitARCValueOperation(CGF, value, nullptr, EP, IID, tailKind);
2357+
}
2358+
23202359
/// Retain the given object which is the result of a function call.
23212360
/// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
23222361
///
23232362
/// Yes, this function name is one character away from a different
23242363
/// call with completely different semantics.
23252364
llvm::Value *
23262365
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);
2366+
return emitOptimizedARCReturnCall(value, true, *this);
23362367
}
23372368

23382369
/// Claim a possibly-autoreleased return value at +0. This is only
@@ -2344,15 +2375,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
23442375
/// call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
23452376
llvm::Value *
23462377
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);
2378+
return emitOptimizedARCReturnCall(value, false, *this);
23562379
}
23572380

23582381
/// Release the given object.

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

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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 "clang.arc.rv"="claim" [[A:.*]]* @makeA()
14+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
15+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
16+
// CHECK-NEXT: bitcast
17+
// CHECK-NEXT: lifetime.end
18+
// CHECK-NEXT: ret void
19+
20+
void test_assign_assign() {
21+
__unsafe_unretained id x, y;
22+
x = y = makeA();
23+
}
24+
// CHECK-LABEL: define{{.*}} void @test_assign_assign()
25+
// CHECK: [[X:%.*]] = alloca i8*
26+
// CHECK: [[Y:%.*]] = alloca i8*
27+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="claim" [[A]]* @makeA()
28+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
29+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
30+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
31+
// CHECK-NEXT: bitcast
32+
// CHECK-NEXT: lifetime.end
33+
// CHECK-NEXT: bitcast
34+
// CHECK-NEXT: lifetime.end
35+
// CHECK-NEXT: ret void
36+
37+
void test_strong_assign_assign() {
38+
__strong id x;
39+
__unsafe_unretained id y;
40+
x = y = makeA();
41+
}
42+
// CHECK-LABEL: define{{.*}} void @test_strong_assign_assign()
43+
// CHECK: [[X:%.*]] = alloca i8*
44+
// CHECK: [[Y:%.*]] = alloca i8*
45+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="retain" [[A]]* @makeA()
46+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
47+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
48+
// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]]
49+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
50+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]]
51+
// CHECK-NEXT: bitcast
52+
// CHECK-NEXT: lifetime.end
53+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
54+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
55+
// CHECK-NEXT: bitcast
56+
// CHECK-NEXT: lifetime.end
57+
// CHECK-NEXT: ret void
58+
59+
void test_assign_strong_assign() {
60+
__unsafe_unretained id x;
61+
__strong id y;
62+
x = y = makeA();
63+
}
64+
// CHECK-LABEL: define{{.*}} void @test_assign_strong_assign()
65+
// CHECK: [[X:%.*]] = alloca i8*
66+
// CHECK: [[Y:%.*]] = alloca i8*
67+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="retain" [[A]]* @makeA()
68+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
69+
// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[Y]]
70+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
71+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]]
72+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
73+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
74+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
75+
// CHECK-NEXT: bitcast
76+
// CHECK-NEXT: lifetime.end
77+
// CHECK-NEXT: bitcast
78+
// CHECK-NEXT: lifetime.end
79+
// CHECK-NEXT: ret void
80+
81+
void test_init() {
82+
__unsafe_unretained id x = makeA();
83+
}
84+
// CHECK-LABEL: define{{.*}} void @test_init()
85+
// CHECK: [[X:%.*]] = alloca i8*
86+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="claim" [[A]]* @makeA()
87+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
88+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
89+
// CHECK-NEXT: bitcast
90+
// CHECK-NEXT: lifetime.end
91+
// CHECK-NEXT: ret void
92+
93+
void test_init_assignment() {
94+
__unsafe_unretained id x;
95+
__unsafe_unretained id y = x = makeA();
96+
}
97+
// CHECK-LABEL: define{{.*}} void @test_init_assignment()
98+
// CHECK: [[X:%.*]] = alloca i8*
99+
// CHECK: [[Y:%.*]] = alloca i8*
100+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="claim" [[A]]* @makeA()
101+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
102+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
103+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
104+
// CHECK-NEXT: bitcast
105+
// CHECK-NEXT: lifetime.end
106+
// CHECK-NEXT: bitcast
107+
// CHECK-NEXT: lifetime.end
108+
// CHECK-NEXT: ret void
109+
110+
void test_strong_init_assignment() {
111+
__unsafe_unretained id x;
112+
__strong id y = x = makeA();
113+
}
114+
// CHECK-LABEL: define{{.*}} void @test_strong_init_assignment()
115+
// CHECK: [[X:%.*]] = alloca i8*
116+
// CHECK: [[Y:%.*]] = alloca i8*
117+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="retain" [[A]]* @makeA()
118+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
119+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
120+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
121+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
122+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
123+
// CHECK-NEXT: bitcast
124+
// CHECK-NEXT: lifetime.end
125+
// CHECK-NEXT: bitcast
126+
// CHECK-NEXT: lifetime.end
127+
// CHECK-NEXT: ret void
128+
129+
void test_init_strong_assignment() {
130+
__strong id x;
131+
__unsafe_unretained id y = x = makeA();
132+
}
133+
// CHECK-LABEL: define{{.*}} void @test_init_strong_assignment()
134+
// CHECK: [[X:%.*]] = alloca i8*
135+
// CHECK: [[Y:%.*]] = alloca i8*
136+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="retain" [[A]]* @makeA()
137+
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
138+
// CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]]
139+
// CHECK-NEXT: store i8* [[T1]], i8** [[X]]
140+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]])
141+
// CHECK-NEXT: store i8* [[T1]], i8** [[Y]]
142+
// CHECK-NEXT: bitcast
143+
// CHECK-NEXT: lifetime.end
144+
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
145+
// CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]])
146+
// CHECK-NEXT: bitcast
147+
// CHECK-NEXT: lifetime.end
148+
// CHECK-NEXT: ret void
149+
150+
void test_ignored() {
151+
makeA();
152+
}
153+
// CHECK-LABEL: define{{.*}} void @test_ignored()
154+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="claim" [[A]]* @makeA()
155+
// CHECK-NEXT: ret void
156+
157+
void test_cast_to_void() {
158+
(void) makeA();
159+
}
160+
// CHECK-LABEL: define{{.*}} void @test_cast_to_void()
161+
// CHECK: [[T0:%.*]] = call "clang.arc.rv"="claim" [[A]]* @makeA()
162+
// CHECK-NEXT: ret void
163+
164+
// This is always at the end of the module.
165+
166+
// CHECK-OPTIMIZED: !llvm.module.flags = !{!0,
167+
// 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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===- ObjCARCRVAttr.h - ObjC ARC Attribute Analysis ------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
/// This file defines functions which look for or remove attributes retainRV,
10+
/// claimRV, and rv_marker.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_LIB_ANALYSIS_OBJCARCRVATTR_H
15+
#define LLVM_LIB_ANALYSIS_OBJCARCRVATTR_H
16+
17+
#include "llvm/IR/InstrTypes.h"
18+
19+
namespace llvm {
20+
namespace objcarc {
21+
22+
static inline const char *getRVMarkerModuleFlagStr() {
23+
return "clang.arc.retainAutoreleasedReturnValueMarker";
24+
}
25+
26+
static inline const char *getRVAttrKeyStr() { return "clang.arc.rv"; }
27+
28+
static inline const char *getRVAttrValStr(bool Retain) {
29+
return Retain ? "retain" : "claim";
30+
}
31+
32+
static inline bool hasRetainRVAttr(const CallBase *CB) {
33+
return CB->getAttribute(llvm::AttributeList::ReturnIndex, getRVAttrKeyStr())
34+
.getValueAsString()
35+
.equals(getRVAttrValStr(true));
36+
}
37+
static inline bool hasClaimRVAttr(const CallBase *CB) {
38+
return CB->getAttribute(llvm::AttributeList::ReturnIndex, getRVAttrKeyStr())
39+
.getValueAsString()
40+
.equals(getRVAttrValStr(false));
41+
}
42+
43+
static inline bool hasRetainRVOrClaimRVAttr(const CallBase *CB) {
44+
return CB->hasRetAttr(getRVAttrKeyStr());
45+
}
46+
47+
static inline void removeRetainRVOrClaimRVAttr(CallBase *CB) {
48+
CB->removeAttribute(llvm::AttributeList::ReturnIndex, getRVAttrKeyStr());
49+
}
50+
51+
} // end namespace objcarc
52+
} // end namespace llvm
53+
54+
#endif

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414

1515
#include "llvm/IR/AutoUpgrade.h"
1616
#include "llvm/ADT/StringSwitch.h"
17+
#include "llvm/Analysis/ObjCARCRVAttr.h"
1718
#include "llvm/IR/Constants.h"
1819
#include "llvm/IR/DIBuilder.h"
1920
#include "llvm/IR/DebugInfo.h"
2021
#include "llvm/IR/DiagnosticInfo.h"
2122
#include "llvm/IR/Function.h"
2223
#include "llvm/IR/IRBuilder.h"
23-
#include "llvm/IR/Instruction.h"
2424
#include "llvm/IR/InstVisitor.h"
25+
#include "llvm/IR/Instruction.h"
2526
#include "llvm/IR/IntrinsicInst.h"
2627
#include "llvm/IR/Intrinsics.h"
2728
#include "llvm/IR/IntrinsicsAArch64.h"
@@ -3996,7 +3997,7 @@ bool llvm::UpgradeDebugInfo(Module &M) {
39963997
/// returns true if module is modified.
39973998
static bool UpgradeRetainReleaseMarker(Module &M) {
39983999
bool Changed = false;
3999-
const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker";
4000+
const char *MarkerKey = objcarc::getRVMarkerModuleFlagStr();
40004001
NamedMDNode *ModRetainReleaseMarker = M.getNamedMetadata(MarkerKey);
40014002
if (ModRetainReleaseMarker) {
40024003
MDNode *Op = ModRetainReleaseMarker->getOperand(0);

llvm/lib/IR/Instruction.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "llvm/IR/Instruction.h"
14-
#include "llvm/IR/IntrinsicInst.h"
1514
#include "llvm/ADT/DenseSet.h"
15+
#include "llvm/Analysis/ObjCARCRVAttr.h"
1616
#include "llvm/IR/Constants.h"
1717
#include "llvm/IR/Instructions.h"
18+
#include "llvm/IR/IntrinsicInst.h"
1819
#include "llvm/IR/MDBuilder.h"
1920
#include "llvm/IR/Operator.h"
2021
#include "llvm/IR/Type.h"
@@ -572,8 +573,13 @@ bool Instruction::mayWriteToMemory() const {
572573
return true;
573574
case Instruction::Call:
574575
case Instruction::Invoke:
575-
case Instruction::CallBr:
576-
return !cast<CallBase>(this)->onlyReadsMemory();
576+
case Instruction::CallBr: {
577+
if (!cast<CallBase>(this)->onlyReadsMemory())
578+
return true;
579+
if (auto *CB = dyn_cast<CallBase>(this))
580+
return objcarc::hasRetainRVOrClaimRVAttr(CB);
581+
return false;
582+
}
577583
case Instruction::Load:
578584
return !cast<LoadInst>(this)->isUnordered();
579585
}

0 commit comments

Comments
 (0)