From e68b8f4dcc2b3a6ab03326ad4167f1164cae61e4 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 17 Oct 2012 02:28:37 +0000 Subject: [PATCH] At -O0, prefer objc_storeStrong with a null new value to the combination of a load+objc_release; this is generally better for tools that try to track why values are retained and released. Also use objc_storeStrong when copying a block (again, only at -O0), which requires us to do a preliminary store of null in order to compensate for objc_storeStrong's assign semantics. llvm-svn: 166085 --- clang/lib/CodeGen/CGBlocks.cpp | 90 +++++++++++++------ clang/lib/CodeGen/CGObjC.cpp | 28 +++++- clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/test/CodeGenObjC/arc-arm.m | 3 +- clang/test/CodeGenObjC/arc-blocks.m | 60 ++++++++++++- clang/test/CodeGenObjC/arc-exceptions.m | 5 +- clang/test/CodeGenObjC/arc-foreach.m | 8 +- clang/test/CodeGenObjC/arc-no-runtime.m | 4 + clang/test/CodeGenObjC/arc-property.m | 4 +- .../CodeGenObjC/arc-related-result-type.m | 10 +-- .../objc-arc-container-subscripting.m | 5 +- clang/test/CodeGenObjCXX/arc-exceptions.mm | 10 +-- clang/test/CodeGenObjCXX/arc-new-delete.mm | 5 +- .../arc-special-member-functions.mm | 7 +- 14 files changed, 176 insertions(+), 64 deletions(-) diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 33f4bf167032..b178f5eac1eb 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -1241,7 +1241,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { const Expr *copyExpr = ci->getCopyExpr(); BlockFieldFlags flags; - bool isARCWeakCapture = false; + bool useARCWeakCopy = false; + bool useARCStrongCopy = false; if (copyExpr) { assert(!ci->isByRef()); @@ -1254,21 +1255,35 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { } else if (type->isObjCRetainableType()) { flags = BLOCK_FIELD_IS_OBJECT; - if (type->isBlockPointerType()) + bool isBlockPointer = type->isBlockPointerType(); + if (isBlockPointer) flags = BLOCK_FIELD_IS_BLOCK; // Special rules for ARC captures: if (getLangOpts().ObjCAutoRefCount) { Qualifiers qs = type.getQualifiers(); - // Don't generate special copy logic for a captured object - // unless it's __strong or __weak. - if (!qs.hasStrongOrWeakObjCLifetime()) - continue; + // We need to register __weak direct captures with the runtime. + if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) { + useARCWeakCopy = true; - // Support __weak direct captures. - if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) - isARCWeakCapture = true; + // We need to retain the copied value for __strong direct captures. + } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) { + // If it's a block pointer, we have to copy the block and + // assign that to the destination pointer, so we might as + // well use _Block_object_assign. Otherwise we can avoid that. + if (!isBlockPointer) + useARCStrongCopy = true; + + // Otherwise the memcpy is fine. + } else { + continue; + } + + // Non-ARC captures of retainable pointers are strong and + // therefore require a call to _Block_object_assign. + } else { + // fall through } } else { continue; @@ -1281,14 +1296,36 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // If there's an explicit copy expression, we do that. if (copyExpr) { EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr); - } else if (isARCWeakCapture) { + } else if (useARCWeakCopy) { EmitARCCopyWeak(dstField, srcField); } else { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); - srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy); - llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy); - Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue, - llvm::ConstantInt::get(Int32Ty, flags.getBitMask())); + if (useARCStrongCopy) { + // At -O0, store null into the destination field (so that the + // storeStrong doesn't over-release) and then call storeStrong. + // This is a workaround to not having an initStrong call. + if (CGM.getCodeGenOpts().OptimizationLevel == 0) { + llvm::PointerType *ty = cast(srcValue->getType()); + llvm::Value *null = llvm::ConstantPointerNull::get(ty); + Builder.CreateStore(null, dstField); + EmitARCStoreStrongCall(dstField, srcValue, true); + + // With optimization enabled, take advantage of the fact that + // the blocks runtime guarantees a memcpy of the block data, and + // just emit a retain of the src field. + } else { + EmitARCRetainNonBlock(srcValue); + + // We don't need this anymore, so kill it. It's not quite + // worth the annoyance to avoid creating it in the first place. + cast(dstField)->eraseFromParent(); + } + } else { + srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy); + llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy); + Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue, + llvm::ConstantInt::get(Int32Ty, flags.getBitMask())); + } } } @@ -1353,7 +1390,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { BlockFieldFlags flags; const CXXDestructorDecl *dtor = 0; - bool isARCWeakCapture = false; + bool useARCWeakDestroy = false; + bool useARCStrongDestroy = false; if (ci->isByRef()) { flags = BLOCK_FIELD_IS_BYREF; @@ -1379,7 +1417,11 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { // Support __weak direct captures. if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) - isARCWeakCapture = true; + useARCWeakDestroy = true; + + // Tools really want us to use objc_storeStrong here. + else + useARCStrongDestroy = true; } } else { continue; @@ -1393,9 +1435,13 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { PushDestructorCleanup(dtor, srcField); // If this is a __weak capture, emit the release directly. - } else if (isARCWeakCapture) { + } else if (useARCWeakDestroy) { EmitARCDestroyWeak(srcField); + // Destroy strong objects with a call if requested. + } else if (useARCStrongDestroy) { + EmitARCDestroyStrong(srcField, /*precise*/ false); + // Otherwise we call _Block_object_dispose. It wouldn't be too // hard to just emit this as a cleanup if we wanted to make sure // that things were done in reverse. @@ -1494,10 +1540,7 @@ public: } void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { - llvm::LoadInst *value = CGF.Builder.CreateLoad(field); - value->setAlignment(Alignment.getQuantity()); - - CGF.EmitARCRelease(value, /*precise*/ false); + CGF.EmitARCDestroyStrong(field, /*precise*/ false); } void profileImpl(llvm::FoldingSetNodeID &id) const { @@ -1527,10 +1570,7 @@ public: } void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { - llvm::LoadInst *value = CGF.Builder.CreateLoad(field); - value->setAlignment(Alignment.getQuantity()); - - CGF.EmitARCRelease(value, /*precise*/ false); + CGF.EmitARCDestroyStrong(field, /*precise*/ false); } void profileImpl(llvm::FoldingSetNodeID &id) const { diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 0fa70e7d3d2d..a47c56f67c7a 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1949,6 +1949,28 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { } } +/// Destroy a __strong variable. +/// +/// At -O0, emit a call to store 'null' into the address; +/// instrumenting tools prefer this because the address is exposed, +/// but it's relatively cumbersome to optimize. +/// +/// At -O1 and above, just load and call objc_release. +/// +/// call void \@objc_storeStrong(i8** %addr, i8* null) +void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) { + if (CGM.getCodeGenOpts().OptimizationLevel == 0) { + llvm::PointerType *addrTy = cast(addr->getType()); + llvm::Value *null = llvm::ConstantPointerNull::get( + cast(addrTy->getElementType())); + EmitARCStoreStrongCall(addr, null, /*ignored*/ true); + return; + } + + llvm::Value *value = Builder.CreateLoad(addr); + EmitARCRelease(value, precise); +} + /// Store into a strong object. Always calls this: /// call void \@objc_storeStrong(i8** %addr, i8* %value) llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr, @@ -2222,15 +2244,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { - llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy"); - CGF.EmitARCRelease(ptr, /*precise*/ true); + CGF.EmitARCDestroyStrong(addr, /*precise*/ true); } void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { - llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy"); - CGF.EmitARCRelease(ptr, /*precise*/ false); + CGF.EmitARCDestroyStrong(addr, /*precise*/ false); } void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 65fa87f5828e..34fc8b9b3534 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2353,6 +2353,7 @@ public: llvm::Value *EmitARCRetain(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainNonBlock(llvm::Value *value); llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory); + void EmitARCDestroyStrong(llvm::Value *addr, bool precise); void EmitARCRelease(llvm::Value *value, bool precise); llvm::Value *EmitARCAutorelease(llvm::Value *value); llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value); diff --git a/clang/test/CodeGenObjC/arc-arm.m b/clang/test/CodeGenObjC/arc-arm.m index 4c569da114ea..2ab8cb6ef562 100644 --- a/clang/test/CodeGenObjC/arc-arm.m +++ b/clang/test/CodeGenObjC/arc-arm.m @@ -13,8 +13,7 @@ void test1(void) { // CHECK-NEXT: call void asm sideeffect "mov\09r7, r7 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) // CHECK-NEXT: store i8* [[T1]], - // CHECK-NEXT: load - // CHECK-NEXT: call void @objc_release + // CHECK-NEXT: call void @objc_storeStrong( // CHECK-NEXT: ret void id x = test1_helper(); } diff --git a/clang/test/CodeGenObjC/arc-blocks.m b/clang/test/CodeGenObjC/arc-blocks.m index cbdb49418b20..38c88afb4d66 100644 --- a/clang/test/CodeGenObjC/arc-blocks.m +++ b/clang/test/CodeGenObjC/arc-blocks.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT %s // This shouldn't crash. void test0(id (^maker)(void)) { @@ -41,6 +42,24 @@ void test2(id x) { // CHECK-NEXT: ret void extern void test2_helper(id (^)(void)); test2_helper(^{ return x; }); + +// CHECK: define internal void @__copy_helper_block_ +// CHECK: [[T0:%.*]] = load i8** +// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-NEXT: [[T0:%.*]] = load i8** +// CHECK-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5 +// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]] +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind +// CHECK-NEXT: ret void + +// CHECK: define internal void @__destroy_helper_block_ +// CHECK: [[T0:%.*]] = load i8** +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5 +// CHECK-NEXT: [[T3:%.*]] = load i8** [[T2]] +// CHECK-NEXT: call void @objc_release(i8* [[T3]]) +// CHECK-NEXT: ret void } void test3(void (^sink)(id*)) { @@ -359,7 +378,7 @@ void test10a(void) { // CHECK: [[T0:%.*]] = load i8** {{%.*}} // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]* // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6 -// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]], align 8 +// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]] // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* // CHECK-NEXT: call void @objc_release(i8* [[T4]]) // CHECK-NEXT: ret void @@ -589,3 +608,42 @@ id (^test17(id self, int which))(void) { // CHECK-NEXT: call void @objc_release(i8* [[T0]]) // CHECK-NEXT: store i32 // CHECK-NEXT: br label + +void test18(id x) { +// CHECK-UNOPT: define void @test18( +// CHECK-UNOPT: [[X:%.*]] = alloca i8*, +// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], +// CHECK-UNOPT-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) +// CHECK-UNOPT-NEXT: store i8* [[PARM]], i8** [[X]] +// CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** [[X]], +// CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) +// CHECK-UNOPT-NEXT: store i8* [[T1]], i8** [[SLOT]], +// CHECK-UNOPT-NEXT: bitcast +// CHECK-UNOPT-NEXT: call void @test18_helper( +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[SLOTREL]], i8* null) nounwind +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) nounwind +// CHECK-UNOPT-NEXT: ret void + extern void test18_helper(id (^)(void)); + test18_helper(^{ return x; }); + +// CHECK-UNOPT: define internal void @__copy_helper_block_ +// CHECK-UNOPT: [[T0:%.*]] = load i8** +// CHECK-UNOPT-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** +// CHECK-UNOPT-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-UNOPT-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: [[T1:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[DST]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: [[T2:%.*]] = load i8** [[T0]] +// CHECK-UNOPT-NEXT: store i8* null, i8** [[T1]] +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) nounwind +// CHECK-UNOPT-NEXT: ret void + +// CHECK-UNOPT: define internal void @__destroy_helper_block_ +// CHECK-UNOPT: [[T0:%.*]] = load i8** +// CHECK-UNOPT-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-UNOPT-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) +// CHECK-UNOPT-NEXT: ret void +} diff --git a/clang/test/CodeGenObjC/arc-exceptions.m b/clang/test/CodeGenObjC/arc-exceptions.m index 5ef5ababe695..63945e3a1b49 100644 --- a/clang/test/CodeGenObjC/arc-exceptions.m +++ b/clang/test/CodeGenObjC/arc-exceptions.m @@ -20,9 +20,8 @@ void test0(void) { // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]* // CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]] -// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]] -// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind +// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8** +// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) nounwind // CHECK-NEXT: call void @objc_end_catch() nounwind void test1_helper(void); diff --git a/clang/test/CodeGenObjC/arc-foreach.m b/clang/test/CodeGenObjC/arc-foreach.m index 67fad4d9b04a..b8d2d30ab40a 100644 --- a/clang/test/CodeGenObjC/arc-foreach.m +++ b/clang/test/CodeGenObjC/arc-foreach.m @@ -67,8 +67,7 @@ void test0(NSArray *array) { // CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]] // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] // CHECK-LP64: call void @use_block( -// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[D0]] -// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]]) +// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null) // CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_ // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8* @@ -79,9 +78,8 @@ void test0(NSArray *array) { // CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]]) // Destroy 'array'. -// CHECK-LP64: [[T0:%.*]] = load [[ARRAY_T]]** [[ARRAY]] -// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8* -// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]]) +// CHECK-LP64: [[T0:%.*]] = bitcast [[ARRAY_T]]** [[ARRAY]] to i8** +// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) // CHECK-LP64-NEXT: ret void // CHECK-LP64: define internal void @__test0_block_invoke diff --git a/clang/test/CodeGenObjC/arc-no-runtime.m b/clang/test/CodeGenObjC/arc-no-runtime.m index 3c85e8783cb8..f5f5b90ea52b 100644 --- a/clang/test/CodeGenObjC/arc-no-runtime.m +++ b/clang/test/CodeGenObjC/arc-no-runtime.m @@ -1,9 +1,13 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -emit-llvm %s -o - | FileCheck %s // rdar://problem/9224855 +id make(void) __attribute__((ns_returns_retained)); void test0() { + make(); id x = 0; // CHECK: call void @objc_release( + // CHECK: call void @objc_storeStrong( } // CHECK: declare extern_weak void @objc_release( +// CHECK: declare extern_weak void @objc_storeStrong( diff --git a/clang/test/CodeGenObjC/arc-property.m b/clang/test/CodeGenObjC/arc-property.m index 68344b83b027..db00e369cfd1 100644 --- a/clang/test/CodeGenObjC/arc-property.m +++ b/clang/test/CodeGenObjC/arc-property.m @@ -11,8 +11,8 @@ void test0(Test0 *t0, id value) { // CHECK: call i8* @objc_retain( // CHECK: call i8* @objc_retain( // CHECK: @objc_msgSend -// CHECK: call void @objc_release( -// CHECK: call void @objc_release( +// CHECK: call void @objc_storeStrong( +// CHECK: call void @objc_storeStrong( struct S1 { Class isa; }; @interface Test1 diff --git a/clang/test/CodeGenObjC/arc-related-result-type.m b/clang/test/CodeGenObjC/arc-related-result-type.m index f73aa5049f5c..ee0a41dd00b4 100644 --- a/clang/test/CodeGenObjC/arc-related-result-type.m +++ b/clang/test/CodeGenObjC/arc-related-result-type.m @@ -20,11 +20,9 @@ void test0(Test0 *val) { // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]* // CHECK-NEXT: store [[TEST0]]* [[T2]], [[TEST0]]** [[X]] -// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[X]] -// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) -// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[VAL]] -// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) +// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]** [[X]] to i8** +// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) +// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]** [[VAL]] to i8** +// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) // CHECK-NEXT: ret void } diff --git a/clang/test/CodeGenObjC/objc-arc-container-subscripting.m b/clang/test/CodeGenObjC/objc-arc-container-subscripting.m index 892491630e6e..71339c7085a4 100644 --- a/clang/test/CodeGenObjC/objc-arc-container-subscripting.m +++ b/clang/test/CodeGenObjC/objc-arc-container-subscripting.m @@ -13,9 +13,8 @@ id func() { // CHECK: [[call:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend // CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) nounwind -// CHECK: [[ARRAY:%.*]] = load %0** -// CHECK: [[ARRAY_CASTED:%.*]] = bitcast{{.*}}[[ARRAY]] to i8* -// CHECK: call void @objc_release(i8* [[ARRAY_CASTED]]) +// CHECK: [[ARRAY_CASTED:%.*]] = bitcast %0** {{%.*}} to i8** +// CHECK: call void @objc_storeStrong(i8** [[ARRAY_CASTED]], i8* null) // CHECK: [[EIGHT:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) nounwind // CHECK: ret i8* [[EIGHT]] diff --git a/clang/test/CodeGenObjCXX/arc-exceptions.mm b/clang/test/CodeGenObjCXX/arc-exceptions.mm index b1fa8ca2403b..fb5300d15e4c 100644 --- a/clang/test/CodeGenObjCXX/arc-exceptions.mm +++ b/clang/test/CodeGenObjCXX/arc-exceptions.mm @@ -20,9 +20,8 @@ void test0(void) { // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]* // CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]] -// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]] -// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind +// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8** +// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) nounwind // CHECK-NEXT: call void @objc_end_catch() nounwind void test1_helper(void); @@ -60,9 +59,8 @@ void test2(void) { // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]* // CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]] -// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]] -// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8* -// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind +// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8** +// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) nounwind // CHECK-NEXT: call void @__cxa_end_catch() nounwind void test3_helper(void); diff --git a/clang/test/CodeGenObjCXX/arc-new-delete.mm b/clang/test/CodeGenObjCXX/arc-new-delete.mm index a778bcad8fa7..ce7eb3deb141 100644 --- a/clang/test/CodeGenObjCXX/arc-new-delete.mm +++ b/clang/test/CodeGenObjCXX/arc-new-delete.mm @@ -35,7 +35,7 @@ void test_new(id invalue) { // CHECK: call i8* @objc_initWeak new __weak id(invalue); - // CHECK: call void @objc_release + // CHECK: call void @objc_storeStrong // CHECK: ret void } @@ -76,8 +76,7 @@ void test_array_delete(__strong id *sptr, __weak id *wptr) { // CHECK-NEXT: icmp eq i8** [[BEGIN]], [[END]] // CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], // CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1 - // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]] - // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: call void @objc_storeStrong(i8** [[CUR]], i8* null) // CHECK-NEXT: icmp eq i8** [[CUR]], [[BEGIN]] // CHECK: call void @_ZdaPv delete [] sptr; diff --git a/clang/test/CodeGenObjCXX/arc-special-member-functions.mm b/clang/test/CodeGenObjCXX/arc-special-member-functions.mm index 421a9fedffac..0b34538d13ef 100644 --- a/clang/test/CodeGenObjCXX/arc-special-member-functions.mm +++ b/clang/test/CodeGenObjCXX/arc-special-member-functions.mm @@ -111,7 +111,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) { // Implicitly-generated destructor for ObjCBlockMember // CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberD2Ev -// CHECK: call void @objc_release(i8* +// CHECK: call void @objc_storeStrong(i8* // CHECK: ret // Implicitly-generated default constructor for ObjCBlockMember @@ -134,8 +134,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) { // CHECK-NEXT: br label // CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] // CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1 -// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]] -// CHECK-NEXT: call void @objc_release(i8* [[T0]]) +// CHECK-NEXT: call void @objc_storeStrong(i8** [[CUR]], i8* null) // CHECK-NEXT: [[T1:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]] // CHECK-NEXT: br i1 [[T1]], // CHECK: ret void @@ -154,7 +153,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) { // Implicitly-generated destructor for ObjCMember // CHECK: define linkonce_odr void @_ZN10ObjCMemberD2Ev -// CHECK: call void @objc_release +// CHECK: call void @objc_storeStrong // CHECK: ret void // Implicitly-generated default constructor for ObjCMember