From: John McCall Date: Wed, 21 Oct 2015 18:06:31 +0000 (+0000) Subject: In ARC, peephole the initialization of a __weak variable with X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4673434589b49bc514150f00391673c8c15967f9;p=clang In ARC, peephole the initialization of a __weak variable with a value loaded from a __weak variable into a call to objc_copyWeak or objc_moveWeak. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@250916 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 3cff635f94..fe80c8058b 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -597,6 +597,47 @@ static bool isAccessedBy(const ValueDecl *decl, const Expr *e) { return isAccessedBy(*var, e); } +static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF, + const LValue &destLV, const Expr *init) { + while (auto castExpr = dyn_cast(init->IgnoreParens())) { + switch (castExpr->getCastKind()) { + // Look through casts that don't require representation changes. + case CK_NoOp: + case CK_BitCast: + case CK_BlockPointerToObjCPointerCast: + break; + + // If we find an l-value to r-value cast from a __weak variable, + // emit this operation as a copy or move. + case CK_LValueToRValue: { + const Expr *srcExpr = castExpr->getSubExpr(); + if (srcExpr->getType().getObjCLifetime() != Qualifiers::OCL_Weak) + return false; + + // Emit the source l-value. + LValue srcLV = CGF.EmitLValue(srcExpr); + + // If it was an l-value, use objc_copyWeak. + if (srcExpr->getValueKind() == VK_LValue) { + CGF.EmitARCCopyWeak(destLV.getAddress(), srcLV.getAddress()); + } else { + assert(srcExpr->getValueKind() == VK_XValue); + CGF.EmitARCMoveWeak(destLV.getAddress(), srcLV.getAddress()); + } + return true; + } + + // Stop at anything else. + default: + return false; + } + + init = castExpr->getSubExpr(); + continue; + } + return false; +} + static void drillIntoBlockVariable(CodeGenFunction &CGF, LValue &lvalue, const VarDecl *var) { @@ -673,6 +714,12 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, } case Qualifiers::OCL_Weak: { + // If it's not accessed by the initializer, try to emit the + // initialization with a copy or move. + if (!accessedByInit && tryEmitARCCopyWeakInit(*this, lvalue, init)) { + return; + } + // No way to optimize a producing initializer into this. It's not // worth optimizing for, because the value will immediately // disappear in the common case. diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m index e7bf01dbb0..30f9271bd9 100644 --- a/test/CodeGenObjC/arc-blocks.m +++ b/test/CodeGenObjC/arc-blocks.m @@ -263,8 +263,7 @@ void test7(void) { // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT // CHECK: store i32 -1040187392, // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 - // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[VAR]]) - // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]]) + // CHECK-NEXT: call void @objc_copyWeak(i8** [[SLOT]], i8** [[VAR]]) // CHECK: call void @test7_helper( // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}}) // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]]) diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index 17067a0a58..90d9c1f126 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -110,9 +110,7 @@ void test1(NSArray *array) { // CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 -// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]]) -// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]]) -// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]]) +// CHECK-LP64-NEXT: call void @objc_copyWeak(i8** [[T0]], i8** [[X]]) // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to // CHECK-LP64: call void @use_block // CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[D0]]) diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm index 4ce59df3e0..e3a6349afa 100644 --- a/test/CodeGenObjCXX/arc.mm +++ b/test/CodeGenObjCXX/arc.mm @@ -324,3 +324,13 @@ template void test40_helper(); // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[TEMP]] // CHECK-NEXT: call i8* @objc_retain(i8* [[T0]]) +// Check that moves out of __weak variables are compiled to use objc_moveWeak. +void test41(__weak id &&x) { + __weak id y = static_cast<__weak id &&>(x); +} +// CHECK-LABEL: define void @_Z6test41OU6__weakP11objc_object +// CHECK: [[X:%.*]] = alloca i8** +// CHECK: [[Y:%.*]] = alloca i8* +// CHECK: [[T0:%.*]] = load i8**, i8*** [[X]] +// CHECK-NEXT: call void @objc_moveWeak(i8** [[Y]], i8** [[T0]]) +// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Y]])