1 ; RUN: llc < %s -mtriple=i686-windows | FileCheck %s -check-prefix=NORMAL 2 ; RUN: llc < %s -mtriple=x86_64-windows | FileCheck %s -check-prefix=X64 3 ; RUN: llc < %s -mtriple=i686-windows -force-align-stack -stack-alignment=32 | FileCheck %s -check-prefix=ALIGNED 4 5 declare void @good(i32 %a, i32 %b, i32 %c, i32 %d) 6 declare void @inreg(i32 %a, i32 inreg %b, i32 %c, i32 %d) 7 declare void @oneparam(i32 %a) 8 declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) 9 10 11 ; Here, we should have a reserved frame, so we don't expect pushes 12 ; NORMAL-LABEL: test1: 13 ; NORMAL: subl $16, %esp 14 ; NORMAL-NEXT: movl $4, 12(%esp) 15 ; NORMAL-NEXT: movl $3, 8(%esp) 16 ; NORMAL-NEXT: movl $2, 4(%esp) 17 ; NORMAL-NEXT: movl $1, (%esp) 18 ; NORMAL-NEXT: call 19 ; NORMAL-NEXT: addl $16, %esp 20 define void @test1() { 21 entry: 22 call void @good(i32 1, i32 2, i32 3, i32 4) 23 ret void 24 } 25 26 ; We're optimizing for code size, so we should get pushes for x86, 27 ; even though there is a reserved call frame. 28 ; Make sure we don't touch x86-64 29 ; NORMAL-LABEL: test1b: 30 ; NORMAL-NOT: subl {{.*}} %esp 31 ; NORMAL: pushl $4 32 ; NORMAL-NEXT: pushl $3 33 ; NORMAL-NEXT: pushl $2 34 ; NORMAL-NEXT: pushl $1 35 ; NORMAL-NEXT: call 36 ; NORMAL-NEXT: addl $16, %esp 37 ; X64-LABEL: test1b: 38 ; X64: movl $1, %ecx 39 ; X64-NEXT: movl $2, %edx 40 ; X64-NEXT: movl $3, %r8d 41 ; X64-NEXT: movl $4, %r9d 42 ; X64-NEXT: callq good 43 define void @test1b() optsize { 44 entry: 45 call void @good(i32 1, i32 2, i32 3, i32 4) 46 ret void 47 } 48 49 ; Same as above, but for minsize 50 ; NORMAL-LABEL: test1c: 51 ; NORMAL-NOT: subl {{.*}} %esp 52 ; NORMAL: pushl $4 53 ; NORMAL-NEXT: pushl $3 54 ; NORMAL-NEXT: pushl $2 55 ; NORMAL-NEXT: pushl $1 56 ; NORMAL-NEXT: call 57 ; NORMAL-NEXT: addl $16, %esp 58 define void @test1c() minsize { 59 entry: 60 call void @good(i32 1, i32 2, i32 3, i32 4) 61 ret void 62 } 63 64 ; If we have a reserved frame, we should have pushes 65 ; NORMAL-LABEL: test2: 66 ; NORMAL-NOT: subl {{.*}} %esp 67 ; NORMAL: pushl $4 68 ; NORMAL-NEXT: pushl $3 69 ; NORMAL-NEXT: pushl $2 70 ; NORMAL-NEXT: pushl $1 71 ; NORMAL-NEXT: call 72 define void @test2(i32 %k) { 73 entry: 74 %a = alloca i32, i32 %k 75 call void @good(i32 1, i32 2, i32 3, i32 4) 76 ret void 77 } 78 79 ; Again, we expect a sequence of 4 immediate pushes 80 ; Checks that we generate the right pushes for >8bit immediates 81 ; NORMAL-LABEL: test2b: 82 ; NORMAL-NOT: subl {{.*}} %esp 83 ; NORMAL: pushl $4096 84 ; NORMAL-NEXT: pushl $3072 85 ; NORMAL-NEXT: pushl $2048 86 ; NORMAL-NEXT: pushl $1024 87 ; NORMAL-NEXT: call 88 ; NORMAL-NEXT: addl $16, %esp 89 define void @test2b() optsize { 90 entry: 91 call void @good(i32 1024, i32 2048, i32 3072, i32 4096) 92 ret void 93 } 94 95 ; The first push should push a register 96 ; NORMAL-LABEL: test3: 97 ; NORMAL-NOT: subl {{.*}} %esp 98 ; NORMAL: pushl $4 99 ; NORMAL-NEXT: pushl $3 100 ; NORMAL-NEXT: pushl $2 101 ; NORMAL-NEXT: pushl %e{{..}} 102 ; NORMAL-NEXT: call 103 ; NORMAL-NEXT: addl $16, %esp 104 define void @test3(i32 %k) optsize { 105 entry: 106 %f = add i32 %k, 1 107 call void @good(i32 %f, i32 2, i32 3, i32 4) 108 ret void 109 } 110 111 ; We don't support weird calling conventions 112 ; NORMAL-LABEL: test4: 113 ; NORMAL: subl $12, %esp 114 ; NORMAL-NEXT: movl $4, 8(%esp) 115 ; NORMAL-NEXT: movl $3, 4(%esp) 116 ; NORMAL-NEXT: movl $1, (%esp) 117 ; NORMAL-NEXT: movl $2, %eax 118 ; NORMAL-NEXT: call 119 ; NORMAL-NEXT: addl $12, %esp 120 define void @test4() optsize { 121 entry: 122 call void @inreg(i32 1, i32 2, i32 3, i32 4) 123 ret void 124 } 125 126 ; When there is no reserved call frame, check that additional alignment 127 ; is added when the pushes don't add up to the required alignment. 128 ; ALIGNED-LABEL: test5: 129 ; ALIGNED: subl $16, %esp 130 ; ALIGNED-NEXT: pushl $4 131 ; ALIGNED-NEXT: pushl $3 132 ; ALIGNED-NEXT: pushl $2 133 ; ALIGNED-NEXT: pushl $1 134 ; ALIGNED-NEXT: call 135 define void @test5(i32 %k) { 136 entry: 137 %a = alloca i32, i32 %k 138 call void @good(i32 1, i32 2, i32 3, i32 4) 139 ret void 140 } 141 142 ; When the alignment adds up, do the transformation 143 ; ALIGNED-LABEL: test5b: 144 ; ALIGNED: pushl $8 145 ; ALIGNED-NEXT: pushl $7 146 ; ALIGNED-NEXT: pushl $6 147 ; ALIGNED-NEXT: pushl $5 148 ; ALIGNED-NEXT: pushl $4 149 ; ALIGNED-NEXT: pushl $3 150 ; ALIGNED-NEXT: pushl $2 151 ; ALIGNED-NEXT: pushl $1 152 ; ALIGNED-NEXT: call 153 define void @test5b() optsize { 154 entry: 155 call void @eightparams(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8) 156 ret void 157 } 158 159 ; When having to compensate for the alignment isn't worth it, 160 ; don't use pushes. 161 ; ALIGNED-LABEL: test5c: 162 ; ALIGNED: movl $1, (%esp) 163 ; ALIGNED-NEXT: call 164 define void @test5c() optsize { 165 entry: 166 call void @oneparam(i32 1) 167 ret void 168 } 169 170 ; Check that pushing the addresses of globals (Or generally, things that 171 ; aren't exactly immediates) isn't broken. 172 ; Fixes PR21878. 173 ; NORMAL-LABEL: test6: 174 ; NORMAL: pushl $_ext 175 ; NORMAL-NEXT: call 176 declare void @f(i8*) 177 @ext = external constant i8 178 179 define void @test6() { 180 call void @f(i8* @ext) 181 br label %bb 182 bb: 183 alloca i32 184 ret void 185 } 186 187 ; Check that we fold simple cases into the push 188 ; NORMAL-LABEL: test7: 189 ; NORMAL-NOT: subl {{.*}} %esp 190 ; NORMAL: movl 4(%esp), [[EAX:%e..]] 191 ; NORMAL-NEXT: pushl $4 192 ; NORMAL-NEXT: pushl ([[EAX]]) 193 ; NORMAL-NEXT: pushl $2 194 ; NORMAL-NEXT: pushl $1 195 ; NORMAL-NEXT: call 196 ; NORMAL-NEXT: addl $16, %esp 197 define void @test7(i32* %ptr) optsize { 198 entry: 199 %val = load i32, i32* %ptr 200 call void @good(i32 1, i32 2, i32 %val, i32 4) 201 ret void 202 } 203 204 ; Fold stack-relative loads into the push, with correct offset 205 ; In particular, at the second push, %b was at 12(%esp) and 206 ; %a wast at 8(%esp), but the second push bumped %esp, so %a 207 ; is now it at 12(%esp) 208 ; NORMAL-LABEL: test8: 209 ; NORMAL: pushl $4 210 ; NORMAL-NEXT: pushl 12(%esp) 211 ; NORMAL-NEXT: pushl 12(%esp) 212 ; NORMAL-NEXT: pushl $1 213 ; NORMAL-NEXT: call 214 ; NORMAL-NEXT: addl $16, %esp 215 define void @test8(i32 %a, i32 %b) optsize { 216 entry: 217 call void @good(i32 1, i32 %a, i32 %b, i32 4) 218 ret void 219 } 220 221 ; If one function is using push instructions, and the other isn't 222 ; (because it has frame-index references), then we must resolve 223 ; these references correctly. 224 ; NORMAL-LABEL: test9: 225 ; NORMAL-NOT: leal (%esp), 226 ; NORMAL: pushl $4 227 ; NORMAL-NEXT: pushl $3 228 ; NORMAL-NEXT: pushl $2 229 ; NORMAL-NEXT: pushl $1 230 ; NORMAL-NEXT: call 231 ; NORMAL-NEXT: addl $16, %esp 232 ; NORMAL-NEXT: subl $16, %esp 233 ; NORMAL-NEXT: leal 16(%esp), [[EAX:%e..]] 234 ; NORMAL-NEXT: movl [[EAX]], 12(%esp) 235 ; NORMAL-NEXT: movl $7, 8(%esp) 236 ; NORMAL-NEXT: movl $6, 4(%esp) 237 ; NORMAL-NEXT: movl $5, (%esp) 238 ; NORMAL-NEXT: call 239 ; NORMAL-NEXT: addl $16, %esp 240 define void @test9() optsize { 241 entry: 242 %p = alloca i32, align 4 243 call void @good(i32 1, i32 2, i32 3, i32 4) 244 %0 = ptrtoint i32* %p to i32 245 call void @good(i32 5, i32 6, i32 7, i32 %0) 246 ret void 247 } 248 249 ; We can end up with an indirect call which gets reloaded on the spot. 250 ; Make sure we reference the correct stack slot - we spill into (%esp) 251 ; and reload from 16(%esp) due to the pushes. 252 ; NORMAL-LABEL: test10: 253 ; NORMAL: movl $_good, [[ALLOC:.*]] 254 ; NORMAL-NEXT: movl [[ALLOC]], [[EAX:%e..]] 255 ; NORMAL-NEXT: movl [[EAX]], (%esp) # 4-byte Spill 256 ; NORMAL: nop 257 ; NORMAL: pushl $4 258 ; NORMAL-NEXT: pushl $3 259 ; NORMAL-NEXT: pushl $2 260 ; NORMAL-NEXT: pushl $1 261 ; NORMAL-NEXT: calll *16(%esp) 262 ; NORMAL-NEXT: addl $16, %esp 263 define void @test10() optsize { 264 %stack_fptr = alloca void (i32, i32, i32, i32)* 265 store void (i32, i32, i32, i32)* @good, void (i32, i32, i32, i32)** %stack_fptr 266 %good_ptr = load volatile void (i32, i32, i32, i32)*, void (i32, i32, i32, i32)** %stack_fptr 267 call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di}"() 268 call void (i32, i32, i32, i32) %good_ptr(i32 1, i32 2, i32 3, i32 4) 269 ret void 270 } 271 272 ; We can't fold the load from the global into the push because of 273 ; interference from the store 274 ; NORMAL-LABEL: test11: 275 ; NORMAL: movl _the_global, [[EAX:%e..]] 276 ; NORMAL-NEXT: movl $42, _the_global 277 ; NORMAL-NEXT: pushl $4 278 ; NORMAL-NEXT: pushl $3 279 ; NORMAL-NEXT: pushl $2 280 ; NORMAL-NEXT: pushl [[EAX]] 281 ; NORMAL-NEXT: call 282 ; NORMAL-NEXT: addl $16, %esp 283 @the_global = external global i32 284 define void @test11() optsize { 285 %myload = load i32, i32* @the_global 286 store i32 42, i32* @the_global 287 call void @good(i32 %myload, i32 2, i32 3, i32 4) 288 ret void 289 } 290 291 ; Converting one mov into a push isn't worth it when 292 ; doing so forces too much overhead for other calls. 293 ; NORMAL-LABEL: test12: 294 ; NORMAL: subl $16, %esp 295 ; NORMAL-NEXT: movl $4, 8(%esp) 296 ; NORMAL-NEXT: movl $3, 4(%esp) 297 ; NORMAL-NEXT: movl $1, (%esp) 298 ; NORMAL-NEXT: movl $2, %eax 299 ; NORMAL-NEXT: calll _inreg 300 ; NORMAL-NEXT: movl $8, 12(%esp) 301 ; NORMAL-NEXT: movl $7, 8(%esp) 302 ; NORMAL-NEXT: movl $6, 4(%esp) 303 ; NORMAL-NEXT: movl $5, (%esp) 304 ; NORMAL-NEXT: calll _good 305 ; NORMAL-NEXT: movl $12, 8(%esp) 306 ; NORMAL-NEXT: movl $11, 4(%esp) 307 ; NORMAL-NEXT: movl $9, (%esp) 308 ; NORMAL-NEXT: movl $10, %eax 309 ; NORMAL-NEXT: calll _inreg 310 ; NORMAL-NEXT: addl $16, %esp 311 define void @test12() optsize { 312 entry: 313 call void @inreg(i32 1, i32 2, i32 3, i32 4) 314 call void @good(i32 5, i32 6, i32 7, i32 8) 315 call void @inreg(i32 9, i32 10, i32 11, i32 12) 316 ret void 317 } 318 319 ; But if the gains outweigh the overhead, we should do it 320 ; NORMAL-LABEL: test12b: 321 ; NORMAL: pushl $4 322 ; NORMAL-NEXT: pushl $3 323 ; NORMAL-NEXT: pushl $2 324 ; NORMAL-NEXT: pushl $1 325 ; NORMAL-NEXT: calll _good 326 ; NORMAL-NEXT: addl $16, %esp 327 ; NORMAL-NEXT: subl $12, %esp 328 ; NORMAL-NEXT: movl $8, 8(%esp) 329 ; NORMAL-NEXT: movl $7, 4(%esp) 330 ; NORMAL-NEXT: movl $5, (%esp) 331 ; NORMAL-NEXT: movl $6, %eax 332 ; NORMAL-NEXT: calll _inreg 333 ; NORMAL-NEXT: addl $12, %esp 334 ; NORMAL-NEXT: pushl $12 335 ; NORMAL-NEXT: pushl $11 336 ; NORMAL-NEXT: pushl $10 337 ; NORMAL-NEXT: pushl $9 338 ; NORMAL-NEXT: calll _good 339 ; NORMAL-NEXT: addl $16, %esp 340 define void @test12b() optsize { 341 entry: 342 call void @good(i32 1, i32 2, i32 3, i32 4) 343 call void @inreg(i32 5, i32 6, i32 7, i32 8) 344 call void @good(i32 9, i32 10, i32 11, i32 12) 345 ret void 346 } 347