summaryrefslogtreecommitdiffstats
path: root/clang/test/CodeGenObjC
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-07-31 23:20:56 +0000
committerJohn McCall <rjmccall@apple.com>2010-07-31 23:20:56 +0000
commit42227edc79b34ba31220d4712d2da07b46152cd8 (patch)
tree6d98493ff929c909f30e6ae4c9b3c027a8988ea1 /clang/test/CodeGenObjC
parent66161f5eb4a9e68add2e6097b980b71babb7a8ab (diff)
downloadbcm5719-llvm-42227edc79b34ba31220d4712d2da07b46152cd8.tar.gz
bcm5719-llvm-42227edc79b34ba31220d4712d2da07b46152cd8.zip
Fix fragile-ABI ObjC exceptions in the presence of optimization with
the magic of inline assembly. Essentially we use read and write hazards on the set of local variables to force flushing locals to memory immediately before any protected calls and to inhibit optimizing locals across the setjmp->catch edge. Fixes rdar://problem/8160285 llvm-svn: 109960
Diffstat (limited to 'clang/test/CodeGenObjC')
-rw-r--r--clang/test/CodeGenObjC/exceptions.m46
-rw-r--r--clang/test/CodeGenObjC/synchronized.m51
2 files changed, 88 insertions, 9 deletions
diff --git a/clang/test/CodeGenObjC/exceptions.m b/clang/test/CodeGenObjC/exceptions.m
index 5be695932b0..e9d5b6f2e2c 100644
--- a/clang/test/CodeGenObjC/exceptions.m
+++ b/clang/test/CodeGenObjC/exceptions.m
@@ -37,3 +37,49 @@ void f1() {
}
}
}
+
+// Test that modifications to local variables are respected under
+// optimization. rdar://problem/8160285
+
+// CHECK: define i32 @f2()
+int f2() {
+ extern void foo(void);
+
+ // CHECK: [[X:%.*]] = alloca i32
+ // CHECK: store i32 0, i32* [[X]]
+ int x = 0;
+
+ // CHECK: [[SETJMP:%.*]] = call i32 @_setjmp
+ // CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0
+ // CHECK-NEXT: br i1 [[CAUGHT]]
+ @try {
+ // This load should be coalescable with the store of 0, so if the
+ // optimizers ever figure out that out, that's okay.
+ // CHECK: [[T1:%.*]] = load i32* [[X]]
+ // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], 1
+ // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
+ x++;
+ // CHECK-NEXT: call void asm sideeffect "", "*m"(i32* [[X]]) nounwind
+ // CHECK-NEXT: call void @foo()
+ foo();
+ } @catch (id) {
+ // Landing pad. It turns out that the re-enter is unnecessary here.
+ // CHECK: call void asm sideeffect "", "=*m"(i32* [[X]]) nounwind
+ // CHECK-NEXT: call i8* @objc_exception_extract
+ // CHECK-NEXT: call void @objc_exception_try_enter
+ // CHECK-NEXT: call i32 @_setjmp
+ // CHECK-NEXT: icmp eq i32
+ // CHECK-NEXT: br i1
+
+ // Catch handler.
+ // CHECK: [[T1:%.*]] = load i32* [[X]]
+ // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1
+ // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
+ // CHECK-NEXT: br label
+ x--;
+ }
+ // CHECK: call void @objc_exception_try_exit
+ // CHECK-NEXT: [[T:%.*]] = load i32* [[X]]
+ // CHECK: ret i32 [[T]]
+ return x;
+}
diff --git a/clang/test/CodeGenObjC/synchronized.m b/clang/test/CodeGenObjC/synchronized.m
index 1af82345e0b..b71337972dc 100644
--- a/clang/test/CodeGenObjC/synchronized.m
+++ b/clang/test/CodeGenObjC/synchronized.m
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -triple=i686-apple-darwin9 -o %t %s -O2
-// RUN: grep 'ret i32' %t | count 1
-// RUN: grep 'ret i32 1' %t | count 1
+// RUN: %clang_cc1 -emit-llvm -triple=i686-apple-darwin9 -o - %s -O2 | FileCheck %s
@interface MyClass
{
@@ -10,31 +8,66 @@
@implementation MyClass
+// CHECK: define internal void @"\01-[MyClass method]"
- (void)method
{
- @synchronized(self)
- {
- }
+ // CHECK: call void @objc_sync_enter
+ // CHECK: call void @objc_exception_try_enter
+ // CHECK: call i32 @_setjmp
+ @synchronized(self) {
+ }
}
@end
+// CHECK: define void @foo(
void foo(id a) {
+ // CHECK: [[A:%.*]] = alloca i8*
+
+ // CHECK: call void @objc_sync_enter
+ // CHECK: call void @objc_exception_try_enter
+ // CHECK: call i32 @_setjmp
@synchronized(a) {
+ // CHECK: call void @objc_exception_try_exit
+ // CHECK: call void @objc_sync_exit
+ // CHECK: ret void
return;
}
+
+ // This is unreachable, but the optimizers can't know that.
+ // CHECK: call void asm sideeffect "", "=*m"(i8** [[A]])
+ // CHECK: call i8* @objc_exception_extract
+ // CHECK: call void @objc_sync_exit
+ // CHECK: call void @objc_exception_throw
+ // CHECK: unreachable
}
+// CHECK: define i32 @f0(
int f0(id a) {
+ // TODO: we can optimize the ret to a constant if we can figure out
+ // either that x isn't stored to within the synchronized block or
+ // that the synchronized block can't longjmp.
+
+ // CHECK: [[X:%.*]] = alloca i32
+ // CHECK: store i32 1, i32* [[X]]
int x = 0;
@synchronized((x++, a)) {
}
- return x; // ret i32 1
+
+ // CHECK: [[T:%.*]] = load i32* [[X]]
+ // CHECK: ret i32 [[T]]
+ return x;
}
+// CHECK: define void @f1(
void f1(id a) {
- // The trick here is that the return shouldn't go through clean up,
- // but there isn't a simple way to check this property.
+ // Check that the return doesn't go through the cleanup.
+ extern void opaque(void);
+ opaque();
+
+ // CHECK: call void @opaque()
+ // CHECK-NEXT: ret void
+
@synchronized(({ return; }), a) {
return;
}
OpenPOWER on IntegriCloud