[cfe-commits] r136337 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGObjC.cpp test/CodeGenObjC/arc.m test/CodeGenObjCXX/arc-special-member-functions.mm
John McCall
rjmccall at apple.com
Thu Jul 28 00:23:35 PDT 2011
Author: rjmccall
Date: Thu Jul 28 02:23:35 2011
New Revision: 136337
URL: http://llvm.org/viewvc/llvm-project?rev=136337&view=rev
Log:
Fix a couple of problems with initialization and assignment to
__block variables where the act of initialization/assignment
itself causes the __block variable to be copied to the heap
because the variable is of block type and is being assigned
a block literal which captures the variable.
rdar://problem/9814099
Modified:
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CGObjC.cpp
cfe/trunk/test/CodeGenObjC/arc.m
cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=136337&r1=136336&r2=136337&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Thu Jul 28 02:23:35 2011
@@ -507,7 +507,7 @@
// actually perform the initialization with an assign.
bool accessedByInit = false;
if (lifetime != Qualifiers::OCL_ExplicitNone)
- accessedByInit = isAccessedBy(D, init);
+ accessedByInit = (capturedByInit || isAccessedBy(D, init));
if (accessedByInit) {
LValue tempLV = lvalue;
// Drill down to the __block object if necessary.
Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=136337&r1=136336&r2=136337&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Thu Jul 28 02:23:35 2011
@@ -2144,10 +2144,20 @@
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
llvm::Value *value = result.getPointer();
+ bool hasImmediateRetain = result.getInt();
+
+ // If we didn't emit a retained object, and the l-value is of block
+ // type, then we need to emit the block-retain immediately in case
+ // it invalidates the l-value.
+ if (!hasImmediateRetain && e->getType()->isBlockPointerType()) {
+ value = EmitARCRetainBlock(value);
+ hasImmediateRetain = true;
+ }
+
LValue lvalue = EmitLValue(e->getLHS());
// If the RHS was emitted retained, expand this.
- if (result.getInt()) {
+ if (hasImmediateRetain) {
llvm::Value *oldValue =
EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(),
lvalue.getAlignment(), e->getType(),
Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=136337&r1=136336&r2=136337&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Thu Jul 28 02:23:35 2011
@@ -1684,3 +1684,73 @@
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: ret void
}
+
+// rdar://problem/9814099
+// Test that we correctly initialize __block variables
+// when the initialization captures the variable.
+void test60a(void) {
+ __block void (^block)(void) = ^{ block(); };
+ // CHECK: define void @test60a()
+ // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
+
+ // Zero-initialization before running the initializer.
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
+
+ // Run the initializer as an assignment.
+ // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
+ // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
+ // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
+ // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
+ // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T7]])
+
+ // Destroy at end of function.
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: ret void
+}
+
+// Test that we correctly assign to __block variables when the
+// assignment captures the variable.
+void test60b(void) {
+ __block void (^block)(void);
+ block = ^{ block(); };
+
+ // CHECK: define void @test60b()
+ // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
+
+ // Zero-initialize.
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
+
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+
+ // The assignment.
+ // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
+ // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
+ // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
+ // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
+ // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T7]])
+
+ // Destroy at end of function.
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: ret void
+}
Modified: cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm?rev=136337&r1=136336&r2=136337&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm Thu Jul 28 02:23:35 2011
@@ -92,12 +92,16 @@
// Implicitly-generated copy assignment operator for ObjCBlockMember
// CHECK: define linkonce_odr {{%.*}}* @_ZN15ObjCBlockMemberaSERKS_(
-// CHECK: [[T0:%.*]] = call i8* @objc_retainBlock(
-// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32 (i32)*
-// CHECK-NEXT: [[T2:%.*]] = load {{.*}} [[SLOT:%.*]],
-// CHECK: store
-// CHECK-NEXT: [[T3:%.*]] = bitcast
-// CHECK-NEXT: call void @objc_release(i8* [[T3]])
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[T:%.*]]* {{%.*}}, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = load i32 (i32)** [[T0]], align 8
+// CHECK-NEXT: [[T2:%.*]] = bitcast i32 (i32)* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainBlock(i8* [[T2]])
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i32 (i32)*
+// CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[T]]* {{%.*}}, i32 0, i32 0
+// CHECK-NEXT: [[T6:%.*]] = load i32 (i32)** [[T5]], align 8
+// CHECK-NEXT: store i32 (i32)* [[T4]], i32 (i32)** [[T5]]
+// CHECK-NEXT: [[T7:%.*]] = bitcast i32 (i32)* [[T6]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T7]])
// CHECK-NEXT: ret
// Implicitly-generated copy constructor for ObjCBlockMember
More information about the cfe-commits
mailing list