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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166085 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
index 4c569da..2ab8cb6 100644
--- a/test/CodeGenObjC/arc-arm.m
+++ b/test/CodeGenObjC/arc-arm.m
@@ -13,8 +13,7 @@
// 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/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index cbdb494..38c88af 100644
--- a/test/CodeGenObjC/arc-blocks.m
+++ b/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 @@
// 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 @@
// 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 @@
// 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/test/CodeGenObjC/arc-exceptions.m b/test/CodeGenObjC/arc-exceptions.m
index 5ef5aba..63945e3 100644
--- a/test/CodeGenObjC/arc-exceptions.m
+++ b/test/CodeGenObjC/arc-exceptions.m
@@ -20,9 +20,8 @@
// 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/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index 67fad4d..b8d2d30 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -67,8 +67,7 @@
// 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 @@
// 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/test/CodeGenObjC/arc-no-runtime.m b/test/CodeGenObjC/arc-no-runtime.m
index 3c85e87..f5f5b90 100644
--- a/test/CodeGenObjC/arc-no-runtime.m
+++ b/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/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m
index 68344b8..db00e36 100644
--- a/test/CodeGenObjC/arc-property.m
+++ b/test/CodeGenObjC/arc-property.m
@@ -11,8 +11,8 @@
// 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/test/CodeGenObjC/arc-related-result-type.m b/test/CodeGenObjC/arc-related-result-type.m
index f73aa50..ee0a41d 100644
--- a/test/CodeGenObjC/arc-related-result-type.m
+++ b/test/CodeGenObjC/arc-related-result-type.m
@@ -20,11 +20,9 @@
// 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/test/CodeGenObjC/objc-arc-container-subscripting.m b/test/CodeGenObjC/objc-arc-container-subscripting.m
index 8924916..71339c7 100644
--- a/test/CodeGenObjC/objc-arc-container-subscripting.m
+++ b/test/CodeGenObjC/objc-arc-container-subscripting.m
@@ -13,9 +13,8 @@
// 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/test/CodeGenObjCXX/arc-exceptions.mm b/test/CodeGenObjCXX/arc-exceptions.mm
index b1fa8ca..fb5300d 100644
--- a/test/CodeGenObjCXX/arc-exceptions.mm
+++ b/test/CodeGenObjCXX/arc-exceptions.mm
@@ -20,9 +20,8 @@
// 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 @@
// 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/test/CodeGenObjCXX/arc-new-delete.mm b/test/CodeGenObjCXX/arc-new-delete.mm
index a778bca..ce7eb3d 100644
--- a/test/CodeGenObjCXX/arc-new-delete.mm
+++ b/test/CodeGenObjCXX/arc-new-delete.mm
@@ -35,7 +35,7 @@
// 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 @@
// 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/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm
index 421a9fe..0b34538 100644
--- a/test/CodeGenObjCXX/arc-special-member-functions.mm
+++ b/test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -111,7 +111,7 @@
// 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 @@
// 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 @@
// 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