1;; Check that this produces the expected assembly output 2; RUN: llc -mtriple=thumbv7-windows -o - %s -verify-machineinstrs | FileCheck %s 3;; Also try to write an object file, which verifies that the SEH opcodes 4;; match the actual prologue/epilogue length. 5; RUN: llc -mtriple=thumbv7-windows -filetype=obj -o %t.obj %s -verify-machineinstrs 6 7; CHECK-LABEL: clobberR4Frame: 8; CHECK-NEXT: .seh_proc clobberR4Frame 9; CHECK-NEXT: @ %bb.0: @ %entry 10; CHECK-NEXT: push.w {r4, r7, r11, lr} 11; CHECK-NEXT: .seh_save_regs_w {r4, r7, r11, lr} 12; CHECK-NEXT: add.w r11, sp, #8 13; CHECK-NEXT: .seh_nop_w 14; CHECK-NEXT: .seh_endprologue 15; CHECK-NEXT: bl other 16 17; CHECK: .seh_startepilogue 18; CHECK-NEXT: pop.w {r4, r7, r11, pc} 19; CHECK-NEXT: .seh_save_regs_w {r4, r7, r11, lr} 20; CHECK-NEXT: .seh_endepilogue 21; CHECK-NEXT: .seh_endproc 22 23define arm_aapcs_vfpcc void @clobberR4Frame() uwtable "frame-pointer"="all" { 24entry: 25 call arm_aapcs_vfpcc void @other() 26 call void asm sideeffect "", "~{r4}"() 27 ret void 28} 29 30; CHECK-LABEL: clobberR4NoFrame: 31; CHECK-NEXT: .seh_proc clobberR4NoFrame 32; CHECK-NEXT: @ %bb.0: @ %entry 33; CHECK-NEXT: push {r4, lr} 34; CHECK-NEXT: .seh_save_regs {r4, lr} 35; CHECK-NEXT: .seh_endprologue 36; CHECK-NEXT: bl other 37 38; CHECK: .seh_startepilogue 39; CHECK-NEXT: pop {r4, pc} 40; CHECK-NEXT: .seh_save_regs {r4, lr} 41; CHECK-NEXT: .seh_endepilogue 42; CHECK-NEXT: .seh_endproc 43 44define arm_aapcs_vfpcc void @clobberR4NoFrame() uwtable "frame-pointer"="none" { 45entry: 46 call arm_aapcs_vfpcc void @other() 47 call void asm sideeffect "", "~{r4}"() 48 ret void 49} 50 51; CHECK-LABEL: clobberR4Tail: 52; CHECK-NEXT: .seh_proc clobberR4Tail 53; CHECK-NEXT: @ %bb.0: @ %entry 54; CHECK-NEXT: push {r4, lr} 55; CHECK-NEXT: .seh_save_regs {r4, lr} 56; CHECK-NEXT: .seh_endprologue 57 58; CHECK: .seh_startepilogue 59; CHECK-NEXT: pop.w {r4, lr} 60; CHECK-NEXT: .seh_save_regs_w {r4, lr} 61; CHECK-NEXT: b.w other 62; CHECK-NEXT: .seh_nop_w 63; CHECK-NEXT: .seh_endepilogue 64; CHECK-NEXT: .seh_endproc 65 66define arm_aapcs_vfpcc void @clobberR4Tail() uwtable "frame-pointer"="none" { 67entry: 68 call void asm sideeffect "", "~{r4}"() 69 tail call arm_aapcs_vfpcc void @other() 70 ret void 71} 72 73; CHECK-LABEL: clobberD8D10: 74; CHECK-NEXT: .seh_proc clobberD8D10 75; CHECK-NEXT: @ %bb.0: @ %entry 76; CHECK-NEXT: vpush {d8, d9, d10} 77; CHECK-NEXT: .seh_save_fregs {d8-d10} 78; CHECK-NEXT: .seh_endprologue 79 80; CHECK: .seh_startepilogue 81; CHECK-NEXT: vpop {d8, d9, d10} 82; CHECK-NEXT: .seh_save_fregs {d8-d10} 83; CHECK-NEXT: b.w other 84; CHECK-NEXT: .seh_nop_w 85; CHECK-NEXT: .seh_endepilogue 86; CHECK-NEXT: .seh_endproc 87 88define arm_aapcs_vfpcc void @clobberD8D10() uwtable "frame-pointer"="none" { 89entry: 90 call void asm sideeffect "", "~{d8},~{d9},~{d10}"() 91 tail call arm_aapcs_vfpcc void @other() 92 ret void 93} 94 95declare arm_aapcs_vfpcc void @other() 96 97; CHECK-LABEL: vararg: 98; CHECK-NEXT: .seh_proc vararg 99; CHECK-NEXT: @ %bb.0: @ %entry 100; CHECK-NEXT: sub sp, #12 101; CHECK-NEXT: .seh_stackalloc 12 102; CHECK-NEXT: push.w {r11, lr} 103; CHECK-NEXT: .seh_save_regs_w {r11, lr} 104; CHECK-NEXT: sub sp, #4 105; CHECK-NEXT: .seh_stackalloc 4 106; CHECK-NEXT: .seh_endprologue 107 108; CHECK: .seh_startepilogue 109; CHECK-NEXT: add sp, #4 110; CHECK-NEXT: .seh_stackalloc 4 111; CHECK-NEXT: pop.w {r11, lr} 112; CHECK-NEXT: .seh_save_regs_w {r11, lr} 113; CHECK-NEXT: add sp, #12 114; CHECK-NEXT: .seh_stackalloc 12 115; CHECK-NEXT: bx lr 116; CHECK-NEXT: .seh_nop 117; CHECK-NEXT: .seh_endepilogue 118; CHECK-NEXT: .seh_endproc 119 120define arm_aapcs_vfpcc void @vararg(i32 noundef %a, ...) uwtable "frame-pointer"="none" { 121entry: 122 %ap = alloca ptr, align 4 123 call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %ap) 124 call void @llvm.va_start(ptr nonnull %ap) 125 %0 = load ptr, ptr %ap 126 call arm_aapcs_vfpcc void @useva(ptr noundef %0) 127 call void @llvm.va_end(ptr nonnull %ap) 128 call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %ap) 129 ret void 130} 131 132declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) 133declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) 134declare void @llvm.va_start(ptr) 135declare void @llvm.va_end(ptr) 136 137declare arm_aapcs_vfpcc void @useva(ptr noundef) 138 139; CHECK-LABEL: onlystack: 140; CHECK-NEXT: .seh_proc onlystack 141; CHECK-NEXT: @ %bb.0: @ %entry 142; CHECK-NEXT: sub sp, #4 143; CHECK-NEXT: .seh_stackalloc 4 144; CHECK-NEXT: .seh_endprologue 145 146; CHECK: .seh_startepilogue 147; CHECK-NEXT: add sp, #4 148; CHECK-NEXT: .seh_stackalloc 4 149; CHECK-NEXT: bx lr 150; CHECK-NEXT: .seh_nop 151; CHECK-NEXT: .seh_endepilogue 152; CHECK-NEXT: .seh_endproc 153 154define dso_local arm_aapcs_vfpcc void @onlystack() uwtable "frame-pointer"="none" { 155entry: 156 %buf = alloca [4 x i8], align 1 157 call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %buf) 158 call void asm sideeffect "", "r"(ptr nonnull %buf) 159 call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %buf) 160 ret void 161} 162 163; CHECK-LABEL: func50: 164; CHECK-NEXT: .seh_proc func50 165; CHECK-NEXT: @ %bb.0: @ %entry 166; CHECK-NEXT: push.w {r11, lr} 167; CHECK-NEXT: .seh_save_regs_w {r11, lr} 168; CHECK-NEXT: sub sp, #56 169; CHECK-NEXT: .seh_stackalloc 56 170; CHECK-NEXT: .seh_endprologue 171 172; CHECK: .seh_startepilogue 173; CHECK-NEXT: add sp, #56 174; CHECK-NEXT: .seh_stackalloc 56 175; CHECK-NEXT: pop.w {r11, pc} 176; CHECK-NEXT: .seh_save_regs_w {r11, lr} 177; CHECK-NEXT: .seh_endepilogue 178; CHECK-NEXT: .seh_endproc 179 180define arm_aapcs_vfpcc void @func50() { 181entry: 182 %buf = alloca [50 x i8], align 1 183 call void @llvm.lifetime.start.p0(i64 50, ptr nonnull %buf) 184 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf) 185 call void @llvm.lifetime.end.p0(i64 50, ptr nonnull %buf) 186 ret void 187} 188 189; CHECK-LABEL: func4000: 190; CHECK-NEXT: .seh_proc func4000 191; CHECK-NEXT: @ %bb.0: @ %entry 192; CHECK-NEXT: push.w {r11, lr} 193; CHECK-NEXT: .seh_save_regs_w {r11, lr} 194; CHECK-NEXT: sub.w sp, sp, #4000 195; CHECK-NEXT: .seh_stackalloc_w 4000 196; CHECK-NEXT: .seh_endprologue 197 198; CHECK: .seh_startepilogue 199; CHECK-NEXT: add.w sp, sp, #4000 200; CHECK-NEXT: .seh_stackalloc_w 4000 201; CHECK-NEXT: pop.w {r11, pc} 202; CHECK-NEXT: .seh_save_regs_w {r11, lr} 203; CHECK-NEXT: .seh_endepilogue 204; CHECK-NEXT: .seh_endproc 205 206define arm_aapcs_vfpcc void @func4000() { 207entry: 208 %buf = alloca [4000 x i8], align 1 209 call void @llvm.lifetime.start.p0(i64 4000, ptr nonnull %buf) 210 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf) 211 call void @llvm.lifetime.end.p0(i64 4000, ptr nonnull %buf) 212 ret void 213} 214 215; CHECK-LABEL: func5000: 216; CHECK-NEXT: .seh_proc func5000 217; CHECK-NEXT: @ %bb.0: @ %entry 218; CHECK-NEXT: push {r4, r5, r6, lr} 219; CHECK-NEXT: .seh_save_regs {r4-r6, lr} 220; CHECK-NEXT: movw r4, #1250 221; CHECK-NEXT: .seh_nop_w 222; CHECK-NEXT: bl __chkstk 223; CHECK-NEXT: .seh_nop_w 224; CHECK-NEXT: sub.w sp, sp, r4 225; CHECK-NEXT: .seh_stackalloc_w 5000 226; CHECK-NEXT: .seh_endprologue 227 228; CHECK: .seh_startepilogue 229; CHECK-NEXT: add.w sp, sp, #4992 230; CHECK-NEXT: .seh_stackalloc_w 4992 231; CHECK-NEXT: add sp, #8 232; CHECK-NEXT: .seh_stackalloc 8 233; CHECK-NEXT: pop {r4, r5, r6, pc} 234; CHECK-NEXT: .seh_save_regs {r4-r6, lr} 235; CHECK-NEXT: .seh_endepilogue 236; CHECK-NEXT: .seh_endproc 237 238define arm_aapcs_vfpcc void @func5000() { 239entry: 240 %buf = alloca [5000 x i8], align 1 241 call void @llvm.lifetime.start.p0(i64 5000, ptr nonnull %buf) 242 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf) 243 call void @llvm.lifetime.end.p0(i64 5000, ptr nonnull %buf) 244 ret void 245} 246 247; CHECK-LABEL: func262144: 248; CHECK-NEXT: .seh_proc func262144 249; CHECK-NEXT: @ %bb.0: @ %entry 250; CHECK-NEXT: push {r4, r5, r6, lr} 251; CHECK-NEXT: .seh_save_regs {r4-r6, lr} 252; CHECK-NEXT: movs r4, #0 253; CHECK-NEXT: .seh_nop 254; CHECK-NEXT: movt r4, #1 255; CHECK-NEXT: .seh_nop_w 256; CHECK-NEXT: bl __chkstk 257; CHECK-NEXT: .seh_nop_w 258; CHECK-NEXT: sub.w sp, sp, r4 259; CHECK-NEXT: .seh_stackalloc_w 262144 260; CHECK-NEXT: .seh_endprologue 261 262; CHECK: .seh_startepilogue 263; CHECK-NEXT: add.w sp, sp, #262144 264; CHECK-NEXT: .seh_stackalloc_w 262144 265; CHECK-NEXT: pop {r4, r5, r6, pc} 266; CHECK-NEXT: .seh_save_regs {r4-r6, lr} 267; CHECK-NEXT: .seh_endepilogue 268; CHECK-NEXT: .seh_endproc 269 270define arm_aapcs_vfpcc void @func262144() { 271entry: 272 %buf = alloca [262144 x i8], align 1 273 call void @llvm.lifetime.start.p0(i64 262144, ptr nonnull %buf) 274 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf) 275 call void @llvm.lifetime.end.p0(i64 262144, ptr nonnull %buf) 276 ret void 277} 278 279; CHECK-LABEL: func270000: 280; CHECK-NEXT: .seh_proc func270000 281; CHECK-NEXT: @ %bb.0: @ %entry 282; CHECK-NEXT: push {r4, r5, r6, lr} 283; CHECK-NEXT: .seh_save_regs {r4-r6, lr} 284; CHECK-NEXT: movw r4, #1964 285; CHECK-NEXT: .seh_nop_w 286; CHECK-NEXT: movt r4, #1 287; CHECK-NEXT: .seh_nop_w 288; CHECK-NEXT: bl __chkstk 289; CHECK-NEXT: .seh_nop_w 290; CHECK-NEXT: sub.w sp, sp, r4 291; CHECK-NEXT: .seh_stackalloc_w 270000 292; CHECK-NEXT: .seh_endprologue 293 294; CHECK: .seh_startepilogue 295; CHECK-NEXT: add.w sp, sp, #268288 296; CHECK-NEXT: .seh_stackalloc_w 268288 297; CHECK-NEXT: add.w sp, sp, #1712 298; CHECK-NEXT: .seh_stackalloc_w 1712 299; CHECK-NEXT: pop {r4, r5, r6, pc} 300; CHECK-NEXT: .seh_save_regs {r4-r6, lr} 301; CHECK-NEXT: .seh_endepilogue 302; CHECK-NEXT: .seh_endproc 303 304define arm_aapcs_vfpcc void @func270000() { 305entry: 306 %buf = alloca [270000 x i8], align 1 307 call void @llvm.lifetime.start.p0(i64 270000, ptr nonnull %buf) 308 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf) 309 call void @llvm.lifetime.end.p0(i64 270000, ptr nonnull %buf) 310 ret void 311} 312 313declare arm_aapcs_vfpcc void @useptr(ptr noundef) 314 315; CHECK-LABEL: func_fp: 316; CHECK-NEXT: .seh_proc func_fp 317; CHECK-NEXT: @ %bb.0: @ %entry 318; CHECK-NEXT: str r11, [sp, #-4]! 319; CHECK-NEXT: .seh_save_regs_w {r11} 320; CHECK-NEXT: mov r11, sp 321; CHECK-NEXT: .seh_save_sp r11 322; CHECK-NEXT: .seh_endprologue 323 324; CHECK-NEXT: mov r0, r11 325 326; CHECK-NEXT: .seh_startepilogue 327; CHECK-NEXT: ldr r11, [sp], #4 328; CHECK-NEXT: .seh_save_regs_w {r11} 329; CHECK-NEXT: bx lr 330; CHECK-NEXT: .seh_nop 331; CHECK-NEXT: .seh_endepilogue 332; CHECK-NEXT: .seh_endproc 333 334define arm_aapcs_vfpcc i32 @func_fp() { 335entry: 336 %0 = tail call ptr @llvm.frameaddress.p0(i32 0) 337 %1 = ptrtoint ptr %0 to i32 338 ret i32 %1 339} 340 341declare ptr @llvm.frameaddress.p0(i32 immarg) 342