1; RUN: llc < %s -mtriple=i686-windows | FileCheck %s -check-prefix=NORMAL 2; RUN: llc < %s -mtriple=i686-windows -no-x86-call-frame-opt | FileCheck %s -check-prefix=NOPUSH 3; RUN: llc < %s -mtriple=x86_64-windows | FileCheck %s -check-prefix=X64 4; RUN: llc < %s -mtriple=i686-pc-linux | FileCheck %s -check-prefix=LINUX 5 6%class.Class = type { i32 } 7%struct.s = type { i64 } 8 9declare void @good(i32 %a, i32 %b, i32 %c, i32 %d) 10declare void @inreg(i32 %a, i32 inreg %b, i32 %c, i32 %d) 11declare x86_thiscallcc void @thiscall(ptr %class, i32 %a, i32 %b, i32 %c, i32 %d) 12declare void @oneparam(i32 %a) 13declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) 14declare void @eightparams16(i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g, i16 %h) 15declare void @eightparams64(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h) 16declare void @struct(ptr byval(%struct.s) %a, i32 %b, i32 %c, i32 %d) 17declare void @inalloca(ptr inalloca(<{ %struct.s }>)) 18 19declare ptr @llvm.stacksave() 20declare void @llvm.stackrestore(ptr) 21 22; We should get pushes for x86, even though there is a reserved call frame. 23; Make sure we don't touch x86-64, and that turning it off works. 24; NORMAL-LABEL: test1: 25; NORMAL-NOT: subl {{.*}} %esp 26; NORMAL: pushl $4 27; NORMAL-NEXT: pushl $3 28; NORMAL-NEXT: pushl $2 29; NORMAL-NEXT: pushl $1 30; NORMAL-NEXT: call 31; NORMAL-NEXT: addl $16, %esp 32; X64-LABEL: test1: 33; X64: movl $1, %ecx 34; X64-NEXT: movl $2, %edx 35; X64-NEXT: movl $3, %r8d 36; X64-NEXT: movl $4, %r9d 37; X64-NEXT: callq good 38; NOPUSH-LABEL: test1: 39; NOPUSH: subl $16, %esp 40; NOPUSH-NEXT: movl $4, 12(%esp) 41; NOPUSH-NEXT: movl $3, 8(%esp) 42; NOPUSH-NEXT: movl $2, 4(%esp) 43; NOPUSH-NEXT: movl $1, (%esp) 44; NOPUSH-NEXT: call 45; NOPUSH-NEXT: addl $16, %esp 46define void @test1() { 47entry: 48 call void @good(i32 1, i32 2, i32 3, i32 4) 49 ret void 50} 51 52; If we have a reserved frame, we should have pushes 53; NORMAL-LABEL: test2: 54; NORMAL-NOT: subl {{.*}} %esp 55; NORMAL: pushl $4 56; NORMAL-NEXT: pushl $3 57; NORMAL-NEXT: pushl $2 58; NORMAL-NEXT: pushl $1 59; NORMAL-NEXT: call 60define void @test2(i32 %k) { 61entry: 62 %a = alloca i32, i32 %k 63 call void @good(i32 1, i32 2, i32 3, i32 4) 64 ret void 65} 66 67; Again, we expect a sequence of 4 immediate pushes 68; Checks that we generate the right pushes for >8bit immediates 69; NORMAL-LABEL: test2b: 70; NORMAL-NOT: subl {{.*}} %esp 71; NORMAL: pushl $4096 72; NORMAL-NEXT: pushl $3072 73; NORMAL-NEXT: pushl $2048 74; NORMAL-NEXT: pushl $1024 75; NORMAL-NEXT: call 76; NORMAL-NEXT: addl $16, %esp 77define void @test2b() optsize { 78entry: 79 call void @good(i32 1024, i32 2048, i32 3072, i32 4096) 80 ret void 81} 82 83; The first push should push a register 84; NORMAL-LABEL: test3: 85; NORMAL-NOT: subl {{.*}} %esp 86; NORMAL: pushl $4 87; NORMAL-NEXT: pushl $3 88; NORMAL-NEXT: pushl $2 89; NORMAL-NEXT: pushl %e{{..}} 90; NORMAL-NEXT: call 91; NORMAL-NEXT: addl $16, %esp 92define void @test3(i32 %k) optsize { 93entry: 94 %f = add i32 %k, 1 95 call void @good(i32 %f, i32 2, i32 3, i32 4) 96 ret void 97} 98 99; We support weird calling conventions 100; NORMAL-LABEL: test4: 101; NORMAL: movl $2, %eax 102; NORMAL-NEXT: pushl $4 103; NORMAL-NEXT: pushl $3 104; NORMAL-NEXT: pushl $1 105; NORMAL-NEXT: call 106; NORMAL-NEXT: addl $12, %esp 107define void @test4() optsize { 108entry: 109 call void @inreg(i32 1, i32 inreg 2, i32 3, i32 4) 110 ret void 111} 112 113; NORMAL-LABEL: test4b: 114; NORMAL: movl 4(%esp), %ecx 115; NORMAL-NEXT: pushl $4 116; NORMAL-NEXT: pushl $3 117; NORMAL-NEXT: pushl $2 118; NORMAL-NEXT: pushl $1 119; NORMAL-NEXT: call 120; NORMAL-NEXT: ret 121define void @test4b(ptr %f) optsize { 122entry: 123 call x86_thiscallcc void @thiscall(ptr %f, i32 1, i32 2, i32 3, i32 4) 124 ret void 125} 126 127; Check that pushing the addresses of globals (Or generally, things that 128; aren't exactly immediates) isn't broken. 129; Fixes PR21878. 130; NORMAL-LABEL: test6: 131; NORMAL: pushl $_ext 132; NORMAL-NEXT: call 133declare void @f(ptr) 134@ext = external dso_local constant i8 135 136define void @test6() { 137 call void @f(ptr @ext) 138 br label %bb 139bb: 140 alloca i32 141 ret void 142} 143 144; Check that we fold simple cases into the push 145; NORMAL-LABEL: test7: 146; NORMAL-NOT: subl {{.*}} %esp 147; NORMAL: movl 4(%esp), [[EAX:%e..]] 148; NORMAL-NEXT: pushl $4 149; NORMAL-NEXT: pushl ([[EAX]]) 150; NORMAL-NEXT: pushl $2 151; NORMAL-NEXT: pushl $1 152; NORMAL-NEXT: call 153; NORMAL-NEXT: addl $16, %esp 154define void @test7(ptr %ptr) optsize { 155entry: 156 %val = load i32, ptr %ptr 157 call void @good(i32 1, i32 2, i32 %val, i32 4) 158 ret void 159} 160 161; Fold stack-relative loads into the push, with correct offset 162; In particular, at the second push, %b was at 12(%esp) and 163; %a wast at 8(%esp), but the second push bumped %esp, so %a 164; is now it at 12(%esp) 165; NORMAL-LABEL: test8: 166; NORMAL: pushl $4 167; NORMAL-NEXT: pushl 12(%esp) 168; NORMAL-NEXT: pushl 12(%esp) 169; NORMAL-NEXT: pushl $1 170; NORMAL-NEXT: call 171; NORMAL-NEXT: addl $16, %esp 172define void @test8(i32 %a, i32 %b) optsize { 173entry: 174 call void @good(i32 1, i32 %a, i32 %b, i32 4) 175 ret void 176} 177 178; If one function is using push instructions, and the other isn't 179; (because it has frame-index references), then we must resolve 180; these references correctly. 181; NORMAL-LABEL: test9: 182; NORMAL-NOT: leal (%esp), 183; NORMAL: pushl $4 184; NORMAL-NEXT: pushl $3 185; NORMAL-NEXT: pushl $2 186; NORMAL-NEXT: pushl $1 187; NORMAL-NEXT: call 188; NORMAL-NEXT: addl $16, %esp 189; NORMAL-NEXT: movl (%esp), [[E1:%e..]] 190; NORMAL-NEXT: movl 4(%esp), [[E2:%e..]] 191; NORMAL-NEXT: leal 16(%esp), [[E3:%e..]] 192; NORMAL-NEXT: leal 12(%esp), [[E4:%e..]] 193; NORMAL-NEXT: pushl [[E3]] 194; NORMAL-NEXT: pushl [[E4]] 195; NORMAL-NEXT: pushl $6 196; NORMAL-NEXT: pushl [[E2]] 197; NORMAL-NEXT: pushl [[E1]] 198; NORMAL-NEXT: call 199; NORMAL-NEXT: addl $20, %esp 200define void @test9() optsize { 201entry: 202 %p = alloca i32, align 4 203 %q = alloca i32, align 4 204 %s = alloca %struct.s, align 8 205 call void @good(i32 1, i32 2, i32 3, i32 4) 206 %pv = ptrtoint ptr %p to i32 207 %qv = ptrtoint ptr %q to i32 208 call void @struct(ptr byval(%struct.s) %s, i32 6, i32 %qv, i32 %pv) 209 ret void 210} 211 212; We can end up with an indirect call which gets reloaded on the spot. 213; Make sure we reference the correct stack slot - we spill into (%esp) 214; and reload from 16(%esp) due to the pushes. 215; NORMAL-LABEL: test10: 216; NORMAL: movl $_good, [[ALLOC:.*]] 217; NORMAL-NEXT: movl [[ALLOC]], [[EAX:%e..]] 218; NORMAL-NEXT: movl [[EAX]], (%esp) # 4-byte Spill 219; NORMAL: nop 220; NORMAL: pushl $4 221; NORMAL-NEXT: pushl $3 222; NORMAL-NEXT: pushl $2 223; NORMAL-NEXT: pushl $1 224; NORMAL-NEXT: calll *16(%esp) 225; NORMAL-NEXT: addl $24, %esp 226define void @test10() optsize { 227 %stack_fptr = alloca ptr 228 store ptr @good, ptr %stack_fptr 229 %good_ptr = load volatile ptr, ptr %stack_fptr 230 call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di}"() 231 call void (i32, i32, i32, i32) %good_ptr(i32 1, i32 2, i32 3, i32 4) 232 ret void 233} 234 235; We can't fold the load from the global into the push because of 236; interference from the store 237; NORMAL-LABEL: test11: 238; NORMAL: movl _the_global, [[EAX:%e..]] 239; NORMAL-NEXT: movl $42, _the_global 240; NORMAL-NEXT: pushl $4 241; NORMAL-NEXT: pushl $3 242; NORMAL-NEXT: pushl $2 243; NORMAL-NEXT: pushl [[EAX]] 244; NORMAL-NEXT: call 245; NORMAL-NEXT: addl $16, %esp 246@the_global = external dso_local global i32 247define void @test11() optsize { 248 %myload = load i32, ptr @the_global 249 store i32 42, ptr @the_global 250 call void @good(i32 %myload, i32 2, i32 3, i32 4) 251 ret void 252} 253 254; Converting one mov into a push isn't worth it when 255; doing so forces too much overhead for other calls. 256; NORMAL-LABEL: test12: 257; NORMAL: pushl $8 258; NORMAL-NEXT: pushl $7 259; NORMAL-NEXT: pushl $6 260; NORMAL-NEXT: pushl $5 261; NORMAL-NEXT: calll _good 262define void @test12() optsize { 263entry: 264 %s = alloca %struct.s, align 4 265 call void @struct(ptr byval(%struct.s) %s, i32 2, i32 3, i32 4) 266 call void @good(i32 5, i32 6, i32 7, i32 8) 267 call void @struct(ptr byval(%struct.s) %s, i32 10, i32 11, i32 12) 268 ret void 269} 270 271; But if the gains outweigh the overhead, we should do it 272; NORMAL-LABEL: test12b: 273; NORMAL: pushl $4 274; NORMAL-NEXT: pushl $3 275; NORMAL-NEXT: pushl $2 276; NORMAL-NEXT: pushl $1 277; NORMAL-NEXT: calll _good 278; NORMAL-NEXT: addl $16, %esp 279; NORMAL=NEXT: movl (%esp), %eax 280; NORMAL=NEXT: movl 4(%esp), %ecx 281; NORMAL=NEXT: pushl $8 282; NORMAL=NEXT: pushl $7 283; NORMAL=NEXT: pushl $6 284; NORMAL=NEXT: pushl %ecx 285; NORMAL=NEXT: pushl %eax 286; NORMAL=NEXT: calll _struct 287; NORMAL=NEXT: addl $20, %esp 288; NORMAL=NEXT: pushl $12 289; NORMAL=NEXT: pushl $11 290; NORMAL=NEXT: pushl $10 291; NORMAL=NEXT: pushl $9 292; NORMAL=NEXT: calll _good 293; NORMAL=NEXT: addl $16, %esp 294define void @test12b() optsize { 295entry: 296 %s = alloca %struct.s, align 4 297 call void @good(i32 1, i32 2, i32 3, i32 4) 298 call void @struct(ptr byval(%struct.s) %s, i32 6, i32 7, i32 8) 299 call void @good(i32 9, i32 10, i32 11, i32 12) 300 ret void 301} 302 303; Make sure the add does not prevent folding loads into pushes. 304; val1 and val2 will not be folded into pushes since they have 305; an additional use, but val3 should be. 306; NORMAL-LABEL: test13: 307; NORMAL: movl ([[P1:%e..]]), [[V1:%e..]] 308; NORMAL-NEXT: movl ([[P2:%e..]]), [[V2:%e..]] 309; NORMAL-NEXT: , [[ADD:%e..]] 310; NORMAL-NEXT: pushl [[ADD]] 311; NORMAL-NEXT: pushl ([[P3:%e..]]) 312; NORMAL-NEXT: pushl [[V2]] 313; NORMAL-NEXT: pushl [[V1]] 314; NORMAL-NEXT: calll _good 315; NORMAL: movl [[P3]], %eax 316define ptr @test13(ptr inreg %ptr1, ptr inreg %ptr2, ptr inreg %ptr3) optsize { 317entry: 318 %val1 = load i32, ptr %ptr1 319 %val2 = load i32, ptr %ptr2 320 %val3 = load i32, ptr %ptr3 321 %add = add i32 %val1, %val2 322 call void @good(i32 %val1, i32 %val2, i32 %val3, i32 %add) 323 ret ptr %ptr3 324} 325 326; Make sure to fold adjacent stack adjustments. 327; LINUX-LABEL: pr27140: 328; LINUX: subl $12, %esp 329; LINUX: .cfi_def_cfa_offset 16 330; LINUX-NOT: sub 331; LINUX: pushl $4 332; LINUX: .cfi_adjust_cfa_offset 4 333; LINUX: pushl $3 334; LINUX: .cfi_adjust_cfa_offset 4 335; LINUX: pushl $2 336; LINUX: .cfi_adjust_cfa_offset 4 337; LINUX: pushl $1 338; LINUX: .cfi_adjust_cfa_offset 4 339; LINUX: calll good 340; LINUX: addl $28, %esp 341; LINUX: .cfi_adjust_cfa_offset -28 342; LINUX-NOT: add 343; LINUX: retl 344define void @pr27140() optsize { 345entry: 346 tail call void @good(i32 1, i32 2, i32 3, i32 4) 347 ret void 348} 349 350; Check that a stack restore (leal -4(%ebp), %esp) doesn't get merged with a 351; stack adjustment (addl $12, %esp). Just because it's a lea doesn't mean it's 352; simply decreasing the stack pointer. 353; NORMAL-LABEL: test14: 354; NORMAL: calll _B_func 355; NORMAL: leal -4(%ebp), %esp 356; NORMAL-NOT: %esp 357; NORMAL: retl 358%struct.A = type { i32, i32 } 359%struct.B = type { i8 } 360declare x86_thiscallcc ptr @B_ctor(ptr returned, ptr byval(%struct.A)) 361declare void @B_func(ptr sret(%struct.B), ptr, i32) 362define void @test14(ptr %a) { 363entry: 364 %ref.tmp = alloca %struct.B, align 1 365 %agg.tmp = alloca i64, align 8 366 %tmp = alloca %struct.B, align 1 367 %0 = load i64, ptr %a, align 4 368 store i64 %0, ptr %agg.tmp, align 4 369 %call = call x86_thiscallcc ptr @B_ctor(ptr returned %ref.tmp, ptr byval(%struct.A) %agg.tmp) 370 call void @B_func(ptr sret(%struct.B) %tmp, ptr %ref.tmp, i32 1) 371 ret void 372} 373 374; NORMAL-LABEL: pr34863_16 375; NORMAL: movl 4(%esp), %eax 376; NORMAL-NEXT: pushl $65535 377; NORMAL-NEXT: pushl $0 378; NORMAL-NEXT: pushl %eax 379; NORMAL-NEXT: pushl %eax 380; NORMAL-NEXT: pushl %eax 381; NORMAL-NEXT: pushl %eax 382; NORMAL-NEXT: pushl %eax 383; NORMAL-NEXT: pushl %eax 384; NORMAL-NEXT: calll _eightparams16 385; NORMAL-NEXT: addl $32, %esp 386; 387; NOPUSH-LABEL: pr34863_16 388; NOPUSH: subl $32, %esp 389; NOPUSH-NEXT: movl 36(%esp), %eax 390; NOPUSH-NEXT: movl %eax, 20(%esp) 391; NOPUSH-NEXT: movl %eax, 16(%esp) 392; NOPUSH-NEXT: movl %eax, 12(%esp) 393; NOPUSH-NEXT: movl %eax, 8(%esp) 394; NOPUSH-NEXT: movl %eax, 4(%esp) 395; NOPUSH-NEXT: movl %eax, (%esp) 396; NOPUSH-NEXT: movl $65535, 28(%esp) 397; NOPUSH-NEXT: andl $0, 24(%esp) 398; NOPUSH-NEXT: calll _eightparams16 399; NOPUSH-NEXT: addl $32, %esp 400define void @pr34863_16(i16 %x) minsize nounwind { 401entry: 402 tail call void @eightparams16(i16 %x, i16 %x, i16 %x, i16 %x, i16 %x, i16 %x, i16 0, i16 -1) 403 ret void 404} 405 406; NORMAL-LABEL: pr34863_32 407; NORMAL: movl 4(%esp), %eax 408; NORMAL-NEXT: pushl $-1 409; NORMAL-NEXT: pushl $0 410; NORMAL-NEXT: pushl %eax 411; NORMAL-NEXT: pushl %eax 412; NORMAL-NEXT: pushl %eax 413; NORMAL-NEXT: pushl %eax 414; NORMAL-NEXT: pushl %eax 415; NORMAL-NEXT: pushl %eax 416; NORMAL-NEXT: calll _eightparams 417; NORMAL-NEXT: addl $32, %esp 418; 419; NOPUSH-LABEL: pr34863_32 420; NOPUSH: subl $32, %esp 421; NOPUSH-NEXT: movl 36(%esp), %eax 422; NOPUSH-NEXT: movl %eax, 20(%esp) 423; NOPUSH-NEXT: movl %eax, 16(%esp) 424; NOPUSH-NEXT: movl %eax, 12(%esp) 425; NOPUSH-NEXT: movl %eax, 8(%esp) 426; NOPUSH-NEXT: movl %eax, 4(%esp) 427; NOPUSH-NEXT: movl %eax, (%esp) 428; NOPUSH-NEXT: orl $-1, 28(%esp) 429; NOPUSH-NEXT: andl $0, 24(%esp) 430; NOPUSH-NEXT: calll _eightparams 431; NOPUSH-NEXT: addl $32, %esp 432define void @pr34863_32(i32 %x) minsize nounwind { 433entry: 434 tail call void @eightparams(i32 %x, i32 %x, i32 %x, i32 %x, i32 %x, i32 %x, i32 0, i32 -1) 435 ret void 436} 437 438; NORMAL-LABEL: pr34863_64 439; NORMAL: movl 4(%esp), %eax 440; NORMAL-NEXT: movl 8(%esp), %ecx 441; NORMAL-NEXT: pushl $-1 442; NORMAL-NEXT: pushl $-1 443; NORMAL-NEXT: pushl $0 444; NORMAL-NEXT: pushl $0 445; NORMAL-NEXT: pushl %ecx 446; NORMAL-NEXT: pushl %eax 447; NORMAL-NEXT: pushl %ecx 448; NORMAL-NEXT: pushl %eax 449; NORMAL-NEXT: pushl %ecx 450; NORMAL-NEXT: pushl %eax 451; NORMAL-NEXT: pushl %ecx 452; NORMAL-NEXT: pushl %eax 453; NORMAL-NEXT: pushl %ecx 454; NORMAL-NEXT: pushl %eax 455; NORMAL-NEXT: pushl %ecx 456; NORMAL-NEXT: pushl %eax 457; NORMAL-NEXT: calll _eightparams64 458; NORMAL-NEXT: addl $64, %esp 459; 460; NOPUSH-LABEL: pr34863_64 461; NOPUSH: subl $64, %esp 462; NOPUSH-NEXT: movl 68(%esp), %eax 463; NOPUSH-NEXT: movl 72(%esp), %ecx 464; NOPUSH-NEXT: movl %ecx, 44(%esp) 465; NOPUSH-NEXT: movl %eax, 40(%esp) 466; NOPUSH-NEXT: movl %ecx, 36(%esp) 467; NOPUSH-NEXT: movl %eax, 32(%esp) 468; NOPUSH-NEXT: movl %ecx, 28(%esp) 469; NOPUSH-NEXT: movl %eax, 24(%esp) 470; NOPUSH-NEXT: movl %ecx, 20(%esp) 471; NOPUSH-NEXT: movl %eax, 16(%esp) 472; NOPUSH-NEXT: movl %ecx, 12(%esp) 473; NOPUSH-NEXT: movl %eax, 8(%esp) 474; NOPUSH-NEXT: movl %ecx, 4(%esp) 475; NOPUSH-NEXT: movl %eax, (%esp) 476; NOPUSH-NEXT: orl $-1, 60(%esp) 477; NOPUSH-NEXT: orl $-1, 56(%esp) 478; NOPUSH-NEXT: andl $0, 52(%esp) 479; NOPUSH-NEXT: andl $0, 48(%esp) 480; NOPUSH-NEXT: calll _eightparams64 481; NOPUSH-NEXT: addl $64, %esp 482define void @pr34863_64(i64 %x) minsize nounwind { 483entry: 484 tail call void @eightparams64(i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 %x, i64 0, i64 -1) 485 ret void 486} 487