1; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
2; RUN: llc -o %t -filetype=obj %s -mtriple=aarch64-windows
3; RUN: llvm-readobj --unwind %t | FileCheck %s -check-prefix=UNWIND
4
5; We test the following
6; 1) That the unwind help object is created and that its offset from the stack
7;    pointer on entry is patched into the table fed to __CxxFrameHandler3
8; 2) That the stack update for the catch funclet only includes the callee saved
9;    registers
10; 3) That the locals are accessed using the frame pointer in both the funclet
11;    and the parent function.
12
13; The following checks that the unwind help object has -2 stored into it at
14; fp + 16, which is on-entry sp - 16.
15; We check this offset in the table later on.
16
17; CHECK-LABEL: "?func@@YAHXZ":
18; CHECK:       stp     x29, x30, [sp, #-64]!
19; CHECK:       str     x28, [sp, #16]
20; CHECK:       str     x21, [sp, #24]
21; CHECK:       stp     x19, x20, [sp, #32]
22; CHECK:       mov     x29, sp
23; CHECK:       sub     sp, sp, #624
24; CHECK:       mov     x19, sp
25; CHECK:       mov     x0, #-2
26; CHECK:       stur    x0, [x29, #48]
27
28; Now check that x is stored at fp - 20.  We check that this is the same
29; location accessed from the funclet to retrieve x.
30; CHECK:       mov     w8, #1
31; CHECK:       stur    w8, [x29, [[X_OFFSET:#-[1-9][0-9]+]]
32
33; Check the offset off the frame pointer at which B is located.
34; Check the same offset is used to pass the address of B to init2 in the
35; funclet.
36; CHECK:       sub     x0, x29, [[B_OFFSET:#[1-9][0-9]+]]
37; CHECK:       bl      "?init@@YAXPEAH@Z"
38
39; This is the label for the throw that is encoded in the ip2state.
40; We are inside the try block, where we make a call to func2
41; CHECK-LABEL: .Ltmp0:
42; CHECK:       bl      "?func2@@YAHXZ
43
44; CHECK:        [[CATCHRETDEST:.LBB0_[0-9]+]]:      ; %catchret.dest
45
46; Check the catch funclet.
47; CHECK-LABEL: "?catch$2@?0??func@@YAHXZ@4HA":
48
49; Check that the stack space is allocated only for the callee saved registers.
50; CHECK:       stp     x29, x30, [sp, #-48]!
51; CHECK:       str     x28, [sp, #16]
52; CHECK:       str     x21, [sp, #24]
53; CHECK:       stp     x19, x20, [sp, #32]
54; CHECK:       add     x20, x19, #12
55
56; Check that there are no further stack updates.
57; CHECK-NOT:   sub     sp, sp
58
59; Check that the stack address passed to init2 is off the frame pointer, and
60; that it matches the address of B in the parent function.
61; CHECK:       sub     x0, x29, [[B_OFFSET]]
62; CHECK:       bl      "?init2@@YAXPEAH@Z"
63
64; Check that are storing x back to the same location off the frame pointer as in
65; the parent function.
66; CHECK:       stur    w8, [x29, [[X_OFFSET]]]
67
68; Check that the funclet branches back to the catchret destination
69; CHECK:       adrp    x0, .LBB0_3
70; CHECK-NEXT:  add     x0, x0, [[CATCHRETDEST]]
71
72
73; Now check that the offset of the unwind help object from the stack pointer on
74; entry to func is encoded in cppxdata that is passed to __CxxFrameHandler3.  As
75; computed above, this comes to -16.
76; CHECK-LABEL:        "$cppxdata$?func@@YAHXZ":
77; CHECK-NEXT:         .word   429065506               ; MagicNumber
78; CHECK-NEXT:         .word   2                       ; MaxState
79; CHECK-NEXT:         .word   ("$stateUnwindMap$?func@@YAHXZ")@IMGREL ; UnwindMap
80; CHECK-NEXT:         .word   1                       ; NumTryBlocks
81; CHECK-NEXT:         .word   ("$tryMap$?func@@YAHXZ")@IMGREL ; TryBlockMap
82; CHECK-NEXT:         .word   4                       ; IPMapEntries
83; CHECK-NEXT:         .word   ("$ip2state$?func@@YAHXZ")@IMGREL ; IPToStateXData
84; CHECK-NEXT:         .word   -16                     ; UnwindHelp
85
86; UNWIND: Function: ?func@@YAHXZ (0x0)
87; UNWIND: Prologue [
88; UNWIND-NEXT: ; nop
89; UNWIND-NEXT: ; sub sp, #624
90; UNWIND-NEXT: ; mov fp, sp
91; UNWIND-NEXT: ; stp x19, x20, [sp, #32]
92; UNWIND-NEXT: ; str x21, [sp, #24]
93; UNWIND-NEXT: ; str x28, [sp, #16]
94; UNWIND-NEXT: ; stp x29, x30, [sp, #-64]!
95; UNWIND-NEXT: ; end
96; UNWIND: Function: ?catch$2@?0??func@@YAHXZ@4HA
97; UNWIND: Prologue [
98; UNWIND-NEXT: ; stp x19, x20, [sp, #32]
99; UNWIND-NEXT: ; str x21, [sp, #24]
100; UNWIND-NEXT: ; str x28, [sp, #16]
101; UNWIND-NEXT: ; stp x29, x30, [sp, #-48]!
102; UNWIND-NEXT: ; end
103
104target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
105target triple = "aarch64-unknown-windows-msvc19.11.0"
106
107%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
108%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
109%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
110%eh.ThrowInfo = type { i32, i32, i32, i32 }
111
112$"??_R0H@8" = comdat any
113
114$"_CT??_R0H@84" = comdat any
115
116$_CTA1H = comdat any
117
118$_TI1H = comdat any
119
120@"??_7type_info@@6B@" = external constant i8*
121@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
122@__ImageBase = external dso_local constant i8
123@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
124@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
125@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
126
127; Function Attrs: noinline optnone
128define dso_local i32 @"?func@@YAHXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
129entry:
130  %B = alloca [50 x i32], align 4
131  %x = alloca i32, align 4
132  %tmp = alloca i32, align 4
133  %i = alloca i32, align 4
134  %C = alloca [100 x i32], align 4
135  store i32 1, i32* %x, align 4
136  %arraydecay = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 0, i32 0
137  call void @"?init@@YAXPEAH@Z"(i32* %arraydecay)
138  %call = invoke i32 @"?func2@@YAHXZ"()
139          to label %invoke.cont unwind label %catch.dispatch
140
141invoke.cont:                                      ; preds = %entry
142  store i32 %call, i32* %tmp, align 4
143  %0 = bitcast i32* %tmp to i8*
144  invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
145          to label %unreachable unwind label %catch.dispatch
146
147catch.dispatch:                                   ; preds = %invoke.cont, %entry
148  %1 = catchswitch within none [label %catch] unwind to caller
149
150catch:                                            ; preds = %catch.dispatch
151  %2 = catchpad within %1 [%rtti.TypeDescriptor2* @"??_R0H@8", i32 0, i32* %i]
152  %arraydecay1 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i32 0, i32 0
153  call void @"?init@@YAXPEAH@Z"(i32* %arraydecay1) [ "funclet"(token %2) ]
154  %arraydecay2 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 0, i32 0
155  call void @"?init2@@YAXPEAH@Z"(i32* %arraydecay2) [ "funclet"(token %2) ]
156  %3 = load i32, i32* %i, align 4
157  %idxprom = sext i32 %3 to i64
158  %arrayidx = getelementptr inbounds [50 x i32], [50 x i32]* %B, i64 0, i64 %idxprom
159  %4 = load i32, i32* %arrayidx, align 4
160  %5 = load i32, i32* %i, align 4
161  %idxprom3 = sext i32 %5 to i64
162  %arrayidx4 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 0, i64 %idxprom3
163  %6 = load i32, i32* %arrayidx4, align 4
164  %add = add nsw i32 %4, %6
165  %7 = load i32, i32* %i, align 4
166  %8 = load i32, i32* %i, align 4
167  %mul = mul nsw i32 %7, %8
168  %add5 = add nsw i32 %add, %mul
169  store i32 %add5, i32* %x, align 4
170  catchret from %2 to label %catchret.dest
171
172catchret.dest:                                    ; preds = %catch
173  br label %try.cont
174
175try.cont:                                         ; preds = %catchret.dest
176  %arrayidx6 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i64 0, i64 2
177  %9 = load i32, i32* %arrayidx6, align 4
178  %10 = load i32, i32* %x, align 4
179  %add7 = add nsw i32 %9, %10
180  ret i32 %add7
181
182unreachable:                                      ; preds = %invoke.cont
183  unreachable
184}
185
186declare dso_local void @"?init@@YAXPEAH@Z"(i32*)
187
188declare dso_local i32 @"?func2@@YAHXZ"()
189
190declare dso_local i32 @__CxxFrameHandler3(...)
191
192declare dllimport void @_CxxThrowException(i8*, %eh.ThrowInfo*)
193
194declare dso_local void @"?init2@@YAXPEAH@Z"(i32*)
195
196attributes #0 = { noinline optnone }
197attributes #2 = { noreturn }
198