1; RUN: llc -verify-machineinstrs < %s -mtriple=i686-win32 | FileCheck %s 2; RUN: llc -verify-machineinstrs < %s -mtriple=i686-win32 -O0 | FileCheck %s 3 4; IR simplified from the following C++ snippet compiled for i686-windows-msvc: 5 6; struct A { A(); ~A(); int a; }; 7; 8; struct B { 9; virtual int f(int); 10; virtual int g(A, int, A); 11; virtual void h(A, int, A); 12; virtual A i(A, int, A); 13; virtual A j(int); 14; }; 15; 16; int (B::*mp_f)(int) = &B::f; 17; int (B::*mp_g)(A, int, A) = &B::g; 18; void (B::*mp_h)(A, int, A) = &B::h; 19; A (B::*mp_i)(A, int, A) = &B::i; 20; A (B::*mp_j)(int) = &B::j; 21 22; Each member pointer creates a thunk. The ones with inalloca are required to 23; tail calls by the ABI, even at O0. 24 25%struct.B = type { ptr } 26%struct.A = type { i32 } 27 28; CHECK-LABEL: f_thunk: 29; CHECK: jmpl 30; CHECK-NOT: ret 31define x86_thiscallcc i32 @f_thunk(ptr %this, i32) { 32entry: 33 %vtable = load ptr, ptr %this 34 %1 = load ptr, ptr %vtable 35 %2 = musttail call x86_thiscallcc i32 %1(ptr %this, i32 %0) 36 ret i32 %2 37} 38 39; Inalloca thunks shouldn't require any stores to the stack. 40; CHECK-LABEL: g_thunk: 41; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 42; CHECK: jmpl 43; CHECK-NOT: ret 44define x86_thiscallcc i32 @g_thunk(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>)) { 45entry: 46 %vtable = load ptr, ptr %this 47 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1 48 %1 = load ptr, ptr %vfn 49 %2 = musttail call x86_thiscallcc i32 %1(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>) %0) 50 ret i32 %2 51} 52 53; Preallocated thunks shouldn't require any stores to the stack. 54; CHECK-LABEL: g_thunk_preallocated: 55; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 56; CHECK: jmpl 57; CHECK-NOT: ret 58define x86_thiscallcc i32 @g_thunk_preallocated(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>)) { 59entry: 60 %vtable = load ptr, ptr %this 61 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1 62 %1 = load ptr, ptr %vfn 63 %2 = musttail call x86_thiscallcc i32 %1(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>) %0) 64 ret i32 %2 65} 66 67; CHECK-LABEL: h_thunk: 68; CHECK: jmpl 69; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 70; CHECK-NOT: ret 71define x86_thiscallcc void @h_thunk(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>)) { 72entry: 73 %vtable = load ptr, ptr %this 74 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 2 75 %1 = load ptr, ptr %vfn 76 musttail call x86_thiscallcc void %1(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>) %0) 77 ret void 78} 79 80; CHECK-LABEL: h_thunk_preallocated: 81; CHECK: jmpl 82; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 83; CHECK-NOT: ret 84define x86_thiscallcc void @h_thunk_preallocated(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>)) { 85entry: 86 %vtable = load ptr, ptr %this 87 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 2 88 %1 = load ptr, ptr %vfn 89 musttail call x86_thiscallcc void %1(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>) %0) 90 ret void 91} 92 93; CHECK-LABEL: i_thunk: 94; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 95; CHECK: jmpl 96; CHECK-NOT: ret 97define x86_thiscallcc ptr @i_thunk(ptr %this, ptr inalloca(<{ ptr, %struct.A, i32, %struct.A }>)) { 98entry: 99 %vtable = load ptr, ptr %this 100 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 3 101 %1 = load ptr, ptr %vfn 102 %2 = musttail call x86_thiscallcc ptr %1(ptr %this, ptr inalloca(<{ ptr, %struct.A, i32, %struct.A }>) %0) 103 ret ptr %2 104} 105 106; CHECK-LABEL: i_thunk_preallocated: 107; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 108; CHECK: jmpl 109; CHECK-NOT: ret 110define x86_thiscallcc ptr @i_thunk_preallocated(ptr %this, ptr preallocated(<{ ptr, %struct.A, i32, %struct.A }>)) { 111entry: 112 %vtable = load ptr, ptr %this 113 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 3 114 %1 = load ptr, ptr %vfn 115 %2 = musttail call x86_thiscallcc ptr %1(ptr %this, ptr preallocated(<{ ptr, %struct.A, i32, %struct.A }>) %0) 116 ret ptr %2 117} 118 119; CHECK-LABEL: j_thunk: 120; CHECK: jmpl 121; CHECK-NOT: ret 122define x86_thiscallcc void @j_thunk(ptr noalias sret(%struct.A) %agg.result, ptr %this, i32) { 123entry: 124 %vtable = load ptr, ptr %this 125 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 4 126 %1 = load ptr, ptr %vfn 127 musttail call x86_thiscallcc void %1(ptr sret(%struct.A) %agg.result, ptr %this, i32 %0) 128 ret void 129} 130 131; CHECK-LABEL: _stdcall_thunk@8: 132; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 133; CHECK: jmpl 134; CHECK-NOT: ret 135define x86_stdcallcc i32 @stdcall_thunk(ptr inalloca(<{ ptr, %struct.A }>)) { 136entry: 137 %this_ptr = getelementptr inbounds <{ ptr, %struct.A }>, ptr %0, i32 0, i32 0 138 %this = load ptr, ptr %this_ptr 139 %vtable = load ptr, ptr %this 140 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1 141 %1 = load ptr, ptr %vfn 142 %2 = musttail call x86_stdcallcc i32 %1(ptr inalloca(<{ ptr, %struct.A }>) %0) 143 ret i32 %2 144} 145 146; CHECK-LABEL: _stdcall_thunk_preallocated@8: 147; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 148; CHECK: jmpl 149; CHECK-NOT: ret 150define x86_stdcallcc i32 @stdcall_thunk_preallocated(ptr preallocated(<{ ptr, %struct.A }>)) { 151entry: 152 %this_ptr = getelementptr inbounds <{ ptr, %struct.A }>, ptr %0, i32 0, i32 0 153 %this = load ptr, ptr %this_ptr 154 %vtable = load ptr, ptr %this 155 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1 156 %1 = load ptr, ptr %vfn 157 %2 = musttail call x86_stdcallcc i32 %1(ptr preallocated(<{ ptr, %struct.A }>) %0) 158 ret i32 %2 159} 160 161; CHECK-LABEL: @fastcall_thunk@8: 162; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 163; CHECK: jmpl 164; CHECK-NOT: ret 165define x86_fastcallcc i32 @fastcall_thunk(ptr inreg %this, ptr inalloca(<{ %struct.A }>)) { 166entry: 167 %vtable = load ptr, ptr %this 168 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1 169 %1 = load ptr, ptr %vfn 170 %2 = musttail call x86_fastcallcc i32 %1(ptr inreg %this, ptr inalloca(<{ %struct.A }>) %0) 171 ret i32 %2 172} 173 174; CHECK-LABEL: @fastcall_thunk_preallocated@8: 175; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}} 176; CHECK: jmpl 177; CHECK-NOT: ret 178define x86_fastcallcc i32 @fastcall_thunk_preallocated(ptr inreg %this, ptr preallocated(<{ %struct.A }>)) { 179entry: 180 %vtable = load ptr, ptr %this 181 %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1 182 %1 = load ptr, ptr %vfn 183 %2 = musttail call x86_fastcallcc i32 %1(ptr inreg %this, ptr preallocated(<{ %struct.A }>) %0) 184 ret i32 %2 185} 186