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