]> granicus.if.org Git - clang/commitdiff
In ARC, peephole the initialization of a __weak variable with
authorJohn McCall <rjmccall@apple.com>
Wed, 21 Oct 2015 18:06:31 +0000 (18:06 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 21 Oct 2015 18:06:31 +0000 (18:06 +0000)
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

lib/CodeGen/CGDecl.cpp
test/CodeGenObjC/arc-blocks.m
test/CodeGenObjC/arc-foreach.m
test/CodeGenObjCXX/arc.mm

index 3cff635f94e4a7f0566321d35a0c3925080c9c31..fe80c8058baefb5d1e620c317d3195af51bbcc5d 100644 (file)
@@ -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<CastExpr>(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.
index e7bf01dbb0ea2ea21e28733f34f20b950d22d420..30f9271bd9dc663cd94303a4f2974dd64db63ec1 100644 (file)
@@ -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]])
index 17067a0a584e89c79cf46cb8b37555976d442ceb..90d9c1f126173c436eb0b03225c2a5a3e65e4535 100644 (file)
@@ -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]])
index 4ce59df3e0fdaed7bc10025a7bbc9591fae40fd3..e3a6349afaf020c021ce70aaa86bf4cb5d5a6f16 100644 (file)
@@ -324,3 +324,13 @@ template void test40_helper<int>();
 // 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]])