1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
; RUN: llc -mtriple=i686-unknown-linux-gnu -O1 < %s | FileCheck %s
; RUN: llc -mtriple=i686-unknown-linux-gnu -O0 < %s | FileCheck %s
; The MSVC family of x86 calling conventions makes tail calls really tricky.
; Tests of all the various combinations should live here.
declare i32 @cdecl_i32()
declare void @cdecl_void()
; Don't allow tail calling these cdecl functions, because we need to clear the
; incoming stack arguments for these argument-clearing conventions.
define x86_thiscallcc void @thiscall_cdecl_notail(i32 %a, i32 %b, i32 %c) {
tail call void @cdecl_void()
ret void
}
; CHECK-LABEL: thiscall_cdecl_notail
; CHECK: calll cdecl_void
; CHECK: retl $8
define x86_stdcallcc void @stdcall_cdecl_notail(i32 %a, i32 %b, i32 %c) {
tail call void @cdecl_void()
ret void
}
; CHECK-LABEL: stdcall_cdecl_notail
; CHECK: calll cdecl_void
; CHECK: retl $12
define x86_vectorcallcc void @vectorcall_cdecl_notail(i32 inreg %a, i32 inreg %b, i32 %c) {
tail call void @cdecl_void()
ret void
}
; CHECK-LABEL: vectorcall_cdecl_notail
; CHECK: calll cdecl_void
; CHECK: retl $4
define x86_fastcallcc void @fastcall_cdecl_notail(i32 inreg %a, i32 inreg %b, i32 %c) {
tail call void @cdecl_void()
ret void
}
; CHECK-LABEL: fastcall_cdecl_notail
; CHECK: calll cdecl_void
; CHECK: retl $4
; Tail call to/from callee pop functions can work under the right circumstances:
declare x86_thiscallcc void @no_args_method(ptr)
declare x86_thiscallcc void @one_arg_method(ptr, i32)
declare x86_thiscallcc void @two_args_method(ptr, i32, i32)
declare void @ccall_func()
declare void @ccall_func1(i32)
define x86_thiscallcc void @thiscall_thiscall_tail(ptr %this) {
entry:
tail call x86_thiscallcc void @no_args_method(ptr %this)
ret void
}
; CHECK-LABEL: thiscall_thiscall_tail:
; CHECK: jmp no_args_method
define x86_thiscallcc void @thiscall_thiscall_tail2(ptr %this, i32 %a, i32 %b) {
entry:
tail call x86_thiscallcc void @two_args_method(ptr %this, i32 %a, i32 %b)
ret void
}
; @two_args_method will take care of popping %a and %b from the stack for us.
; CHECK-LABEL: thiscall_thiscall_tail2:
; CHECK: jmp two_args_method
define x86_thiscallcc void @thiscall_thiscall_notail(ptr %this, i32 %a, i32 %b, i32 %x) {
entry:
tail call x86_thiscallcc void @two_args_method(ptr %this, i32 %a, i32 %b)
ret void
}
; @two_args_method would not pop %x.
; CHECK-LABEL: thiscall_thiscall_notail:
; CHECK: calll two_args_method
; CHECK: retl $12
define x86_thiscallcc void @thiscall_thiscall_notail2(ptr %this, i32 %a) {
entry:
tail call x86_thiscallcc void @no_args_method(ptr %this)
ret void
}
; @no_args_method would not pop %x for us. Make sure this is checked even
; when there are no arguments to the call.
; CHECK-LABEL: thiscall_thiscall_notail2:
; CHECK: calll no_args_method
; CHECK: retl $4
define void @ccall_thiscall_tail(ptr %x) {
entry:
tail call x86_thiscallcc void @no_args_method(ptr %x)
ret void
}
; Tail calling from ccall to thiscall works.
; CHECK-LABEL: ccall_thiscall_tail:
; CHECK: jmp no_args_method
define void @ccall_thiscall_notail(ptr %x, i32 %y) {
entry:
tail call x86_thiscallcc void @one_arg_method(ptr %x, i32 %y);
ret void
}
; @one_arg_method would pop %y off the stack.
; CHECK-LABEL: ccall_thiscall_notail:
; CHECK: calll one_arg_method
define x86_thiscallcc void @thiscall_ccall_tail(ptr %this) {
entry:
tail call void @ccall_func()
ret void
}
; Tail call from thiscall to ccall works if no arguments need popping.
; CHECK-LABEL: thiscall_ccall_tail:
; CHECK: jmp ccall_func
define x86_thiscallcc void @thiscall_ccall_notail(ptr %this, i32 %x) {
entry:
tail call void @ccall_func1(i32 %x)
ret void
}
; No tail call: %x needs to be popped.
; CHECK-LABEL: thiscall_ccall_notail:
; CHECK: calll ccall_func1
; CHECK: retl $4
%S = type { ptr }
define x86_thiscallcc void @tailcall_through_pointer(ptr %this, i32 %a) {
entry:
%vtable = load ptr, ptr %this
%0 = load ptr, ptr %vtable
tail call x86_thiscallcc void %0(ptr %this, i32 %a)
ret void
}
; Tail calling works through function pointers too.
; CHECK-LABEL: tailcall_through_pointer:
; CHECK: jmpl
define x86_stdcallcc void @stdcall_cdecl_tail() {
tail call void @ccall_func()
ret void
}
; stdcall to cdecl works if no arguments need popping.
; CHECK-LABEL: stdcall_cdecl_tail
; CHECK: jmp ccall_func
define x86_vectorcallcc void @vectorcall_cdecl_tail(i32 inreg %a, i32 inreg %b) {
tail call void @ccall_func()
ret void
}
; vectorcall to cdecl works if no arguments need popping.
; CHECK-LABEL: vectorcall_cdecl_tail
; CHECK: jmp ccall_func
define x86_fastcallcc void @fastcall_cdecl_tail(i32 inreg %a, i32 inreg %b) {
tail call void @ccall_func()
ret void
}
; fastcall to cdecl works if no arguments need popping.
; CHECK-LABEL: fastcall_cdecl_tail
; CHECK: jmp ccall_func
define x86_stdcallcc void @stdcall_thiscall_notail(ptr %this, i32 %a, i32 %b) {
tail call x86_thiscallcc void @two_args_method(ptr %this, i32 %a, i32 %b)
ret void
}
; two_args_method will not pop %this.
; CHECK-LABEL: stdcall_thiscall_notail
; CHECK: calll two_args_method
define x86_stdcallcc void @stdcall_thiscall_tail(i32 %a, i32 %b) {
tail call x86_thiscallcc void @two_args_method(ptr null, i32 %a, i32 %b)
ret void
}
; The callee pop amounts match up.
; CHECK-LABEL: stdcall_thiscall_tail
; CHECK: jmp two_args_method
declare x86_fastcallcc void @fastcall2(i32 inreg %a, i32 inreg %b)
define void @cdecl_fastcall_tail(i32 %a, i32 %b) {
tail call x86_fastcallcc void @fastcall2(i32 inreg %a, i32 inreg %b)
ret void
}
; fastcall2 won't pop anything.
; CHECK-LABEL: cdecl_fastcall_tail
; CHECK: jmp fastcall2
|