[WinEH] Add comments explaining the EH tables
[oota-llvm.git] / test / CodeGen / X86 / win32-seh-catchpad.ll
1 ; RUN: llc < %s | FileCheck %s
2
3 target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
4 target triple = "i686-pc-windows-msvc"
5
6 define void @try_except() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
7 entry:
8   %__exception_code = alloca i32, align 4
9   call void (...) @llvm.localescape(i32* %__exception_code)
10   invoke void @f(i32 1) #3
11           to label %invoke.cont unwind label %catch.dispatch
12
13 catch.dispatch:                                   ; preds = %entry
14   %cs1 = catchswitch within none [label %__except.ret] unwind to caller
15
16 __except.ret:                                     ; preds = %catch.dispatch
17   %0 = catchpad within %cs1 [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)]
18   catchret from %0 to label %__except
19
20 __except:                                         ; preds = %__except.ret
21   call void @f(i32 2)
22   br label %__try.cont
23
24 __try.cont:                                       ; preds = %__except, %invoke.cont
25   call void @f(i32 3)
26   ret void
27
28 invoke.cont:                                      ; preds = %entry
29   br label %__try.cont
30 }
31
32 ; CHECK-LABEL: _try_except:
33 ;     Store state #0
34 ; CHECK: movl $0, -[[state:[0-9]+]](%ebp)
35 ; CHECK: movl $1, (%esp)
36 ; CHECK: calll _f
37 ; CHECK: movl $-1, -[[state]](%ebp)
38 ; CHECK: movl $3, (%esp)
39 ; CHECK: calll _f
40 ; CHECK: retl
41
42 ;   __except
43 ; CHECK: movl $-1, -[[state]](%ebp)
44 ; CHECK: movl $2, (%esp)
45 ; CHECK: calll _f
46
47 ; CHECK: .section        .xdata,"dr"
48 ; CHECK: L__ehtable$try_except:
49 ; CHECK:         .long   -1                          # ToState
50 ; CHECK:         .long   _try_except_filter_catchall # Filter
51 ; CHECK:         .long   LBB0_1
52
53 define internal i32 @try_except_filter_catchall() #0 {
54 entry:
55   %0 = call i8* @llvm.frameaddress(i32 1)
56   %1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @try_except to i8*), i8* %0)
57   %2 = call i8* @llvm.localrecover(i8* bitcast (void ()* @try_except to i8*), i8* %1, i32 0)
58   %__exception_code = bitcast i8* %2 to i32*
59   %3 = getelementptr inbounds i8, i8* %0, i32 -20
60   %4 = bitcast i8* %3 to i8**
61   %5 = load i8*, i8** %4, align 4
62   %6 = bitcast i8* %5 to { i32*, i8* }*
63   %7 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %6, i32 0, i32 0
64   %8 = load i32*, i32** %7, align 4
65   %9 = load i32, i32* %8, align 4
66   store i32 %9, i32* %__exception_code, align 4
67   ret i32 1
68 }
69
70 define void @nested_exceptions() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
71 entry:
72   %__exception_code = alloca i32, align 4
73   call void (...) @llvm.localescape(i32* %__exception_code)
74   invoke void @crash() #3
75           to label %__try.cont unwind label %catch.dispatch
76
77 catch.dispatch:                                   ; preds = %entry
78   %cs1 = catchswitch within none [label %__except.ret] unwind label %catch.dispatch.11
79
80 __except.ret:                                     ; preds = %catch.dispatch
81   %0 = catchpad within %cs1 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
82   catchret from %0 to label %__try.cont
83
84 __try.cont:                                       ; preds = %entry, %__except.ret
85   invoke void @crash() #3
86           to label %__try.cont.9 unwind label %catch.dispatch.5
87
88 catch.dispatch.5:                                 ; preds = %__try.cont
89   %cs2 = catchswitch within none [label %__except.ret.7] unwind label %catch.dispatch.11
90
91 __except.ret.7:                                   ; preds = %catch.dispatch.5
92   %1 = catchpad within %cs2 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
93   catchret from %1 to label %__try.cont.9
94
95 __try.cont.9:                                     ; preds = %__try.cont, %__except.ret.7
96   invoke void @crash() #3
97           to label %__try.cont.15 unwind label %catch.dispatch.11
98
99 catch.dispatch.11:                                ; preds = %catchendblock, %catchendblock.6, %__try.cont.9
100   %cs3 = catchswitch within none [label %__except.ret.13] unwind label %catch.dispatch.17
101
102 __except.ret.13:                                  ; preds = %catch.dispatch.11
103   %2 = catchpad within %cs3 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
104   catchret from %2 to label %__try.cont.15
105
106 __try.cont.15:                                    ; preds = %__try.cont.9, %__except.ret.13
107   invoke void @crash() #3
108           to label %__try.cont.35 unwind label %catch.dispatch.17
109
110 catch.dispatch.17:                                ; preds = %catchendblock.12, %__try.cont.15
111   %cs4 = catchswitch within none [label %__except.ret.19] unwind to caller
112
113 __except.ret.19:                                  ; preds = %catch.dispatch.17
114   %3 = catchpad within %cs4 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
115   catchret from %3 to label %__except.20
116
117 __except.20:                                      ; preds = %__except.ret.19
118   invoke void @crash() #3
119           to label %__try.cont.27 unwind label %catch.dispatch.23
120
121 catch.dispatch.23:                                ; preds = %__except.20
122   %cs5 = catchswitch within none [label %__except.ret.25] unwind to caller
123
124 __except.ret.25:                                  ; preds = %catch.dispatch.23
125   %4 = catchpad within %cs5 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
126   catchret from %4 to label %__try.cont.27
127
128 __try.cont.27:                                    ; preds = %__except.20, %__except.ret.25
129   invoke void @crash() #3
130           to label %__try.cont.35 unwind label %catch.dispatch.30
131
132 catch.dispatch.30:                                ; preds = %__try.cont.27
133   %cs6 = catchswitch within none [label %__except.ret.32] unwind to caller
134
135 __except.ret.32:                                  ; preds = %catch.dispatch.30
136   %5 = catchpad within %cs6 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
137   catchret from %5 to label %__try.cont.35
138
139 __try.cont.35:                                    ; preds = %__try.cont.15, %__try.cont.27, %__except.ret.32
140   ret void
141 }
142
143 ; This table is equivalent to the one produced by MSVC, even if it isn't in
144 ; quite the same order.
145
146 ; CHECK-LABEL: _nested_exceptions:
147 ; CHECK: L__ehtable$nested_exceptions:
148 ; CHECK:         .long   -1
149 ; CHECK:         .long   _nested_exceptions_filter_catchall
150 ; CHECK:         .long   LBB
151 ; CHECK:         .long   0
152 ; CHECK:         .long   _nested_exceptions_filter_catchall
153 ; CHECK:         .long   LBB
154 ; CHECK:         .long   1
155 ; CHECK:         .long   _nested_exceptions_filter_catchall
156 ; CHECK:         .long   LBB
157 ; CHECK:         .long   1
158 ; CHECK:         .long   _nested_exceptions_filter_catchall
159 ; CHECK:         .long   LBB
160 ; CHECK:         .long   -1
161 ; CHECK:         .long   _nested_exceptions_filter_catchall
162 ; CHECK:         .long   LBB
163 ; CHECK:         .long   -1
164 ; CHECK:         .long   _nested_exceptions_filter_catchall
165 ; CHECK:         .long   LBB
166
167 declare void @crash() #0
168
169 define internal i32 @nested_exceptions_filter_catchall() #0 {
170 entry:
171   %0 = call i8* @llvm.frameaddress(i32 1)
172   %1 = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @nested_exceptions to i8*), i8* %0)
173   %2 = call i8* @llvm.localrecover(i8* bitcast (void ()* @nested_exceptions to i8*), i8* %1, i32 0)
174   %__exception_code3 = bitcast i8* %2 to i32*
175   %3 = getelementptr inbounds i8, i8* %0, i32 -20
176   %4 = bitcast i8* %3 to i8**
177   %5 = load i8*, i8** %4, align 4
178   %6 = bitcast i8* %5 to { i32*, i8* }*
179   %7 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %6, i32 0, i32 0
180   %8 = load i32*, i32** %7, align 4
181   %9 = load i32, i32* %8, align 4
182   store i32 %9, i32* %__exception_code3, align 4
183   ret i32 1
184 }
185
186 define void @code_in_catchpad() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
187 entry:
188   invoke void @f(i32 1) #3
189           to label %__except unwind label %catch.dispatch
190
191 catch.dispatch:                                   ; preds = %entry
192   %cs1 = catchswitch within none [label %__except.ret] unwind to caller
193
194 __except.ret:                                     ; preds = %catch.dispatch
195   %0 = catchpad within %cs1 [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)]
196   call void @f(i32 2) [ "funclet"(token %0) ]
197   catchret from %0 to label %__except
198
199 __except:
200   ret void
201 }
202
203 ; CHECK-LABEL: _code_in_catchpad:
204 ; CHECK: # %__except.ret
205 ; CHECK-NEXT:         movl    -24(%ebp), %esp
206 ; CHECK-NEXT:         addl    $12, %ebp
207 ; CHECK-NEXT:         movl    $-1, -16(%ebp)
208 ; CHECK-NEXT:         movl    $2, (%esp)
209 ; CHECK-NEXT:         calll   _f
210
211
212 ; Function Attrs: nounwind readnone
213 declare i8* @llvm.frameaddress(i32) #1
214
215 ; Function Attrs: nounwind readnone
216 declare i8* @llvm.x86.seh.recoverfp(i8*, i8*) #1
217
218 ; Function Attrs: nounwind readnone
219 declare i8* @llvm.localrecover(i8*, i8*, i32) #1
220
221 declare void @f(i32) #0
222
223 declare i32 @_except_handler3(...)
224
225 ; Function Attrs: nounwind
226 declare void @llvm.localescape(...) #2
227
228 attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
229 attributes #1 = { nounwind readnone }
230 attributes #2 = { nounwind }
231 attributes #3 = { noinline }