From 65c98b9da474d0562f883d6001f31ba5b2b95183 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 31 Jan 2014 17:41:22 +0000 Subject: [ms-cxxabi] Add a new calling convention that swaps 'this' and 'sret' MSVC always places the 'this' parameter for a method first. The implicit 'sret' pointer for methods always comes second. We already implement this for __thiscall by putting sret parameters on the stack, but __cdecl methods require putting both parameters on the stack in opposite order. Using a special calling convention allows frontends to keep the sret parameter first, which avoids breaking lots of assumptions in LLVM and Clang. Fixes PR15768 with the corresponding change in Clang. Reviewers: ributzka, majnemer Differential Revision: http://llvm-reviews.chandlerc.com/D2663 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200561 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AsmParser/LLLexer.cpp | 1 + lib/AsmParser/LLParser.cpp | 2 ++ lib/AsmParser/LLToken.h | 2 +- lib/IR/AsmWriter.cpp | 1 + lib/Target/X86/X86CallingConv.h | 27 +++++++++++++++++++++++++++ lib/Target/X86/X86CallingConv.td | 10 ++++++++++ 6 files changed, 42 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 7fb8032ca9..00b137d5a7 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -550,6 +550,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(x86_stdcallcc); KEYWORD(x86_fastcallcc); KEYWORD(x86_thiscallcc); + KEYWORD(x86_cdeclmethodcc); KEYWORD(arm_apcscc); KEYWORD(arm_aapcscc); KEYWORD(arm_aapcs_vfpcc); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index ab4b48bf6e..b36f0e840c 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -1357,6 +1357,7 @@ bool LLParser::ParseOptionalDLLStorageClass(unsigned &Res) { /// ::= 'x86_stdcallcc' /// ::= 'x86_fastcallcc' /// ::= 'x86_thiscallcc' +/// ::= 'x86_cdeclmethodcc' /// ::= 'arm_apcscc' /// ::= 'arm_aapcscc' /// ::= 'arm_aapcs_vfpcc' @@ -1382,6 +1383,7 @@ bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) { case lltok::kw_x86_stdcallcc: CC = CallingConv::X86_StdCall; break; case lltok::kw_x86_fastcallcc: CC = CallingConv::X86_FastCall; break; case lltok::kw_x86_thiscallcc: CC = CallingConv::X86_ThisCall; break; + case lltok::kw_x86_cdeclmethodcc:CC = CallingConv::X86_CDeclMethod; break; case lltok::kw_arm_apcscc: CC = CallingConv::ARM_APCS; break; case lltok::kw_arm_aapcscc: CC = CallingConv::ARM_AAPCS; break; case lltok::kw_arm_aapcs_vfpcc:CC = CallingConv::ARM_AAPCS_VFP; break; diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 50318500bf..67f2c0c42b 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -85,7 +85,7 @@ namespace lltok { kw_cc, kw_ccc, kw_fastcc, kw_coldcc, kw_intel_ocl_bicc, - kw_x86_stdcallcc, kw_x86_fastcallcc, kw_x86_thiscallcc, + kw_x86_stdcallcc, kw_x86_fastcallcc, kw_x86_thiscallcc, kw_x86_cdeclmethodcc, kw_arm_apcscc, kw_arm_aapcscc, kw_arm_aapcs_vfpcc, kw_msp430_intrcc, kw_ptx_kernel, kw_ptx_device, diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index 2b23278a88..c48214cc2f 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -78,6 +78,7 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::X86_StdCall: Out << "x86_stdcallcc"; break; case CallingConv::X86_FastCall: Out << "x86_fastcallcc"; break; case CallingConv::X86_ThisCall: Out << "x86_thiscallcc"; break; + case CallingConv::X86_CDeclMethod:Out << "x86_cdeclmethodcc"; break; case CallingConv::Intel_OCL_BI: Out << "intel_ocl_bicc"; break; case CallingConv::ARM_APCS: Out << "arm_apcscc"; break; case CallingConv::ARM_AAPCS: Out << "arm_aapcscc"; break; diff --git a/lib/Target/X86/X86CallingConv.h b/lib/Target/X86/X86CallingConv.h index e76f9fda2d..040da3535e 100644 --- a/lib/Target/X86/X86CallingConv.h +++ b/lib/Target/X86/X86CallingConv.h @@ -29,6 +29,33 @@ inline bool CC_X86_AnyReg_Error(unsigned &, MVT &, MVT &, return false; } +inline bool CC_X86_CDeclMethod_SRet(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { + // Swap the order of the first two parameters if the first parameter is sret. + if (ArgFlags.isSRet()) { + assert(ValNo == 0); + assert(ValVT == MVT::i32); + State.AllocateStack(8, 4); + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 4, LocVT, LocInfo)); + + // Indicate that we need to swap the order of the first and second + // parameters by "allocating" register zero. There are no register + // parameters with cdecl methods, so we can use this to communicate to the + // next call. + State.AllocateReg(1); + return true; + } else if (ValNo == 1 && State.isAllocated(1)) { + assert(ValVT == MVT::i32 && "non-i32-sized this param unsupported"); + // Stack was already allocated while processing sret. + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 0, LocVT, LocInfo)); + return true; + } + + // All other args use the C calling convention. + return false; +} + } // End llvm namespace #endif diff --git a/lib/Target/X86/X86CallingConv.td b/lib/Target/X86/X86CallingConv.td index 5b51a1e8e0..f40a42ee9b 100644 --- a/lib/Target/X86/X86CallingConv.td +++ b/lib/Target/X86/X86CallingConv.td @@ -485,6 +485,15 @@ def CC_X86_32_ThisCall_Win : CallingConv<[ CCDelegateTo ]>; +def CC_X86_CDeclMethod : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType>, + + CCCustom<"CC_X86_CDeclMethod_SRet">, + + CCDelegateTo +]>; + def CC_X86_32_ThisCall : CallingConv<[ CCIfSubtarget<"isTargetCygMing()", CCDelegateTo>, CCDelegateTo @@ -574,6 +583,7 @@ def CC_Intel_OCL_BI : CallingConv<[ def CC_X86_32 : CallingConv<[ CCIfCC<"CallingConv::X86_FastCall", CCDelegateTo>, CCIfCC<"CallingConv::X86_ThisCall", CCDelegateTo>, + CCIfCC<"CallingConv::X86_CDeclMethod", CCDelegateTo>, CCIfCC<"CallingConv::Fast", CCDelegateTo>, CCIfCC<"CallingConv::GHC", CCDelegateTo>, CCIfCC<"CallingConv::HiPE", CCDelegateTo>, -- cgit v1.2.3