forked from OSchip/llvm-project
144 lines
3.9 KiB
LLVM
144 lines
3.9 KiB
LLVM
|
; RUN: llc < %s -mtriple=i686-pc-linux | FileCheck %s
|
||
|
|
||
|
declare i32 @__gxx_personality_v0(...)
|
||
|
declare void @good(i32 %a, i32 %b, i32 %c, i32 %d)
|
||
|
declare void @large(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f)
|
||
|
declare void @empty()
|
||
|
|
||
|
; We use an invoke, and expect a .cfi_escape GNU_ARGS_SIZE with size 16
|
||
|
; before the invocation
|
||
|
; CHECK-LABEL: test1:
|
||
|
; CHECK: .cfi_escape 0x2e, 0x10
|
||
|
; CHECK-NEXT: pushl $4
|
||
|
; CHECK-NEXT: pushl $3
|
||
|
; CHECK-NEXT: pushl $2
|
||
|
; CHECK-NEXT: pushl $1
|
||
|
; CHECK-NEXT: call
|
||
|
; CHECK-NEXT: addl $16, %esp
|
||
|
define void @test1() optsize personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||
|
entry:
|
||
|
invoke void @good(i32 1, i32 2, i32 3, i32 4)
|
||
|
to label %continue unwind label %cleanup
|
||
|
continue:
|
||
|
ret void
|
||
|
cleanup:
|
||
|
landingpad { i8*, i32 }
|
||
|
cleanup
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; If the function has no handlers, we don't need to generate GNU_ARGS_SIZE,
|
||
|
; even if it has an unwind table.
|
||
|
; CHECK-LABEL: test2:
|
||
|
; CHECK-NOT: .cfi_escape
|
||
|
; CHECK: pushl $4
|
||
|
; CHECK-NEXT: pushl $3
|
||
|
; CHECK-NEXT: pushl $2
|
||
|
; CHECK-NEXT: pushl $1
|
||
|
; CHECK-NEXT: call
|
||
|
; CHECK-NEXT: addl $16, %esp
|
||
|
define void @test2() optsize personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||
|
entry:
|
||
|
call void @good(i32 1, i32 2, i32 3, i32 4)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; If we did not end up using any pushes, no need for GNU_ARGS_SIZE anywhere
|
||
|
; CHECK-LABEL: test3:
|
||
|
; CHECK-NOT: .cfi_escape
|
||
|
; CHECK-NOT: pushl
|
||
|
; CHECK: retl
|
||
|
define void @test3() optsize personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||
|
entry:
|
||
|
invoke void @empty()
|
||
|
to label %continue unwind label %cleanup
|
||
|
continue:
|
||
|
ret void
|
||
|
cleanup:
|
||
|
landingpad { i8*, i32 }
|
||
|
cleanup
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; Different sized stacks need different GNU_ARGS_SIZEs
|
||
|
; CHECK-LABEL: test4:
|
||
|
; CHECK: .cfi_escape 0x2e, 0x10
|
||
|
; CHECK-NEXT: pushl $4
|
||
|
; CHECK-NEXT: pushl $3
|
||
|
; CHECK-NEXT: pushl $2
|
||
|
; CHECK-NEXT: pushl $1
|
||
|
; CHECK-NEXT: call
|
||
|
; CHECK-NEXT: addl $16, %esp
|
||
|
; CHECK: .cfi_escape 0x2e, 0x20
|
||
|
; CHECK-NEXT: subl $8, %esp
|
||
|
; CHECK-NEXT: pushl $11
|
||
|
; CHECK-NEXT: pushl $10
|
||
|
; CHECK-NEXT: pushl $9
|
||
|
; CHECK-NEXT: pushl $8
|
||
|
; CHECK-NEXT: pushl $7
|
||
|
; CHECK-NEXT: pushl $6
|
||
|
; CHECK-NEXT: calll large
|
||
|
; CHECK-NEXT: addl $32, %esp
|
||
|
define void @test4() optsize personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||
|
entry:
|
||
|
invoke void @good(i32 1, i32 2, i32 3, i32 4)
|
||
|
to label %continue1 unwind label %cleanup
|
||
|
continue1:
|
||
|
invoke void @large(i32 6, i32 7, i32 8, i32 9, i32 10, i32 11)
|
||
|
to label %continue2 unwind label %cleanup
|
||
|
continue2:
|
||
|
ret void
|
||
|
cleanup:
|
||
|
landingpad { i8*, i32 }
|
||
|
cleanup
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; If we did use pushes, we need to reset GNU_ARGS_SIZE before a call
|
||
|
; without parameters
|
||
|
; CHECK-LABEL: test5:
|
||
|
; CHECK: .cfi_escape 0x2e, 0x10
|
||
|
; CHECK-NEXT: pushl $4
|
||
|
; CHECK-NEXT: pushl $3
|
||
|
; CHECK-NEXT: pushl $2
|
||
|
; CHECK-NEXT: pushl $1
|
||
|
; CHECK-NEXT: call
|
||
|
; CHECK-NEXT: addl $16, %esp
|
||
|
; CHECK: .cfi_escape 0x2e, 0x00
|
||
|
; CHECK-NEXT: call
|
||
|
define void @test5() optsize personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||
|
entry:
|
||
|
invoke void @good(i32 1, i32 2, i32 3, i32 4)
|
||
|
to label %continue1 unwind label %cleanup
|
||
|
continue1:
|
||
|
invoke void @empty()
|
||
|
to label %continue2 unwind label %cleanup
|
||
|
continue2:
|
||
|
ret void
|
||
|
cleanup:
|
||
|
landingpad { i8*, i32 }
|
||
|
cleanup
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; This is actually inefficient - we don't need to repeat the .cfi_escape twice.
|
||
|
; CHECK-LABEL: test6:
|
||
|
; CHECK: .cfi_escape 0x2e, 0x10
|
||
|
; CHECK: call
|
||
|
; CHECK: .cfi_escape 0x2e, 0x10
|
||
|
; CHECK: call
|
||
|
define void @test6() optsize personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
|
||
|
entry:
|
||
|
invoke void @good(i32 1, i32 2, i32 3, i32 4)
|
||
|
to label %continue1 unwind label %cleanup
|
||
|
continue1:
|
||
|
invoke void @good(i32 5, i32 6, i32 7, i32 8)
|
||
|
to label %continue2 unwind label %cleanup
|
||
|
continue2:
|
||
|
ret void
|
||
|
cleanup:
|
||
|
landingpad { i8*, i32 }
|
||
|
cleanup
|
||
|
ret void
|
||
|
}
|