• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: llc -mtriple i686-pc-windows-msvc < %s | FileCheck %s
2
3; This test case is also intended to be run manually as a complete functional
4; test. It should link, print something, and exit zero rather than crashing.
5; It is the hypothetical lowering of a C source program that looks like:
6;
7;   int safe_div(int *n, int *d) {
8;     int r;
9;     __try {
10;       __try {
11;         r = *n / *d;
12;       } __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) {
13;         puts("EXCEPTION_ACCESS_VIOLATION");
14;         r = -1;
15;       }
16;     } __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
17;       puts("EXCEPTION_INT_DIVIDE_BY_ZERO");
18;       r = -2;
19;     }
20;     return r;
21;   }
22
23@str1 = internal constant [27 x i8] c"EXCEPTION_ACCESS_VIOLATION\00"
24@str2 = internal constant [29 x i8] c"EXCEPTION_INT_DIVIDE_BY_ZERO\00"
25
26define i32 @safe_div(i32* %n, i32* %d) personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
27entry:
28  %r = alloca i32, align 4
29  store i32 42, i32* %r
30  invoke void @try_body(i32* %r, i32* %n, i32* %d)
31          to label %__try.cont unwind label %lpad0
32
33lpad0:
34  %cs0 = catchswitch within none [label %handler0] unwind label %lpad1
35
36handler0:
37  %p0 = catchpad within %cs0 [i8* bitcast (i32 ()* @safe_div_filt0 to i8*)]
38  call void @puts(i8* getelementptr ([27 x i8], [27 x i8]* @str1, i32 0, i32 0)) [ "funclet"(token %p0) ]
39  store i32 -1, i32* %r, align 4
40  catchret from %p0 to label %__try.cont
41
42lpad1:
43  %cs1 = catchswitch within none [label %handler1] unwind to caller
44
45handler1:
46  %p1 = catchpad within %cs1 [i8* bitcast (i32 ()* @safe_div_filt1 to i8*)]
47  call void @puts(i8* getelementptr ([29 x i8], [29 x i8]* @str2, i32 0, i32 0)) [ "funclet"(token %p1) ]
48  store i32 -2, i32* %r, align 4
49  catchret from %p1 to label %__try.cont
50
51__try.cont:
52  %safe_ret = load i32, i32* %r, align 4
53  ret i32 %safe_ret
54}
55
56; Normal path code
57
58; CHECK: {{^}}_safe_div:
59; CHECK: movl $42, [[rloc:.*\(%ebp\)]]
60; CHECK: leal [[rloc]],
61; CHECK: calll _try_body
62; CHECK: [[cont_bb:LBB0_[0-9]+]]:
63; CHECK: movl [[rloc]], %eax
64; CHECK: retl
65
66; Landing pad code
67
68; CHECK: [[handler1:LBB0_[0-9]+]]: # %handler1
69; 	Restore SP
70; CHECK: movl {{.*}}(%ebp), %esp
71; CHECK: calll _puts
72; CHECK: jmp [[cont_bb]]
73
74; CHECK: [[handler0:LBB0_[0-9]+]]: # %handler0
75; 	Restore SP
76; CHECK: movl {{.*}}(%ebp), %esp
77; CHECK: calll _puts
78; CHECK: jmp [[cont_bb]]
79
80; CHECK: .section .xdata,"dr"
81; CHECK: L__ehtable$safe_div:
82; CHECK-NEXT: .long -1
83; CHECK-NEXT: .long _safe_div_filt1
84; CHECK-NEXT: .long [[handler1]]
85; CHECK-NEXT: .long 0
86; CHECK-NEXT: .long _safe_div_filt0
87; CHECK-NEXT: .long [[handler0]]
88
89define void @try_body(i32* %r, i32* %n, i32* %d) {
90entry:
91  %0 = load i32, i32* %n, align 4
92  %1 = load i32, i32* %d, align 4
93  %div = sdiv i32 %0, %1
94  store i32 %div, i32* %r, align 4
95  ret void
96}
97
98; The prototype of these filter functions is:
99; int filter(EXCEPTION_POINTERS *eh_ptrs, void *rbp);
100
101; The definition of EXCEPTION_POINTERS is:
102;   typedef struct _EXCEPTION_POINTERS {
103;     EXCEPTION_RECORD *ExceptionRecord;
104;     CONTEXT          *ContextRecord;
105;   } EXCEPTION_POINTERS;
106
107; The definition of EXCEPTION_RECORD is:
108;   typedef struct _EXCEPTION_RECORD {
109;     DWORD ExceptionCode;
110;     ...
111;   } EXCEPTION_RECORD;
112
113define i32 @safe_div_filt0() {
114  %ebp = call i8* @llvm.frameaddress(i32 1)
115  %eh_ptrs.addr.i8 = getelementptr inbounds i8, i8* %ebp, i32 -20
116  %eh_ptrs.addr = bitcast i8* %eh_ptrs.addr.i8 to i32***
117  %eh_ptrs = load i32**, i32*** %eh_ptrs.addr
118  %eh_rec = load i32*, i32** %eh_ptrs
119  %eh_code = load i32, i32* %eh_rec
120  ; EXCEPTION_ACCESS_VIOLATION = 0xC0000005
121  %cmp = icmp eq i32 %eh_code, 3221225477
122  %filt.res = zext i1 %cmp to i32
123  ret i32 %filt.res
124}
125define i32 @safe_div_filt1() {
126  %ebp = call i8* @llvm.frameaddress(i32 1)
127  %eh_ptrs.addr.i8 = getelementptr inbounds i8, i8* %ebp, i32 -20
128  %eh_ptrs.addr = bitcast i8* %eh_ptrs.addr.i8 to i32***
129  %eh_ptrs = load i32**, i32*** %eh_ptrs.addr
130  %eh_rec = load i32*, i32** %eh_ptrs
131  %eh_code = load i32, i32* %eh_rec
132  ; EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094
133  %cmp = icmp eq i32 %eh_code, 3221225620
134  %filt.res = zext i1 %cmp to i32
135  ret i32 %filt.res
136}
137
138@str_result = internal constant [21 x i8] c"safe_div result: %d\0A\00"
139
140define i32 @main() {
141  %d.addr = alloca i32, align 4
142  %n.addr = alloca i32, align 4
143
144  store i32 10, i32* %n.addr, align 4
145  store i32 2, i32* %d.addr, align 4
146  %r1 = call i32 @safe_div(i32* %n.addr, i32* %d.addr)
147  call void (i8*, ...) @printf(i8* getelementptr ([21 x i8], [21 x i8]* @str_result, i32 0, i32 0), i32 %r1)
148
149  store i32 10, i32* %n.addr, align 4
150  store i32 0, i32* %d.addr, align 4
151  %r2 = call i32 @safe_div(i32* %n.addr, i32* %d.addr)
152  call void (i8*, ...) @printf(i8* getelementptr ([21 x i8], [21 x i8]* @str_result, i32 0, i32 0), i32 %r2)
153
154  %r3 = call i32 @safe_div(i32* %n.addr, i32* null)
155  call void (i8*, ...) @printf(i8* getelementptr ([21 x i8], [21 x i8]* @str_result, i32 0, i32 0), i32 %r3)
156  ret i32 0
157}
158
159declare i32 @_except_handler3(...)
160declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
161declare void @puts(i8*)
162declare void @printf(i8*, ...)
163declare void @abort()
164declare i8* @llvm.frameaddress(i32)
165