diff options
author | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 |
---|---|---|
committer | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 |
commit | be1de4be954c80875ad4108e0a33e8e131b2f2c0 (patch) | |
tree | 1fbbecf276bf7c7bdcbb4dd446099d6d90eaa516 /clang/test/CodeGenObjC/exceptions.m | |
parent | c4626a62754862d20b41e8a46a3574264ea80e6d (diff) | |
parent | f1bd2e48c5324d3f7cda4090c87f8a5b6f463ce2 (diff) |
Merge branch 'master' of ssh://bitbucket.org/czan/honours
Diffstat (limited to 'clang/test/CodeGenObjC/exceptions.m')
-rw-r--r-- | clang/test/CodeGenObjC/exceptions.m | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/clang/test/CodeGenObjC/exceptions.m b/clang/test/CodeGenObjC/exceptions.m new file mode 100644 index 0000000..24fb657 --- /dev/null +++ b/clang/test/CodeGenObjC/exceptions.m @@ -0,0 +1,183 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s +// +// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes + +// Just check that we don't emit any dead blocks. +@interface NSArray @end +void f0() { + @try { + @try { + @throw @"a"; + } @catch(NSArray *e) { + } + } @catch (id e) { + } +} + +// CHECK: define void @f1() +void f1() { + extern void foo(void); + + while (1) { + // CHECK: call void @objc_exception_try_enter + // CHECK-NEXT: getelementptr + // CHECK-NEXT: call i32 @_setjmp( + // CHECK-NEXT: icmp + // CHECK-NEXT: br i1 + @try { + // CHECK: call void asm sideeffect "", "*m" + // CHECK-NEXT: call void @foo() + foo(); + // CHECK-NEXT: call void @objc_exception_try_exit + + // CHECK: call void asm sideeffect "", "=*m" + } @finally { + break; + } + } +} + +// 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 5, i32* [[X]] + int x = 0; + x += 5; + + // CHECK: [[SETJMP:%.*]] = call i32 @_setjmp + // CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0 + // CHECK-NEXT: br i1 [[CAUGHT]] + @try { + // CHECK: store i32 6, i32* [[X]] + x++; + // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* [[X]] + // CHECK-NEXT: call void @foo() + // CHECK-NEXT: call void @objc_exception_try_exit + // CHECK-NEXT: [[T:%.*]] = load i32* [[X]] + foo(); + } @catch (id) { + // Landing pad. Note that we elide the re-enter. + // CHECK: call void asm sideeffect "", "=*m,=*m"(i32* [[X]] + // CHECK-NEXT: call i8* @objc_exception_extract + // CHECK-NEXT: [[T1:%.*]] = load i32* [[X]] + // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1 + + // This store is dead. + // CHECK-NEXT: store i32 [[T2]], i32* [[X]] + x--; + } + + return x; +} + +// Test that the cleanup destination is saved when entering a finally +// block. rdar://problem/8293901 +// CHECK: define void @f3() +void f3() { + extern void f3_helper(int, int*); + + // CHECK: [[X:%.*]] = alloca i32 + // CHECK: store i32 0, i32* [[X]] + int x = 0; + + // CHECK: call void @objc_exception_try_enter( + // CHECK: call i32 @_setjmp + // CHECK-NEXT: icmp eq + // CHECK-NEXT: br i1 + + @try { + // CHECK: call void @f3_helper(i32 0, i32* [[X]]) + // CHECK: call void @objc_exception_try_exit( + f3_helper(0, &x); + } @finally { + // CHECK: [[DEST1:%.*]] = phi i32 [ 0, {{%.*}} ], [ 3, {{%.*}} ] + // CHECK: call void @objc_exception_try_enter + // CHECK: call i32 @_setjmp + @try { + // CHECK: call void @f3_helper(i32 1, i32* [[X]]) + // CHECK: call void @objc_exception_try_exit( + f3_helper(1, &x); + } @finally { + // CHECK: [[DEST2:%.*]] = phi i32 [ 0, {{%.*}} ], [ 5, {{%.*}} ] + // CHECK: call void @f3_helper(i32 2, i32* [[X]]) + f3_helper(2, &x); + + // This loop is large enough to dissuade the optimizer from just + // duplicating the finally block. + while (x) f3_helper(3, &x); + + // This is a switch or maybe some chained branches, but relying + // on a specific result from the optimizer is really unstable. + // CHECK: [[DEST2]] + } + + // This is a switch or maybe some chained branches, but relying + // on a specific result from the optimizer is really unstable. + // CHECK: [[DEST1]] + } + + // CHECK: call void @f3_helper(i32 4, i32* [[X]]) + // CHECK-NEXT: ret void + f3_helper(4, &x); +} + +// rdar://problem/8440970 +void f4() { + extern void f4_help(int); + + // CHECK: define void @f4() + // CHECK: [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align + // CHECK: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]]) + // CHECK: call i32 @_setjmp + @try { + // CHECK: call void @f4_help(i32 0) + f4_help(0); + + // The finally cleanup has two threaded entrypoints after optimization: + + // finally.no-call-exit: Predecessor is when the catch throws. + // CHECK: call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]]) + // CHECK-NEXT: call void @f4_help(i32 2) + // CHECK-NEXT: br label + // -> rethrow + + // finally.call-exit: Predecessors are the @try and @catch fallthroughs + // as well as the no-match case in the catch mechanism. The i1 is whether + // to rethrow and should be true only in the last case. + // CHECK: phi i1 + // CHECK-NEXT: phi i8* + // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* [[EXNDATA]]) + // CHECK-NEXT: call void @f4_help(i32 2) + // CHECK-NEXT: br i1 + // -> ret, rethrow + + // ret: + // CHECK: ret void + + // Catch mechanism: + // CHECK: call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]]) + // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]]) + // CHECK: call i32 @_setjmp + // -> next, finally.no-call-exit + // CHECK: call i32 @objc_exception_match + // -> finally.call-exit, match + } @catch (NSArray *a) { + // match: + // CHECK: call void @f4_help(i32 1) + // CHECK-NEXT: br label + // -> finally.call-exit + f4_help(1); + } @finally { + f4_help(2); + } + + // rethrow: + // CHECK: phi i8* + // CHECK-NEXT: call void @objc_exception_throw(i8* + // CHECK-NEXT: unreachable +} |