xref: /aosp_15_r20/external/clang/test/CodeGen/exceptions-seh-leave.c (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | opt -instnamer -S | FileCheck %s
2*67e74705SXin Li 
3*67e74705SXin Li void g(void);
4*67e74705SXin Li 
5*67e74705SXin Li //////////////////////////////////////////////////////////////////////////////
6*67e74705SXin Li // __leave with __except
7*67e74705SXin Li 
8*67e74705SXin Li // Nothing in the __try block can trap, so __try.cont isn't created.
__leave_with___except_simple()9*67e74705SXin Li int __leave_with___except_simple() {
10*67e74705SXin Li   int myres = 0;
11*67e74705SXin Li   __try {
12*67e74705SXin Li     myres = 15;
13*67e74705SXin Li     __leave;
14*67e74705SXin Li     myres = 23;
15*67e74705SXin Li   } __except (1) {
16*67e74705SXin Li     return 0;
17*67e74705SXin Li   }
18*67e74705SXin Li   return 1;
19*67e74705SXin Li }
20*67e74705SXin Li // CHECK-LABEL: define i32 @__leave_with___except_simple()
21*67e74705SXin Li // CHECK: store i32 15, i32* %myres
22*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
23*67e74705SXin Li // CHECK-NOT: store i32 23
24*67e74705SXin Li // CHECK: [[tryleave]]
25*67e74705SXin Li // CHECK-NEXT: ret i32 1
26*67e74705SXin Li 
27*67e74705SXin Li 
28*67e74705SXin Li // The "normal" case.
__leave_with___except()29*67e74705SXin Li int __leave_with___except() {
30*67e74705SXin Li   int myres = 0;
31*67e74705SXin Li   __try {
32*67e74705SXin Li     g();
33*67e74705SXin Li     __leave;
34*67e74705SXin Li     myres = 23;
35*67e74705SXin Li   } __except (1) {
36*67e74705SXin Li     return 0;
37*67e74705SXin Li   }
38*67e74705SXin Li   return 1;
39*67e74705SXin Li }
40*67e74705SXin Li // CHECK-LABEL: define i32 @__leave_with___except()
41*67e74705SXin Li // CHECK: invoke void @g()
42*67e74705SXin Li // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
43*67e74705SXin Li // For __excepts, instead of an explicit __try.__leave label, we could use
44*67e74705SXin Li // use invoke.cont as __leave jump target instead.  However, not doing this
45*67e74705SXin Li // keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will
46*67e74705SXin Li // simplify this anyways.
47*67e74705SXin Li // CHECK: [[cont]]
48*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
49*67e74705SXin Li // CHECK-NOT: store i32 23
50*67e74705SXin Li // CHECK: [[tryleave]]
51*67e74705SXin Li // CHECK-NEXT: br label %
52*67e74705SXin Li 
53*67e74705SXin Li 
54*67e74705SXin Li //////////////////////////////////////////////////////////////////////////////
55*67e74705SXin Li // __leave with __finally
56*67e74705SXin Li 
57*67e74705SXin Li void abort(void) __attribute__((noreturn));
58*67e74705SXin Li 
59*67e74705SXin Li // Nothing in the __try block can trap, so __finally.cont and friends aren't
60*67e74705SXin Li // created.
__leave_with___finally_simple()61*67e74705SXin Li int __leave_with___finally_simple() {
62*67e74705SXin Li   int myres = 0;
63*67e74705SXin Li   __try {
64*67e74705SXin Li     myres = 15;
65*67e74705SXin Li     __leave;
66*67e74705SXin Li     myres = 23;
67*67e74705SXin Li   } __finally {
68*67e74705SXin Li     return 0;
69*67e74705SXin Li   }
70*67e74705SXin Li   return 1;
71*67e74705SXin Li }
72*67e74705SXin Li // CHECK-LABEL: define i32 @__leave_with___finally_simple()
73*67e74705SXin Li // CHECK: store i32 15, i32* %myres
74*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
75*67e74705SXin Li // CHECK-NOT: store i32 23
76*67e74705SXin Li // CHECK: [[tryleave]]
77*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
78*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i8 0, i8* %[[fp]])
79*67e74705SXin Li 
80*67e74705SXin Li // __finally block doesn't return, __finally.cont doesn't exist.
__leave_with___finally_noreturn()81*67e74705SXin Li int __leave_with___finally_noreturn() {
82*67e74705SXin Li   int myres = 0;
83*67e74705SXin Li   __try {
84*67e74705SXin Li     myres = 15;
85*67e74705SXin Li     __leave;
86*67e74705SXin Li     myres = 23;
87*67e74705SXin Li   } __finally {
88*67e74705SXin Li     abort();
89*67e74705SXin Li   }
90*67e74705SXin Li   return 1;
91*67e74705SXin Li }
92*67e74705SXin Li // CHECK-LABEL: define i32 @__leave_with___finally_noreturn()
93*67e74705SXin Li // CHECK: store i32 15, i32* %myres
94*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
95*67e74705SXin Li // CHECK-NOT: store i32 23
96*67e74705SXin Li // CHECK: [[tryleave]]
97*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
98*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i8 0, i8* %[[fp]])
99*67e74705SXin Li 
100*67e74705SXin Li // The "normal" case.
__leave_with___finally()101*67e74705SXin Li int __leave_with___finally() {
102*67e74705SXin Li   int myres = 0;
103*67e74705SXin Li   __try {
104*67e74705SXin Li     g();
105*67e74705SXin Li     __leave;
106*67e74705SXin Li     myres = 23;
107*67e74705SXin Li   } __finally {
108*67e74705SXin Li     return 0;
109*67e74705SXin Li   }
110*67e74705SXin Li   return 1;
111*67e74705SXin Li }
112*67e74705SXin Li // CHECK-LABEL: define i32 @__leave_with___finally()
113*67e74705SXin Li // CHECK: invoke void @g()
114*67e74705SXin Li // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
115*67e74705SXin Li // For __finally, there needs to be an explicit __try.__leave, because
116*67e74705SXin Li // abnormal.termination.slot needs to be set there.
117*67e74705SXin Li // CHECK: [[cont]]
118*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
119*67e74705SXin Li // CHECK-NOT: store i32 23
120*67e74705SXin Li // CHECK: [[tryleave]]
121*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
122*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i8 0, i8* %[[fp]])
123*67e74705SXin Li 
124*67e74705SXin Li 
125*67e74705SXin Li //////////////////////////////////////////////////////////////////////////////
126*67e74705SXin Li // Mixed, nested cases.
127*67e74705SXin Li 
nested___except___finally()128*67e74705SXin Li int nested___except___finally() {
129*67e74705SXin Li   int myres = 0;
130*67e74705SXin Li   __try {
131*67e74705SXin Li     __try {
132*67e74705SXin Li       g();
133*67e74705SXin Li     } __finally {
134*67e74705SXin Li       g();
135*67e74705SXin Li       __leave;  // Refers to the outer __try, not the __finally!
136*67e74705SXin Li       myres = 23;
137*67e74705SXin Li       return 0;
138*67e74705SXin Li     }
139*67e74705SXin Li 
140*67e74705SXin Li     myres = 51;
141*67e74705SXin Li   } __except (1) {
142*67e74705SXin Li   }
143*67e74705SXin Li   return 1;
144*67e74705SXin Li }
145*67e74705SXin Li // CHECK-LABEL: define i32 @nested___except___finally()
146*67e74705SXin Li 
147*67e74705SXin Li // CHECK-LABEL: invoke void @g()
148*67e74705SXin Li // CHECK-NEXT:       to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]]
149*67e74705SXin Li 
150*67e74705SXin Li // CHECK: [[g1_cont1]]
151*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
152*67e74705SXin Li // CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 0, i8* %[[fp]])
153*67e74705SXin Li // CHECK-NEXT:       to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]]
154*67e74705SXin Li 
155*67e74705SXin Li // CHECK: [[fin_cont]]
156*67e74705SXin Li // CHECK: store i32 51, i32* %
157*67e74705SXin Li // CHECK-NEXT: br label %[[trycont:[^ ]*]]
158*67e74705SXin Li 
159*67e74705SXin Li // CHECK: [[g1_lpad]]
160*67e74705SXin Li // CHECK-NEXT: cleanuppad
161*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
162*67e74705SXin Li // CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]])
163*67e74705SXin Li // CHECK-NEXT:       to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]
164*67e74705SXin Li // CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]]
165*67e74705SXin Li 
166*67e74705SXin Li // CHECK: [[g2_lpad]]
167*67e74705SXin Li // CHECK: catchpad {{.*}} [i8* null]
168*67e74705SXin Li // CHECK: catchret
169*67e74705SXin Li // CHECK: br label %[[trycont]]
170*67e74705SXin Li 
171*67e74705SXin Li // CHECK: [[trycont]]
172*67e74705SXin Li // CHECK-NEXT: ret i32 1
173*67e74705SXin Li 
174*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
175*67e74705SXin Li // CHECK: call void @g()
176*67e74705SXin Li // CHECK: unreachable
177*67e74705SXin Li 
nested___except___except()178*67e74705SXin Li int nested___except___except() {
179*67e74705SXin Li   int myres = 0;
180*67e74705SXin Li   __try {
181*67e74705SXin Li     __try {
182*67e74705SXin Li       g();
183*67e74705SXin Li       myres = 16;
184*67e74705SXin Li     } __except (1) {
185*67e74705SXin Li       g();
186*67e74705SXin Li       __leave;  // Refers to the outer __try, not the __except we're in!
187*67e74705SXin Li       myres = 23;
188*67e74705SXin Li       return 0;
189*67e74705SXin Li     }
190*67e74705SXin Li 
191*67e74705SXin Li     myres = 51;
192*67e74705SXin Li   } __except (1) {
193*67e74705SXin Li   }
194*67e74705SXin Li   return 1;
195*67e74705SXin Li }
196*67e74705SXin Li // The order of basic blocks in the below doesn't matter.
197*67e74705SXin Li // CHECK-LABEL: define i32 @nested___except___except()
198*67e74705SXin Li 
199*67e74705SXin Li // CHECK-LABEL: invoke void @g()
200*67e74705SXin Li // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
201*67e74705SXin Li 
202*67e74705SXin Li // CHECK: [[g1_lpad]]
203*67e74705SXin Li // CHECK: catchpad {{.*}} [i8* null]
204*67e74705SXin Li // CHECK: catchret {{.*}} to label %[[except:[^ ]*]]
205*67e74705SXin Li // CHECK: [[except]]
206*67e74705SXin Li // CHECK: invoke void @g()
207*67e74705SXin Li // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
208*67e74705SXin Li 
209*67e74705SXin Li // CHECK: [[g2_lpad]]
210*67e74705SXin Li // CHECK: catchpad {{.*}} [i8* null]
211*67e74705SXin Li // CHECK: catchret
212*67e74705SXin Li // CHECK: br label %[[trycont4:[^ ]*]]
213*67e74705SXin Li 
214*67e74705SXin Li // CHECK: [[trycont4]]
215*67e74705SXin Li // CHECK-NEXT: ret i32 1
216*67e74705SXin Li 
217*67e74705SXin Li // CHECK: [[g2_cont]]
218*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
219*67e74705SXin Li // CHECK-NOT: store i32 23
220*67e74705SXin Li 
221*67e74705SXin Li // CHECK: [[g1_cont]]
222*67e74705SXin Li // CHECK: store i32 16, i32* %myres
223*67e74705SXin Li // CHECK-NEXT: br label %[[trycont:[^ ]*]]
224*67e74705SXin Li 
225*67e74705SXin Li // CHECK: [[trycont]]
226*67e74705SXin Li // CHECK-NEXT: store i32 51, i32* %myres
227*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave]]
228*67e74705SXin Li 
229*67e74705SXin Li // CHECK: [[tryleave]]
230*67e74705SXin Li // CHECK-NEXT: br label %[[trycont4]]
231*67e74705SXin Li 
nested___finally___except()232*67e74705SXin Li int nested___finally___except() {
233*67e74705SXin Li   int myres = 0;
234*67e74705SXin Li   __try {
235*67e74705SXin Li     __try {
236*67e74705SXin Li       g();
237*67e74705SXin Li     } __except (1) {
238*67e74705SXin Li       g();
239*67e74705SXin Li       __leave;  // Refers to the outer __try, not the __except!
240*67e74705SXin Li       myres = 23;
241*67e74705SXin Li       return 0;
242*67e74705SXin Li     }
243*67e74705SXin Li 
244*67e74705SXin Li     myres = 51;
245*67e74705SXin Li   } __finally {
246*67e74705SXin Li   }
247*67e74705SXin Li   return 1;
248*67e74705SXin Li }
249*67e74705SXin Li // The order of basic blocks in the below doesn't matter.
250*67e74705SXin Li // CHECK-LABEL: define i32 @nested___finally___except()
251*67e74705SXin Li 
252*67e74705SXin Li // CHECK-LABEL: invoke void @g()
253*67e74705SXin Li // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
254*67e74705SXin Li 
255*67e74705SXin Li // CHECK: [[g1_lpad]]
256*67e74705SXin Li // CHECK: catchpad
257*67e74705SXin Li // CHECK: catchret
258*67e74705SXin Li // CHECK: invoke void @g()
259*67e74705SXin Li // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
260*67e74705SXin Li 
261*67e74705SXin Li // CHECK: [[g2_cont]]
262*67e74705SXin Li // CHECK: br label %[[tryleave:[^ ]*]]
263*67e74705SXin Li // CHECK-NOT: 23
264*67e74705SXin Li 
265*67e74705SXin Li // CHECK: [[g1_cont]]
266*67e74705SXin Li // CHECK-NEXT: br label %[[trycont:[^ ]*]]
267*67e74705SXin Li 
268*67e74705SXin Li // CHECK: [[trycont]]
269*67e74705SXin Li // CHECK: store i32 51, i32* %
270*67e74705SXin Li // CHECK-NEXT: br label %[[tryleave]]
271*67e74705SXin Li 
272*67e74705SXin Li // CHECK: [[tryleave]]
273*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
274*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 0, i8* %[[fp]])
275*67e74705SXin Li // CHECK-NEXT: ret i32 1
276*67e74705SXin Li 
277*67e74705SXin Li // CHECK: [[g2_lpad]]
278*67e74705SXin Li // CHECK: cleanuppad
279*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
280*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]])
281*67e74705SXin Li // CHECK: cleanupret {{.*}} unwind to caller
282*67e74705SXin Li 
283*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i8 %abnormal_termination, i8* %frame_pointer)
284*67e74705SXin Li // CHECK: ret void
285*67e74705SXin Li 
nested___finally___finally()286*67e74705SXin Li int nested___finally___finally() {
287*67e74705SXin Li   int myres = 0;
288*67e74705SXin Li   __try {
289*67e74705SXin Li     __try {
290*67e74705SXin Li       g();
291*67e74705SXin Li       myres = 16;
292*67e74705SXin Li     } __finally {
293*67e74705SXin Li       g();
294*67e74705SXin Li       __leave;  // Refers to the outer __try, not the __finally we're in!
295*67e74705SXin Li       myres = 23;
296*67e74705SXin Li       return 0;
297*67e74705SXin Li     }
298*67e74705SXin Li 
299*67e74705SXin Li     myres = 51;
300*67e74705SXin Li   } __finally {
301*67e74705SXin Li   }
302*67e74705SXin Li   return 1;
303*67e74705SXin Li }
304*67e74705SXin Li // The order of basic blocks in the below doesn't matter.
305*67e74705SXin Li // CHECK-LABEL: define i32 @nested___finally___finally()
306*67e74705SXin Li 
307*67e74705SXin Li // CHECK: invoke void @g()
308*67e74705SXin Li // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
309*67e74705SXin Li 
310*67e74705SXin Li // CHECK: [[g1_cont]]
311*67e74705SXin Li // CHECK: store i32 16, i32* %[[myres:[^ ]*]],
312*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
313*67e74705SXin Li // CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]])
314*67e74705SXin Li // CHECK-NEXT:       to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]]
315*67e74705SXin Li 
316*67e74705SXin Li // CHECK: [[finally_cont]]
317*67e74705SXin Li // CHECK: store i32 51, i32* %[[myres]]
318*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
319*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]])
320*67e74705SXin Li // CHECK-NEXT: ret i32 1
321*67e74705SXin Li 
322*67e74705SXin Li // CHECK: [[g1_lpad]]
323*67e74705SXin Li // CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none []
324*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
325*67e74705SXin Li // CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]])
326*67e74705SXin Li // CHECK-NEXT:       to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]
327*67e74705SXin Li // CHECK: [[finally_cont2]]
328*67e74705SXin Li // CHECK: cleanupret from %[[padtoken]] unwind label %[[g2_lpad]]
329*67e74705SXin Li 
330*67e74705SXin Li // CHECK: [[g2_lpad]]
331*67e74705SXin Li // CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none []
332*67e74705SXin Li // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
333*67e74705SXin Li // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]])
334*67e74705SXin Li // CHECK: cleanupret from %[[padtoken]] unwind to caller
335*67e74705SXin Li 
336*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
337*67e74705SXin Li // CHECK: ret void
338*67e74705SXin Li 
339*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
340*67e74705SXin Li // CHECK: call void @g()
341*67e74705SXin Li // CHECK: unreachable
342