From b79274c2f9e7403d7e257ac98b663550b63023b3 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 18 Feb 2011 02:58:31 +0000 Subject: [PATCH] The flags we're supposed to write into a byref struct are *not* the _Block_object_* flags; it's just BLOCK_HAS_COPY_DISPOSE or not. Also, we don't need to chase forwarding pointers prior to calling _Block_object_dispose; _Block_object_dispose in fact already does this. rdar://problem/9006315 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125823 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDecl.cpp | 25 ++++++++++---------- test/CodeGenObjC/blocks-2.m | 8 ++----- test/CodeGenObjC/blocks.m | 56 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 22f28197c..a87dfaed9 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -504,9 +504,7 @@ namespace { CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {} void Emit(CodeGenFunction &CGF, bool IsForEH) { - llvm::Value *V = CGF.Builder.CreateStructGEP(Addr, 1, "forwarding"); - V = CGF.Builder.CreateLoad(V); - CGF.BuildBlockRelease(V, BLOCK_FIELD_IS_BYREF); + CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF); } }; } @@ -743,10 +741,6 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D, if (isByRef) { EnsureInsertPoint(); - llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0); - llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1); - llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2); - llvm::Value *size_field = Builder.CreateStructGEP(DeclPtr, 3); llvm::Value *V; BlockFieldFlags fieldFlags; @@ -776,16 +770,23 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D, if (fieldFlags & BLOCK_FIELD_IS_WEAK) isa = 1; V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa"); - Builder.CreateStore(V, isa_field); + Builder.CreateStore(V, Builder.CreateStructGEP(DeclPtr, 0, "byref.isa")); - Builder.CreateStore(DeclPtr, forwarding_field); + Builder.CreateStore(DeclPtr, Builder.CreateStructGEP(DeclPtr, 1, + "byref.forwarding")); - Builder.CreateStore(Builder.getInt32(fieldFlags.getBitMask()), flags_field); + // Blocks ABI: + // c) the flags field is set to either 0 if no helper functions are + // needed or BLOCK_HAS_COPY_DISPOSE if they are, + BlockFlags flags; + if (fieldNeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; + Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()), + Builder.CreateStructGEP(DeclPtr, 2, "byref.flags")); const llvm::Type *V1; V1 = cast(DeclPtr->getType())->getElementType(); - V = Builder.getInt32(CGM.GetTargetTypeStoreSize(V1).getQuantity()); - Builder.CreateStore(V, size_field); + V = llvm::ConstantInt::get(IntTy, CGM.GetTargetTypeStoreSize(V1).getQuantity()); + Builder.CreateStore(V, Builder.CreateStructGEP(DeclPtr, 3, "byref.size")); if (fieldNeedsCopyDispose) { llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4); diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m index 8754ff7c3..38b863560 100644 --- a/test/CodeGenObjC/blocks-2.m +++ b/test/CodeGenObjC/blocks-2.m @@ -26,16 +26,12 @@ void test1() { // CHECK: invoke void @{{.*}}test1_help test1_help(^{ n = 20; }); - // CHECK: [[FORWARDING:%.*]] = getelementptr inbounds [[N_T]]* [[N]], i32 0, i32 1 - // CHECK-NEXT: [[T0:%.*]] = load [[N_T]]** [[FORWARDING]] - // CHECK-NEXT: [[T1:%.*]] = bitcast [[N_T]]* [[T0]] to i8* + // CHECK: [[T1:%.*]] = bitcast [[N_T]]* [[N]] to i8* // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8) // CHECK-NEXT: ret void // CHECK: call i8* @llvm.eh.exception() - // CHECK: [[FORWARDING:%.*]] = getelementptr inbounds [[N_T]]* [[N]], i32 0, i32 1 - // CHECK-NEXT: [[T0:%.*]] = load [[N_T]]** [[FORWARDING]] - // CHECK-NEXT: [[T1:%.*]] = bitcast [[N_T]]* [[T0]] to i8* + // CHECK: [[T1:%.*]] = bitcast [[N_T]]* [[N]] to i8* // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8) // CHECK: call void @_Unwind_Resume_or_Rethrow( } diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m index b96a8d942..11fb55b58 100644 --- a/test/CodeGenObjC/blocks.m +++ b/test/CodeGenObjC/blocks.m @@ -1,13 +1,12 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -fblocks -o %t %s -// rdar://6676764 +// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -fblocks -o - %s | FileCheck %s +// test1. All of this is somehow testing rdar://6676764 struct S { void (^F)(struct S*); } P; @interface T - - (int)foo: (T (^)(T*)) x; @end @@ -19,7 +18,7 @@ void foo(T *P) { -(void) im0; @end -// RUN: grep 'define internal i32 @"__8-\[A im0\]_block_invoke_0"' %t +// CHECK: define internal i32 @"__8-[A im0]_block_invoke_0"( @implementation A -(void) im0 { (void) ^{ return 1; }(); @@ -39,3 +38,52 @@ void foo(T *P) { } @end +// rdar://problem/9006315 +// In-depth test for the initialization of a __weak __block variable. +@interface Test2 -(void) destroy; @end +void test2(Test2 *x) { + extern void test2_helper(void (^)(void)); + // CHECK: define void @test2( + // CHECK: [[X:%.*]] = alloca [[TEST2:%.*]]*, + // CHECK-NEXT: [[WEAKX:%.*]] = alloca [[WEAK_T:%.*]], + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]], + // CHECK-NEXT: store [[TEST2]]* + + // isa=1 for weak byrefs. + // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 0 + // CHECK-NEXT: store i8* inttoptr (i32 1 to i8*), i8** [[T0]] + + // Forwarding. + // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 1 + // CHECK-NEXT: store [[WEAK_T]]* [[WEAKX]], [[WEAK_T]]** [[T1]] + + // Flags. This is just BLOCK_HAS_COPY_DISPOSE. + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 2 + // CHECK-NEXT: store i32 33554432, i32* [[T2]] + + // Size. + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 3 + // CHECK-NEXT: store i32 28, i32* [[T3]] + + // Copy and dipose helpers. + // CHECK-NEXT: [[T4:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 4 + // CHECK-NEXT: store i8* bitcast (void (i8*, i8*)* @__Block_byref_object_copy_{{.*}} to i8*), i8** [[T4]] + // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 5 + // CHECK-NEXT: store i8* bitcast (void (i8*)* @__Block_byref_object_dispose_{{.*}} to i8*), i8** [[T5]] + + // Actually capture the value. + // CHECK-NEXT: [[CAPTURE:%.*]] = load [[TEST2]]** [[X]] + // CHECK-NEXT: [[T6:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 6 + // CHECK-NEXT: store [[TEST2]]* [[CAPTURE]], [[TEST2]]** [[T6]] + + // Then we initialize the block, blah blah blah. + // CHECK: call void @test2_helper( + + // Finally, kill the variable with BLOCK_FIELD_IS_BYREF. We're not + // supposed to pass BLOCK_FIELD_IS_WEAK here. + // CHECK: [[T0:%.*]] = bitcast [[WEAK_T]]* [[WEAKX]] to i8* + // CHECK: call void @_Block_object_dispose(i8* [[T0]], i32 8) + + __weak __block Test2 *weakX = x; + test2_helper(^{ [weakX destroy]; }); +} -- 2.11.4.GIT