xref: /aosp_15_r20/external/clang/test/CodeGenObjC/exceptions.m (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fobjc-exceptions -O2 -o - %s | FileCheck %s
2*67e74705SXin Li//
3*67e74705SXin Li// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes
4*67e74705SXin Li
5*67e74705SXin Li// Just check that we don't emit any dead blocks.
6*67e74705SXin Li@interface NSArray @end
7*67e74705SXin Livoid f0() {
8*67e74705SXin Li  @try {
9*67e74705SXin Li    @try {
10*67e74705SXin Li      @throw @"a";
11*67e74705SXin Li    } @catch(NSArray *e) {
12*67e74705SXin Li    }
13*67e74705SXin Li  } @catch (id e) {
14*67e74705SXin Li  }
15*67e74705SXin Li}
16*67e74705SXin Li
17*67e74705SXin Li// CHECK-LABEL: define void @f1()
18*67e74705SXin Livoid f1() {
19*67e74705SXin Li  extern void foo(void);
20*67e74705SXin Li
21*67e74705SXin Li  while (1) {
22*67e74705SXin Li    // CHECK:      call void @objc_exception_try_enter
23*67e74705SXin Li    // CHECK-NEXT: getelementptr
24*67e74705SXin Li    // CHECK-NEXT: call i32 @_setjmp(
25*67e74705SXin Li    // CHECK-NEXT: icmp
26*67e74705SXin Li    // CHECK-NEXT: br i1
27*67e74705SXin Li    @try {
28*67e74705SXin Li    // CHECK:      call void asm sideeffect "", "*m"
29*67e74705SXin Li    // CHECK-NEXT: call void @foo()
30*67e74705SXin Li      foo();
31*67e74705SXin Li    // CHECK:      call void @objc_exception_try_exit
32*67e74705SXin Li
33*67e74705SXin Li    // CHECK:      call void asm sideeffect "", "=*m"
34*67e74705SXin Li    } @finally {
35*67e74705SXin Li      break;
36*67e74705SXin Li    }
37*67e74705SXin Li  }
38*67e74705SXin Li}
39*67e74705SXin Li
40*67e74705SXin Li// Test that modifications to local variables are respected under
41*67e74705SXin Li// optimization.  rdar://problem/8160285
42*67e74705SXin Li
43*67e74705SXin Li// CHECK-LABEL: define i32 @f2()
44*67e74705SXin Liint f2() {
45*67e74705SXin Li  extern void foo(void);
46*67e74705SXin Li
47*67e74705SXin Li  // CHECK:        [[X:%.*]] = alloca i32
48*67e74705SXin Li  // CHECK:        store i32 5, i32* [[X]]
49*67e74705SXin Li  int x = 0;
50*67e74705SXin Li  x += 5;
51*67e74705SXin Li
52*67e74705SXin Li  // CHECK:        [[SETJMP:%.*]] = call i32 @_setjmp
53*67e74705SXin Li  // CHECK-NEXT:   [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0
54*67e74705SXin Li  // CHECK-NEXT:   br i1 [[CAUGHT]]
55*67e74705SXin Li  @try {
56*67e74705SXin Li    // CHECK: store i32 6, i32* [[X]]
57*67e74705SXin Li    x++;
58*67e74705SXin Li    // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* nonnull [[X]]
59*67e74705SXin Li    // CHECK-NEXT: call void @foo()
60*67e74705SXin Li    // CHECK-NEXT: call void @objc_exception_try_exit
61*67e74705SXin Li    // CHECK-NEXT: [[T:%.*]] = load i32, i32* [[X]]
62*67e74705SXin Li    foo();
63*67e74705SXin Li  } @catch (id) {
64*67e74705SXin Li    // Landing pad.  Note that we elide the re-enter.
65*67e74705SXin Li    // CHECK:      call void asm sideeffect "", "=*m,=*m"(i32* nonnull [[X]]
66*67e74705SXin Li    // CHECK-NEXT: call i8* @objc_exception_extract
67*67e74705SXin Li    // CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[X]]
68*67e74705SXin Li    // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1
69*67e74705SXin Li
70*67e74705SXin Li    // This store is dead.
71*67e74705SXin Li    // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
72*67e74705SXin Li    x--;
73*67e74705SXin Li  }
74*67e74705SXin Li
75*67e74705SXin Li  return x;
76*67e74705SXin Li}
77*67e74705SXin Li
78*67e74705SXin Li// Test that the cleanup destination is saved when entering a finally
79*67e74705SXin Li// block.  rdar://problem/8293901
80*67e74705SXin Li// CHECK-LABEL: define void @f3()
81*67e74705SXin Livoid f3() {
82*67e74705SXin Li  extern void f3_helper(int, int*);
83*67e74705SXin Li
84*67e74705SXin Li  // CHECK:      [[X:%.*]] = alloca i32
85*67e74705SXin Li  // CHECK:      [[XPTR:%.*]] = bitcast i32* [[X]] to i8*
86*67e74705SXin Li  // CHECK:      call void @llvm.lifetime.start(i64 4, i8* [[XPTR]])
87*67e74705SXin Li  // CHECK:      store i32 0, i32* [[X]]
88*67e74705SXin Li  int x = 0;
89*67e74705SXin Li
90*67e74705SXin Li  // CHECK:      call void @objc_exception_try_enter(
91*67e74705SXin Li  // CHECK:      call i32 @_setjmp
92*67e74705SXin Li  // CHECK-NEXT: icmp eq
93*67e74705SXin Li  // CHECK-NEXT: br i1
94*67e74705SXin Li
95*67e74705SXin Li  @try {
96*67e74705SXin Li    // CHECK:    call void @f3_helper(i32 0, i32* nonnull [[X]])
97*67e74705SXin Li    // CHECK:    call void @objc_exception_try_exit(
98*67e74705SXin Li    f3_helper(0, &x);
99*67e74705SXin Li  } @finally {
100*67e74705SXin Li    // CHECK:    [[DEST1:%.*]] = phi i32 [ 0, {{%.*}} ], [ 3, {{%.*}} ]
101*67e74705SXin Li    // CHECK:    call void @objc_exception_try_enter
102*67e74705SXin Li    // CHECK:    call i32 @_setjmp
103*67e74705SXin Li    @try {
104*67e74705SXin Li      // CHECK:  call void @f3_helper(i32 1, i32* nonnull [[X]])
105*67e74705SXin Li      // CHECK:  call void @objc_exception_try_exit(
106*67e74705SXin Li      f3_helper(1, &x);
107*67e74705SXin Li    } @finally {
108*67e74705SXin Li      // CHECK:  [[DEST2:%.*]] = phi i32 [ 0, {{%.*}} ], [ 5, {{%.*}} ]
109*67e74705SXin Li      // CHECK:  call void @f3_helper(i32 2, i32* nonnull [[X]])
110*67e74705SXin Li      f3_helper(2, &x);
111*67e74705SXin Li
112*67e74705SXin Li      // This loop is large enough to dissuade the optimizer from just
113*67e74705SXin Li      // duplicating the finally block.
114*67e74705SXin Li      while (x) f3_helper(3, &x);
115*67e74705SXin Li
116*67e74705SXin Li      // This is a switch or maybe some chained branches, but relying
117*67e74705SXin Li      // on a specific result from the optimizer is really unstable.
118*67e74705SXin Li      // CHECK:  [[DEST2]]
119*67e74705SXin Li    }
120*67e74705SXin Li
121*67e74705SXin Li      // This is a switch or maybe some chained branches, but relying
122*67e74705SXin Li      // on a specific result from the optimizer is really unstable.
123*67e74705SXin Li    // CHECK:    [[DEST1]]
124*67e74705SXin Li  }
125*67e74705SXin Li
126*67e74705SXin Li  // CHECK:      call void @f3_helper(i32 4, i32* nonnull [[X]])
127*67e74705SXin Li  // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* nonnull [[XPTR]])
128*67e74705SXin Li  // CHECK-NEXT: ret void
129*67e74705SXin Li  f3_helper(4, &x);
130*67e74705SXin Li}
131*67e74705SXin Li
132*67e74705SXin Li// rdar://problem/8440970
133*67e74705SXin Livoid f4() {
134*67e74705SXin Li  extern void f4_help(int);
135*67e74705SXin Li
136*67e74705SXin Li  // CHECK-LABEL: define void @f4()
137*67e74705SXin Li  // CHECK:      [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align
138*67e74705SXin Li  // CHECK:      call void @objc_exception_try_enter([[EXNDATA_T]]* nonnull [[EXNDATA]])
139*67e74705SXin Li  // CHECK:      call i32 @_setjmp
140*67e74705SXin Li  @try {
141*67e74705SXin Li  // CHECK:      call void @f4_help(i32 0)
142*67e74705SXin Li    f4_help(0);
143*67e74705SXin Li
144*67e74705SXin Li  // The finally cleanup has two threaded entrypoints after optimization:
145*67e74705SXin Li
146*67e74705SXin Li  // finally.no-call-exit:  Predecessor is when the catch throws.
147*67e74705SXin Li  // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* nonnull [[EXNDATA]])
148*67e74705SXin Li  // CHECK-NEXT: call void @f4_help(i32 2)
149*67e74705SXin Li  // CHECK-NEXT: br label
150*67e74705SXin Li  //   -> rethrow
151*67e74705SXin Li
152*67e74705SXin Li  // finally.call-exit:  Predecessors are the @try and @catch fallthroughs
153*67e74705SXin Li  // as well as the no-match case in the catch mechanism.  The i1 is whether
154*67e74705SXin Li  // to rethrow and should be true only in the last case.
155*67e74705SXin Li  // CHECK:      phi i8*
156*67e74705SXin Li  // CHECK-NEXT: phi i1
157*67e74705SXin Li  // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* nonnull [[EXNDATA]])
158*67e74705SXin Li  // CHECK-NEXT: call void @f4_help(i32 2)
159*67e74705SXin Li  // CHECK-NEXT: br i1
160*67e74705SXin Li  //   -> ret, rethrow
161*67e74705SXin Li
162*67e74705SXin Li  // ret:
163*67e74705SXin Li  // CHECK:      ret void
164*67e74705SXin Li
165*67e74705SXin Li  // Catch mechanism:
166*67e74705SXin Li  // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* nonnull [[EXNDATA]])
167*67e74705SXin Li  // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* nonnull [[EXNDATA]])
168*67e74705SXin Li  // CHECK:      call i32 @_setjmp
169*67e74705SXin Li  //   -> next, finally.no-call-exit
170*67e74705SXin Li  // CHECK:      call i32 @objc_exception_match
171*67e74705SXin Li  //   -> finally.call-exit, match
172*67e74705SXin Li  } @catch (NSArray *a) {
173*67e74705SXin Li  // match:
174*67e74705SXin Li  // CHECK:      call void @f4_help(i32 1)
175*67e74705SXin Li  // CHECK-NEXT: br label
176*67e74705SXin Li  //   -> finally.call-exit
177*67e74705SXin Li    f4_help(1);
178*67e74705SXin Li  } @finally {
179*67e74705SXin Li    f4_help(2);
180*67e74705SXin Li  }
181*67e74705SXin Li
182*67e74705SXin Li  // rethrow:
183*67e74705SXin Li  // CHECK:      phi i8*
184*67e74705SXin Li  // CHECK-NEXT: call void @objc_exception_throw(i8*
185*67e74705SXin Li  // CHECK-NEXT: unreachable
186*67e74705SXin Li}
187