181 lines · plain
1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fobjc-exceptions -mllvm -simplifycfg-sink-common=false -O2 -o - %s | FileCheck %s2//3// [irgen] [eh] Exception code built with clang (x86_64) crashes4 5// Just check that we don't emit any dead blocks.6@interface NSArray @end7void f0(void) {8 @try {9 @try {10 @throw @"a";11 } @catch(NSArray *e) {12 }13 } @catch (id e) {14 }15}16 17// CHECK-LABEL: define{{.*}} void @f1()18void f1(void) {19 extern void foo(void);20 21 while (1) {22 // CHECK: call void @objc_exception_try_enter23 // CHECK-NEXT: call i32 @_setjmp(24 // CHECK-NEXT: icmp25 // CHECK-NEXT: br i126 @try {27 // CHECK: call void asm sideeffect "", "=*m"28 // CHECK: call void asm sideeffect "", "*m"29 // CHECK-NEXT: call void @foo()30 foo();31 // CHECK: call void @objc_exception_try_exit32 33 } @finally {34 break;35 }36 }37}38 39// Test that modifications to local variables are respected under40// optimization.41 42// CHECK-LABEL: define{{.*}} i32 @f2()43int f2(void) {44 extern void foo(void);45 46 // CHECK: [[X:%.*]] = alloca i3247 // CHECK: store i32 5, ptr [[X]]48 int x = 0;49 x += 5;50 51 // CHECK: [[SETJMP:%.*]] = call i32 @_setjmp52 // CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 053 // CHECK-NEXT: br i1 [[CAUGHT]]54 @try {55 // Landing pad. Note that we elide the re-enter.56 // CHECK: call void asm sideeffect "", "=*m,=*m"(ptr nonnull elementtype(i32) [[X]]57 // CHECK-NEXT: call ptr @objc_exception_extract58 // CHECK-NEXT: [[T1:%.*]] = load i32, ptr [[X]]59 // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -160 61 // CHECK: store i32 6, ptr [[X]]62 x++;63 // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(ptr nonnull elementtype(i32) [[X]]64 // CHECK-NEXT: call void @foo()65 // CHECK-NEXT: call void @objc_exception_try_exit66 // CHECK-NEXT: [[T:%.*]] = load i32, ptr [[X]]67 foo();68 } @catch (id) {69 x--;70 }71 72 return x;73}74 75// Test that the cleanup destination is saved when entering a finally76// block.77// CHECK-LABEL: define{{.*}} void @f3()78void f3(void) {79 extern void f3_helper(int, int*);80 81 // CHECK: [[X:%.*]] = alloca i3282 // CHECK: call void @llvm.lifetime.start.p0(ptr nonnull [[X]])83 // CHECK: store i32 0, ptr [[X]]84 int x = 0;85 86 // CHECK: call void @objc_exception_try_enter(87 // CHECK: call i32 @_setjmp88 // CHECK-NEXT: [[DEST1:%.*]] = icmp eq89 // CHECK-NEXT: br i1 [[DEST1]]90 91 @try {92 // CHECK: call void @f3_helper(i32 noundef 0, ptr noundef nonnull [[X]])93 // CHECK: call void @objc_exception_try_exit(94 f3_helper(0, &x);95 } @finally {96 // CHECK: call void @objc_exception_try_enter97 // CHECK: call i32 @_setjmp98 // CHECK-NEXT: [[DEST2:%.*]] = icmp eq99 // CHECK-NEXT: br i1 [[DEST2]]100 @try {101 // CHECK: call void @f3_helper(i32 noundef 1, ptr noundef nonnull [[X]])102 // CHECK: call void @objc_exception_try_exit(103 f3_helper(1, &x);104 } @finally {105 // CHECK: call void @f3_helper(i32 noundef 2, ptr noundef nonnull [[X]])106 f3_helper(2, &x);107 108 // This loop is large enough to dissuade the optimizer from just109 // duplicating the finally block.110 while (x) f3_helper(3, &x);111 112 // This is a switch or maybe some chained branches, but relying113 // on a specific result from the optimizer is really unstable.114 // CHECK: [[DEST2]]115 }116 117 // This is a switch or maybe some chained branches, but relying118 // on a specific result from the optimizer is really unstable.119 // CHECK: [[DEST1]]120 }121 122 // CHECK: call void @f3_helper(i32 noundef 4, ptr noundef nonnull [[X]])123 // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[X]])124 // CHECK-NEXT: ret void125 f3_helper(4, &x);126}127 128void f4(void) {129 extern void f4_help(int);130 131 // CHECK-LABEL: define{{.*}} void @f4()132 // CHECK: [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align133 // CHECK: call void @objc_exception_try_enter(ptr nonnull [[EXNDATA]])134 // CHECK: call i32 @_setjmp135 @try {136 // CHECK: call void @f4_help(i32 noundef 0)137 f4_help(0);138 139 // The finally cleanup has two threaded entrypoints after optimization:140 141 // finally.no-call-exit: Predecessor is when the catch throws.142 // CHECK: call ptr @objc_exception_extract(ptr nonnull [[EXNDATA]])143 // CHECK-NEXT: call void @f4_help(i32 noundef 2)144 // CHECK-NEXT: br label145 // -> rethrow146 147 // finally.call-exit: Predecessor is the no-match case in the catch mechanism148 // which rethrows.149 // CHECK: call void @objc_exception_try_exit(ptr nonnull [[EXNDATA]])150 // CHECK-NEXT: call void @f4_help(i32 noundef 2)151 // CHECK-NEXT: br label152 // -> rethrow153 154 // finally.end.critedge: Predecessors are the @try and @catch fallthroughs.155 // CHECK: call void @objc_exception_try_exit(ptr nonnull [[EXNDATA]])156 // CHECK-NEXT: call void @f4_help(i32 noundef 2)157 // CHECK-NEXT: ret void158 159 // Catch mechanism:160 // CHECK: call ptr @objc_exception_extract(ptr nonnull [[EXNDATA]])161 // CHECK-NEXT: call void @objc_exception_try_enter(ptr nonnull [[EXNDATA]])162 // CHECK: call i32 @_setjmp163 // -> next, finally.no-call-exit164 // CHECK: call i32 @objc_exception_match165 // -> finally.call-exit, match166 } @catch (NSArray *a) {167 // match:168 // CHECK: call void @f4_help(i32 noundef 1)169 // CHECK-NEXT: br label170 // -> finally.call-exit171 f4_help(1);172 } @finally {173 f4_help(2);174 }175 176 // rethrow:177 // CHECK: phi ptr178 // CHECK-NEXT: call void @objc_exception_throw(ptr179 // CHECK-NEXT: unreachable180}181