Clang Project

clang_source_code/test/CodeGen/exceptions-seh.c
1// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - \
2// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X64
3// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - \
4// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X86
5// RUN: %clang_cc1 %s -triple aarch64-windows -fms-extensions -emit-llvm -o - \
6// RUN:         | FileCheck %s --check-prefixes=CHECK,ARM64
7// RUN: %clang_cc1 %s -triple i686-pc-windows-gnu -fms-extensions -emit-llvm -o - \
8// RUN:         | FileCheck %s --check-prefix=X86-GNU
9// RUN: %clang_cc1 %s -triple x86_64-pc-windows-gnu -fms-extensions -emit-llvm -o - \
10// RUN:         | FileCheck %s --check-prefix=X64-GNU
11
12void try_body(int numerator, int denominator, int *myres) {
13  *myres = numerator / denominator;
14}
15// CHECK-LABEL: define dso_local void @try_body(i32 %numerator, i32 %denominator, i32* %myres)
16// CHECK: sdiv i32
17// CHECK: store i32 %{{.*}}, i32*
18// CHECK: ret void
19
20int safe_div(int numerator, int denominator, int *res) {
21  int myres = 0;
22  int success = 1;
23  __try {
24    try_body(numerator, denominator, &myres);
25  } __except (1) {
26    success = -42;
27  }
28  *res = myres;
29  return success;
30}
31
32// CHECK-LABEL: define dso_local i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res)
33// X64-SAME:      personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
34// ARM64-SAME:    personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
35// X86-SAME:      personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
36// CHECK: invoke void @try_body(i32 %{{.*}}, i32 %{{.*}}, i32* %{{.*}}) #[[NOINLINE:[0-9]+]]
37// CHECK:       to label %{{.*}} unwind label %[[catchpad:[^ ]*]]
38//
39// CHECK: [[catchpad]]
40// X64: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [i8* null]
41// ARM64: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [i8* null]
42// X86: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [i8* bitcast (i32 ()* @"?filt$0@0@safe_div@@" to i8*)]
43// CHECK-NEXT: catchret from %[[padtoken]] to label %[[except:[^ ]*]]
44//
45// CHECK: [[except]]
46// CHECK: store i32 -42, i32* %[[success:[^ ]*]]
47//
48// CHECK: %[[res:[^ ]*]] = load i32, i32* %[[success]]
49// CHECK: ret i32 %[[res]]
50
51// 32-bit SEH needs this filter to save the exception code.
52//
53// X86-LABEL: define internal i32 @"?filt$0@0@safe_div@@"()
54// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
55// X86: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[ebp]])
56// X86: call i8* @llvm.localrecover(i8* bitcast (i32 (i32, i32, i32*)* @safe_div to i8*), i8* %[[fp]], i32 0)
57// X86: load i8*, i8**
58// X86: load i32*, i32**
59// X86: load i32, i32*
60// X86: store i32 %{{.*}}, i32*
61// X86: ret i32 1
62
63// Mingw uses msvcrt, so it can also use _except_handler3.
64// X86-GNU-LABEL: define dso_local i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res)
65// X86-GNU-SAME:      personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
66// X64-GNU-LABEL: define dso_local i32 @safe_div(i32 %numerator, i32 %denominator, i32* %res)
67// X64-GNU-SAME:      personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
68
69void j(void);
70
71int filter_expr_capture(void) {
72  int r = 42;
73  __try {
74    j();
75  } __except(r = -1) {
76    r = 13;
77  }
78  return r;
79}
80
81// CHECK-LABEL: define dso_local i32 @filter_expr_capture()
82// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
83// ARM64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
84// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
85// X64: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]])
86// ARM64: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]])
87// X86: call void (...) @llvm.localescape(i32* %[[r:[^ ,]*]], i32* %[[code:[^ ,]*]])
88// CHECK: store i32 42, i32* %[[r]]
89// CHECK: invoke void @j() #[[NOINLINE]]
90//
91// CHECK: catchpad within %{{[^ ]*}} [i8* bitcast (i32 ({{.*}})* @"?filt$0@0@filter_expr_capture@@" to i8*)]
92// CHECK: store i32 13, i32* %[[r]]
93//
94// CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]]
95// CHECK: ret i32 %[[rv]]
96
97// X64-LABEL: define internal i32 @"?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer)
98// X64: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer)
99// X64: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0)
100//
101// ARM64-LABEL: define internal i32 @"?filt$0@0@filter_expr_capture@@"(i8* %exception_pointers, i8* %frame_pointer)
102// ARM64: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %frame_pointer)
103// ARM64: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0)
104//
105// X86-LABEL: define internal i32 @"?filt$0@0@filter_expr_capture@@"()
106// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
107// X86: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[ebp]])
108// X86: call i8* @llvm.localrecover(i8* bitcast (i32 ()* @filter_expr_capture to i8*), i8* %[[fp]], i32 0)
109//
110// CHECK: store i32 -1, i32* %{{.*}}
111// CHECK: ret i32 -1
112
113int nested_try(void) {
114  int r = 42;
115  __try {
116    __try {
117      j();
118      r = 0;
119    } __except(_exception_code() == 123) {
120      r = 123;
121    }
122  } __except(_exception_code() == 456) {
123    r = 456;
124  }
125  return r;
126}
127// CHECK-LABEL: define dso_local i32 @nested_try()
128// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
129// ARM64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
130// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
131// CHECK: store i32 42, i32* %[[r:[^ ,]*]]
132// CHECK: invoke void @j() #[[NOINLINE]]
133// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[cswitch_inner:[^ ]*]]
134//
135// CHECK: [[cswitch_inner]]
136// CHECK: %[[cs_inner:[^ ]*]] = catchswitch within none [label %[[cpad_inner:[^ ]*]]] unwind label %[[cswitch_outer:[^ ]*]]
137//
138// CHECK: [[cswitch_outer]]
139// CHECK: %[[cs_outer:[^ ]*]] = catchswitch within none [label %[[cpad_outer:[^ ]*]]] unwind to caller
140//
141// CHECK: [[cpad_outer]]
142// CHECK: catchpad within %{{[^ ]*}} [i8* bitcast (i32 ({{.*}})* @"?filt$0@0@nested_try@@" to i8*)]
143// CHECK-NEXT: catchret {{.*}} to label %[[except_outer:[^ ]*]]
144//
145// CHECK: [[except_outer]]
146// CHECK: store i32 456, i32* %[[r]]
147// CHECK: br label %[[outer_try_cont:[^ ]*]]
148//
149// CHECK: [[outer_try_cont]]
150// CHECK: %[[r_load:[^ ]*]] = load i32, i32* %[[r]]
151// CHECK: ret i32 %[[r_load]]
152//
153// CHECK: [[cpad_inner]]
154// CHECK: catchpad within %[[cs_inner]] [i8* bitcast (i32 ({{.*}})* @"?filt$1@0@nested_try@@" to i8*)]
155// CHECK-NEXT: catchret {{.*}} to label %[[except_inner:[^ ]*]]
156//
157// CHECK: [[except_inner]]
158// CHECK: store i32 123, i32* %[[r]]
159// CHECK: br label %[[inner_try_cont:[^ ]*]]
160//
161// CHECK: [[inner_try_cont]]
162// CHECK: br label %[[outer_try_cont]]
163//
164// CHECK: [[cont]]
165// CHECK: store i32 0, i32* %[[r]]
166// CHECK: br label %[[inner_try_cont]]
167//
168// CHECK-LABEL: define internal i32 @"?filt$0@0@nested_try@@"({{.*}})
169// X86: call i8* @llvm.eh.recoverfp({{.*}})
170// CHECK: load i32*, i32**
171// CHECK: load i32, i32*
172// CHECK: icmp eq i32 %{{.*}}, 456
173//
174// CHECK-LABEL: define internal i32 @"?filt$1@0@nested_try@@"({{.*}})
175// X86: call i8* @llvm.eh.recoverfp({{.*}})
176// CHECK: load i32*, i32**
177// CHECK: load i32, i32*
178// CHECK: icmp eq i32 %{{.*}}, 123
179
180int basic_finally(int g) {
181  __try {
182    j();
183  } __finally {
184    ++g;
185  }
186  return g;
187}
188// CHECK-LABEL: define dso_local i32 @basic_finally(i32 %g)
189// X64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
190// ARM64-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
191// X86-SAME: personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
192// CHECK: %[[g_addr:[^ ]*]] = alloca i32, align 4
193// CHECK: call void (...) @llvm.localescape(i32* %[[g_addr]])
194// CHECK: store i32 %g, i32* %[[g_addr]]
195//
196// CHECK: invoke void @j()
197// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[cleanuppad:[^ ]*]]
198//
199// CHECK: [[cont]]
200// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
201// CHECK: call void @"?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
202// CHECK: load i32, i32* %[[g_addr]], align 4
203// CHECK: ret i32
204//
205// CHECK: [[cleanuppad]]
206// CHECK: %[[padtoken:[^ ]*]] = cleanuppad within none []
207// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
208// CHECK: call void @"?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
209// CHECK: cleanupret from %[[padtoken]] unwind to caller
210
211// CHECK: define internal void @"?fin$0@0@basic_finally@@"({{i8( zeroext)?}} %abnormal_termination, i8* %frame_pointer)
212// CHECK:   call i8* @llvm.localrecover(i8* bitcast (i32 (i32)* @basic_finally to i8*), i8* %frame_pointer, i32 0)
213// CHECK:   load i32, i32* %{{.*}}, align 4
214// CHECK:   add nsw i32 %{{.*}}, 1
215// CHECK:   store i32 %{{.*}}, i32* %{{.*}}, align 4
216// CHECK:   ret void
217
218int returns_int(void);
219int except_return(void) {
220  __try {
221    return returns_int();
222  } __except(1) {
223    return 42;
224  }
225}
226// CHECK-LABEL: define dso_local i32 @except_return()
227// CHECK: %[[tmp:[^ ]*]] = invoke i32 @returns_int()
228// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[catchpad:[^ ]*]]
229//
230// CHECK: [[catchpad]]
231// CHECK: catchpad
232// CHECK: catchret
233// CHECK: store i32 42, i32* %[[rv:[^ ]*]]
234// CHECK: br label %[[retbb:[^ ]*]]
235//
236// CHECK: [[cont]]
237// CHECK: store i32 %[[tmp]], i32* %[[rv]]
238// CHECK: br label %[[retbb]]
239//
240// CHECK: [[retbb]]
241// CHECK: %[[r:[^ ]*]] = load i32, i32* %[[rv]]
242// CHECK: ret i32 %[[r]]
243
244
245// PR 24751: don't assert if a variable is used twice in a __finally block.
246// Also, make sure we don't do redundant work to capture/project it.
247void finally_capture_twice(int x) {
248  __try {
249  } __finally {
250    int y = x;
251    int z = x;
252  }
253}
254//
255// CHECK-LABEL: define dso_local void @finally_capture_twice(
256// CHECK:         [[X:%.*]] = alloca i32, align 4
257// CHECK:         call void (...) @llvm.localescape(i32* [[X]])
258// CHECK-NEXT:    store i32 {{.*}}, i32* [[X]], align 4
259// CHECK-NEXT:    [[LOCAL:%.*]] = call i8* @llvm.localaddress()
260// CHECK-NEXT:    call void [[FINALLY:@.*]](i8{{ zeroext | }}0, i8* [[LOCAL]])
261// CHECK:       define internal void [[FINALLY]](
262// CHECK:         [[LOCAL:%.*]] = call i8* @llvm.localrecover(
263// CHECK:         [[X:%.*]] = bitcast i8* [[LOCAL]] to i32*
264// CHECK-NEXT:    [[Y:%.*]] = alloca i32, align 4
265// CHECK-NEXT:    [[Z:%.*]] = alloca i32, align 4
266// CHECK-NEXT:    store i8*
267// CHECK-NEXT:    store i8
268// CHECK-NEXT:    [[T0:%.*]] = load i32, i32* [[X]], align 4
269// CHECK-NEXT:    store i32 [[T0]], i32* [[Y]], align 4
270// CHECK-NEXT:    [[T0:%.*]] = load i32, i32* [[X]], align 4
271// CHECK-NEXT:    store i32 [[T0]], i32* [[Z]], align 4
272// CHECK-NEXT:    ret void
273
274int exception_code_in_except(void) {
275  __try {
276    try_body(0, 0, 0);
277  } __except(1) {
278    return _exception_code();
279  }
280}
281
282// CHECK-LABEL: define dso_local i32 @exception_code_in_except()
283// CHECK: %[[ret_slot:[^ ]*]] = alloca i32
284// CHECK: %[[code_slot:[^ ]*]] = alloca i32
285// CHECK: invoke void @try_body(i32 0, i32 0, i32* null)
286// CHECK: %[[pad:[^ ]*]] = catchpad
287// CHECK: catchret from %[[pad]]
288// X64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]])
289// X64: store i32 %[[code]], i32* %[[code_slot]]
290// ARM64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]])
291// ARM64: store i32 %[[code]], i32* %[[code_slot]]
292// CHECK: %[[ret1:[^ ]*]] = load i32, i32* %[[code_slot]]
293// CHECK: store i32 %[[ret1]], i32* %[[ret_slot]]
294// CHECK: %[[ret2:[^ ]*]] = load i32, i32* %[[ret_slot]]
295// CHECK: ret i32 %[[ret2]]
296
297// CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
298