summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorAkira Hatanaka <ahatanaka@apple.com>2017-04-28 18:50:57 +0000
committerAkira Hatanaka <ahatanaka@apple.com>2017-04-28 18:50:57 +0000
commita6b6dcc12384359b0e9a5843ec8e69ff3dc28009 (patch)
tree442e88773ef7214cc66949728e2c35031a589de4 /clang/lib
parent6652a52e2b208ad593ff562667142affaec4a7df (diff)
downloadbcm5719-llvm-a6b6dcc12384359b0e9a5843ec8e69ff3dc28009.tar.gz
bcm5719-llvm-a6b6dcc12384359b0e9a5843ec8e69ff3dc28009.zip
[CodeGen][ObjC] Don't retain captured Objective-C pointers at block
creation that are const-qualified. When a block captures an ObjC object pointer, clang retains the pointer to prevent prematurely destroying the object the pointer points to before the block is called or copied. When the captured object pointer is const-qualified, we can avoid emitting the retain/release pair since the pointer variable cannot be modified in the scope in which the block literal is introduced. For example: void test(const id x) { callee(^{ (void)x; }); } This patch implements that optimization. rdar://problem/28894510 Differential Revision: https://reviews.llvm.org/D32601 llvm-svn: 301667
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGBlocks.cpp14
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp6
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h1
3 files changed, 20 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index 1a57b3e6608..791a57e61f5 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -619,7 +619,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
// Block captures count as local values and have imprecise semantics.
// They also can't be arrays, so need to worry about that.
- if (dtorKind == QualType::DK_objc_strong_lifetime) {
+ //
+ // For const-qualified captures, emit clang.arc.use to ensure the captured
+ // object doesn't get released while we are still depending on its validity
+ // within the block.
+ if (VT.isConstQualified() && VT.getObjCLifetime() == Qualifiers::OCL_Strong)
+ destroyer = CodeGenFunction::emitARCIntrinsicUse;
+ else if (dtorKind == QualType::DK_objc_strong_lifetime) {
destroyer = CodeGenFunction::destroyARCStrongImprecise;
} else {
destroyer = CGF.getDestroyer(dtorKind);
@@ -866,6 +872,12 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} else if (type->isReferenceType()) {
Builder.CreateStore(src.getPointer(), blockField);
+ // If type is const-qualified, copy the value into the block field.
+ } else if (type.isConstQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ llvm::Value *value = Builder.CreateLoad(src, "captured");
+ Builder.CreateStore(value, blockField);
+
// If this is an ARC __strong block-pointer variable, don't do a
// block copy.
//
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 76e7df861f7..f4fbab3c2b8 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -2415,6 +2415,12 @@ void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
CGF.EmitARCDestroyWeak(addr);
}
+void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
+ QualType type) {
+ llvm::Value *value = CGF.Builder.CreateLoad(addr);
+ CGF.EmitARCIntrinsicUse(value);
+}
+
namespace {
struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token;
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 1ded824ba5b..f9bc4a1bc2d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3369,6 +3369,7 @@ public:
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
static Destroyer destroyARCWeak;
+ static Destroyer emitARCIntrinsicUse;
void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
llvm::Value *EmitObjCAutoreleasePoolPush();
OpenPOWER on IntegriCloud