From 21a9fd247ef20f03f6ac8d61daa20d44e39c11b5 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 3 Dec 2013 20:51:23 +0000 Subject: [PATCH] Fix mingw32 thiscall + sret. Unlike msvc, when handling a thiscall + sret gcc will * Put the sret in %ecx * Put the this pointer is (%esp) This fixes, for example, calling stringstream::str. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@196312 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86CallingConv.td | 26 +++++++++++++++++++++----- test/CodeGen/X86/win32_sret.ll | 28 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/lib/Target/X86/X86CallingConv.td b/lib/Target/X86/X86CallingConv.td index a78b5c0a796..fdc1140d596 100644 --- a/lib/Target/X86/X86CallingConv.td +++ b/lib/Target/X86/X86CallingConv.td @@ -453,18 +453,34 @@ def CC_X86_32_FastCall : CallingConv<[ CCDelegateTo ]>; -def CC_X86_32_ThisCall : CallingConv<[ +def CC_X86_32_ThisCall_Common : CallingConv<[ + // The first integer argument is passed in ECX + CCIfType<[i32], CCAssignToReg<[ECX]>>, + + // Otherwise, same as everything else. + CCDelegateTo +]>; + +def CC_X86_32_ThisCall_Mingw : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType>, + + CCDelegateTo +]>; + +def CC_X86_32_ThisCall_Win : CallingConv<[ // Promote i8/i16 arguments to i32. CCIfType<[i8, i16], CCPromoteToType>, // Pass sret arguments indirectly through stack. CCIfSRet>, - // The first integer argument is passed in ECX - CCIfType<[i32], CCAssignToReg<[ECX]>>, + CCDelegateTo +]>; - // Otherwise, same as everything else. - CCDelegateTo +def CC_X86_32_ThisCall : CallingConv<[ + CCIfSubtarget<"isTargetCygMing()", CCDelegateTo>, + CCDelegateTo ]>; def CC_X86_32_FastCC : CallingConv<[ diff --git a/test/CodeGen/X86/win32_sret.ll b/test/CodeGen/X86/win32_sret.ll index a24963a3f34..002cac88245 100644 --- a/test/CodeGen/X86/win32_sret.ll +++ b/test/CodeGen/X86/win32_sret.ll @@ -124,3 +124,31 @@ entry: ; WIN32: ret ret void } + + +%struct.test6 = type { i32, i32, i32 } +define void @test6_f(%struct.test6* %x) nounwind { +; WIN32-LABEL: _test6_f: +; MINGW_X86-LABEL: _test6_f: + +; The %x argument is moved to %ecx. It will be the this pointer. +; WIN32: movl 8(%ebp), %ecx + +; The %x argument is moved to (%esp). It will be the this pointer. With -O0 +; we copy esp to ecx and use (ecx) instead of (esp). +; MINGW_X86: movl 8(%ebp), %eax +; MINGW_X86: movl %eax, (%e{{([a-d]x)|(sp)}}) + +; The sret pointer is (%esp) +; WIN32: leal 8(%esp), %[[REG:e[a-d]x]] +; WIN32-NEXT: movl %[[REG]], (%e{{([a-d]x)|(sp)}}) + +; The sret pointer is %ecx +; MINGW_X86-NEXT: leal 8(%esp), %ecx +; MINGW_X86-NEXT: calll _test6_g + + %tmp = alloca %struct.test6, align 4 + call x86_thiscallcc void @test6_g(%struct.test6* sret %tmp, %struct.test6* %x) + ret void +} +declare x86_thiscallcc void @test6_g(%struct.test6* sret, %struct.test6*)