1 ; RUN: llc -mtriple arm64-windows -o - %s | FileCheck %s
5 ; void foo(struct S o);
10 ; __finally { foo(o.x); }
12 ; void stack_realign() {
13 ; struct S __declspec(align(32)) o;
16 ; __finally { foo(o.x); }
18 ; void vla_present(int n) {
22 ; __finally { foo(n); }
24 ; void vla_and_realign(int n) {
25 ; struct S __declspec(align(32)) o;
29 ; __finally { foo(o.x); }
32 %struct.S = type { i32 }
34 ; Test simple SEH (__try/__finally).
35 define void @simple_seh() #0 personality ptr @__C_specific_handler {
37 ; CHECK-LABEL: simple_seh
38 ; CHECK: add x29, sp, #16
40 ; CHECK: stur x0, [x29, #16]
41 ; CHECK: .set .Lsimple_seh$frame_escape_0, -8
42 ; CHECK: ldur w0, [x29, #-8]
45 %o = alloca %struct.S, align 8
46 call void (...) @llvm.localescape(ptr %o)
47 %0 = load i32, ptr %o, align 4
48 invoke void @foo(i32 %0) #5
49 to label %invoke.cont unwind label %ehcleanup
51 invoke.cont: ; preds = %entry
52 %1 = call ptr @llvm.localaddress()
53 call void @fin_simple_seh(i8 0, ptr %1)
56 ehcleanup: ; preds = %entry
57 %2 = cleanuppad within none []
58 %3 = call ptr @llvm.localaddress()
59 call void @fin_simple_seh(i8 1, ptr %3) [ "funclet"(token %2) ]
60 cleanupret from %2 unwind to caller
63 define void @fin_simple_seh(i8 %abnormal_termination, ptr %frame_pointer) {
65 ; CHECK-LABEL: fin_simple_seh
66 ; CHECK: movz x8, #:abs_g1_s:.Lsimple_seh$frame_escape_0
67 ; CHECK: movk x8, #:abs_g0_nc:.Lsimple_seh$frame_escape_0
68 ; CHECK: strb w0, [sp, #15]
69 ; CHECK: ldr w8, [x1, x8]
72 %frame_pointer.addr = alloca ptr, align 8
73 %abnormal_termination.addr = alloca i8, align 1
74 %0 = call ptr @llvm.localrecover(ptr @simple_seh, ptr %frame_pointer, i32 0)
75 store ptr %frame_pointer, ptr %frame_pointer.addr, align 8
76 store i8 %abnormal_termination, ptr %abnormal_termination.addr, align 1
77 %1 = load i32, ptr %0, align 4
78 call void @foo(i32 %1)
82 ; Test SEH when stack realignment is needed in case highly aligned stack objects are present.
83 define void @stack_realign() #0 personality ptr @__C_specific_handler {
85 ; CHECK-LABEL: stack_realign
86 ; CHECK: add x29, sp, #8
87 ; CHECK: sub x9, sp, #16
88 ; CHECK: and sp, x9, #0xffffffffffffffe0
91 ; CHECK: stur x0, [x29, #24]
92 ; CHECK: .set .Lstack_realign$frame_escape_0, 0
93 ; CHECK: ldr w0, [x19]
96 %o = alloca %struct.S, align 32
97 call void (...) @llvm.localescape(ptr %o)
98 %0 = load i32, ptr %o, align 32
99 invoke void @foo(i32 %0) #5
100 to label %invoke.cont unwind label %ehcleanup
102 invoke.cont: ; preds = %entry
103 %1 = call ptr @llvm.localaddress()
104 call void @fin_stack_realign(i8 0, ptr %1)
107 ehcleanup: ; preds = %entry
108 %2 = cleanuppad within none []
109 %3 = call ptr @llvm.localaddress()
110 call void @fin_stack_realign(i8 1, ptr %3) [ "funclet"(token %2) ]
111 cleanupret from %2 unwind to caller
114 define void @fin_stack_realign(i8 %abnormal_termination, ptr %frame_pointer) {
116 ; CHECK-LABEL: fin_stack_realign
117 ; CHECK: movz x8, #:abs_g1_s:.Lstack_realign$frame_escape_0
118 ; CHECK: movk x8, #:abs_g0_nc:.Lstack_realign$frame_escape_0
119 ; CHECK: strb w0, [sp, #15]
120 ; CHECK: ldr w8, [x1, x8]
123 %frame_pointer.addr = alloca ptr, align 8
124 %abnormal_termination.addr = alloca i8, align 1
125 %0 = call ptr @llvm.localrecover(ptr @stack_realign, ptr %frame_pointer, i32 0)
126 store ptr %frame_pointer, ptr %frame_pointer.addr, align 8
127 store i8 %abnormal_termination, ptr %abnormal_termination.addr, align 1
128 %1 = load i32, ptr %0, align 32
129 call void @foo(i32 %1)
133 ; Test SEH when variable size objects are present on the stack. Note: Escaped vla's are current not supported by SEH.
134 define void @vla_present(i32 %n) #0 personality ptr @__C_specific_handler {
136 ; CHECK-LABEL: vla_present
137 ; CHECK: add x29, sp, #32
139 ; CHECK: stur x1, [x29, #16]
140 ; CHECK: .set .Lvla_present$frame_escape_0, -4
141 ; CHECK: stur w0, [x29, #-4]
142 ; CHECK: ldur w8, [x29, #-4]
144 ; CHECK: stur x9, [x29, #-16]
145 ; CHECK: stur x8, [x29, #-24]
146 ; CHECK: ldur w0, [x29, #-4]
149 %n.addr = alloca i32, align 4
150 %saved_stack = alloca ptr, align 8
151 %__vla_expr0 = alloca i64, align 8
152 call void (...) @llvm.localescape(ptr %n.addr)
153 store i32 %n, ptr %n.addr, align 4
154 %0 = load i32, ptr %n.addr, align 4
155 %1 = zext i32 %0 to i64
156 %2 = call ptr @llvm.stacksave()
157 store ptr %2, ptr %saved_stack, align 8
158 %vla = alloca i32, i64 %1, align 4
159 store i64 %1, ptr %__vla_expr0, align 8
160 %3 = load i32, ptr %n.addr, align 4
161 invoke void @foo(i32 %3) #5
162 to label %invoke.cont unwind label %ehcleanup
164 invoke.cont: ; preds = %entry
165 %4 = call ptr @llvm.localaddress()
166 call void @fin_vla_present(i8 0, ptr %4)
167 %5 = load ptr, ptr %saved_stack, align 8
168 call void @llvm.stackrestore(ptr %5)
171 ehcleanup: ; preds = %entry
172 %6 = cleanuppad within none []
173 %7 = call ptr @llvm.localaddress()
174 call void @fin_vla_present(i8 1, ptr %7) [ "funclet"(token %6) ]
175 cleanupret from %6 unwind to caller
178 define void @fin_vla_present(i8 %abnormal_termination, ptr %frame_pointer) {
180 ; CHECK-LABEL: fin_vla_present
181 ; CHECK: movz x8, #:abs_g1_s:.Lvla_present$frame_escape_0
182 ; CHECK: movk x8, #:abs_g0_nc:.Lvla_present$frame_escape_0
183 ; CHECK: strb w0, [sp, #15]
184 ; CHECK: ldr w8, [x1, x8]
187 %frame_pointer.addr = alloca ptr, align 8
188 %abnormal_termination.addr = alloca i8, align 1
189 %0 = call ptr @llvm.localrecover(ptr @vla_present, ptr %frame_pointer, i32 0)
190 store ptr %frame_pointer, ptr %frame_pointer.addr, align 8
191 store i8 %abnormal_termination, ptr %abnormal_termination.addr, align 1
192 %1 = load i32, ptr %0, align 4
193 call void @foo(i32 %1)
197 ; Test when both vla's and highly aligned objects are present on stack.
198 define void @vla_and_realign(i32 %n) #0 personality ptr @__C_specific_handler {
200 ; CHECK-LABEL: vla_and_realign
201 ; CHECK: add x29, sp, #8
202 ; CHECK: sub x9, sp, #48
203 ; CHECK: and sp, x9, #0xffffffffffffffe0
206 ; CHECK: stur x1, [x29, #24]
207 ; CHECK: .set .Lvla_and_realign$frame_escape_0, 32
208 ; CHECK: str w0, [x29, #36]
209 ; CHECK: ldr w8, [x29, #36]
211 ; CHECK: str x9, [x29, #16]
212 ; CHECK: str x8, [x19, #24]
213 ; CHECK: ldr w0, [x19, #32]
216 %n.addr = alloca i32, align 4
217 %o = alloca %struct.S, align 32
218 %saved_stack = alloca ptr, align 8
219 %__vla_expr0 = alloca i64, align 8
220 call void (...) @llvm.localescape(ptr %o)
221 store i32 %n, ptr %n.addr, align 4
222 %0 = load i32, ptr %n.addr, align 4
223 %1 = zext i32 %0 to i64
224 %2 = call ptr @llvm.stacksave()
225 store ptr %2, ptr %saved_stack, align 8
226 %vla = alloca i32, i64 %1, align 4
227 store i64 %1, ptr %__vla_expr0, align 8
228 %3 = load i32, ptr %o, align 32
229 invoke void @foo(i32 %3) #5
230 to label %invoke.cont unwind label %ehcleanup
232 invoke.cont: ; preds = %entry
233 %4 = call ptr @llvm.localaddress()
234 call void @fin_vla_and_realign(i8 0, ptr %4)
235 %5 = load ptr, ptr %saved_stack, align 8
236 call void @llvm.stackrestore(ptr %5)
239 ehcleanup: ; preds = %entry
240 %6 = cleanuppad within none []
241 %7 = call ptr @llvm.localaddress()
242 call void @fin_vla_and_realign(i8 1, ptr %7) [ "funclet"(token %6) ]
243 cleanupret from %6 unwind to caller
246 define void @fin_vla_and_realign(i8 %abnormal_termination, ptr %frame_pointer) {
248 ; CHECK-LABEL: fin_vla_and_realign
249 ; CHECK: movz x8, #:abs_g1_s:.Lvla_and_realign$frame_escape_0
250 ; CHECK: movk x8, #:abs_g0_nc:.Lvla_and_realign$frame_escape_0
251 ; CHECK: strb w0, [sp, #15]
252 ; CHECK: ldr w8, [x1, x8]
255 %frame_pointer.addr = alloca ptr, align 8
256 %abnormal_termination.addr = alloca i8, align 1
257 %0 = call ptr @llvm.localrecover(ptr @vla_and_realign, ptr %frame_pointer, i32 0)
258 store ptr %frame_pointer, ptr %frame_pointer.addr, align 8
259 store i8 %abnormal_termination, ptr %abnormal_termination.addr, align 1
260 %1 = load i32, ptr %0, align 32
261 call void @foo(i32 %1)
265 declare void @foo(i32)
266 declare void @llvm.stackrestore(ptr)
267 declare ptr @llvm.stacksave()
268 declare ptr @llvm.localrecover(ptr, ptr, i32)
269 declare ptr @llvm.localaddress()
270 declare void @llvm.localescape(...)
271 declare i32 @__C_specific_handler(...)
273 attributes #0 = { noinline optnone }