| ; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck %s | |
| ; RUN: llc < %s -mtriple=i686-pc-win32 -O0 | |
| %struct.S = type { [1024 x i8] } | |
| %struct.T = type { [3000 x i8] } | |
| %struct.U = type { [10000 x i8] } | |
| define void @basics() { | |
| ; CHECK-LABEL: basics: | |
| entry: | |
| br label %bb1 | |
| ; Allocation move sizes should have been removed. | |
| ; CHECK-NOT: movl $1024 | |
| ; CHECK-NOT: movl $3000 | |
| bb1: | |
| %p0 = alloca %struct.S | |
| ; The allocation is small enough not to require stack probing, but the %esp | |
| ; offset after the prologue is not known, so the stack must be touched before | |
| ; the pointer is adjusted. | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $1020, %esp | |
| %saved_stack = tail call i8* @llvm.stacksave() | |
| %p1 = alloca %struct.S | |
| ; We know the %esp offset from above, so there is no need to touch the stack | |
| ; before adjusting it. | |
| ; CHECK: subl $1024, %esp | |
| %p2 = alloca %struct.T | |
| ; The offset is now 2048 bytes, so allocating a T must touch the stack again. | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $2996, %esp | |
| call void @f(%struct.S* %p0) | |
| ; CHECK: calll | |
| %p3 = alloca %struct.T | |
| ; The call above touched the stack, so there is room for a T object. | |
| ; CHECK: subl $3000, %esp | |
| %p4 = alloca %struct.U | |
| ; The U object is large enough to require stack probing. | |
| ; CHECK: movl $10000, %eax | |
| ; CHECK: calll __chkstk | |
| %p5 = alloca %struct.T | |
| ; The stack probing above touched the tip of the stack, so there's room for a T. | |
| ; CHECK: subl $3000, %esp | |
| call void @llvm.stackrestore(i8* %saved_stack) | |
| %p6 = alloca %struct.S | |
| ; The stack restore means we lose track of the stack pointer and must probe. | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $1020, %esp | |
| ; Use the pointers so they're not optimized away. | |
| call void @f(%struct.S* %p1) | |
| call void @g(%struct.T* %p2) | |
| call void @g(%struct.T* %p3) | |
| call void @h(%struct.U* %p4) | |
| call void @g(%struct.T* %p5) | |
| ret void | |
| } | |
| define void @loop() { | |
| ; CHECK-LABEL: loop: | |
| entry: | |
| br label %bb1 | |
| bb1: | |
| %p1 = alloca %struct.S | |
| ; The entry offset is unknown; touch-and-sub. | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $1020, %esp | |
| br label %loop1 | |
| loop1: | |
| %i1 = phi i32 [ 10, %bb1 ], [ %dec1, %loop1 ] | |
| %p2 = alloca %struct.S | |
| ; We know the incoming offset from bb1, but from the back-edge, we assume the | |
| ; worst, and therefore touch-and-sub to allocate. | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $1020, %esp | |
| %dec1 = sub i32 %i1, 1 | |
| %cmp1 = icmp sgt i32 %i1, 0 | |
| br i1 %cmp1, label %loop1, label %end | |
| ; CHECK: decl | |
| ; CHECK: jg | |
| end: | |
| call void @f(%struct.S* %p1) | |
| call void @f(%struct.S* %p2) | |
| ret void | |
| } | |
| define void @probe_size_attribute() "stack-probe-size"="512" { | |
| ; CHECK-LABEL: probe_size_attribute: | |
| entry: | |
| br label %bb1 | |
| bb1: | |
| %p0 = alloca %struct.S | |
| ; The allocation would be small enough not to require probing, if it wasn't | |
| ; for the stack-probe-size attribute. | |
| ; CHECK: movl $1024, %eax | |
| ; CHECK: calll __chkstk | |
| call void @f(%struct.S* %p0) | |
| ret void | |
| } | |
| define void @cfg(i1 %x, i1 %y) { | |
| ; Test that the blocks are analyzed in the correct order. | |
| ; CHECK-LABEL: cfg: | |
| entry: | |
| br i1 %x, label %bb1, label %bb3 | |
| bb1: | |
| %p1 = alloca %struct.S | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $1020, %esp | |
| br label %bb4 | |
| bb2: | |
| %p5 = alloca %struct.T | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $2996, %esp | |
| call void @g(%struct.T* %p5) | |
| ret void | |
| bb3: | |
| %p2 = alloca %struct.T | |
| ; CHECK: pushl %eax | |
| ; CHECK: subl $2996, %esp | |
| br label %bb4 | |
| bb4: | |
| br i1 %y, label %bb5, label %bb2 | |
| bb5: | |
| %p4 = alloca %struct.S | |
| ; CHECK: subl $1024, %esp | |
| call void @f(%struct.S* %p4) | |
| ret void | |
| } | |
| declare void @f(%struct.S*) | |
| declare void @g(%struct.T*) | |
| declare void @h(%struct.U*) | |
| declare i8* @llvm.stacksave() | |
| declare void @llvm.stackrestore(i8*) |