From ded05e34b65dc42998e9db6ca1abd513e7a9d120 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 16 May 2010 09:08:45 +0000 Subject: [PATCH] Add support for thiscall calling convention. Patch by Charles Davis and Steven Watanabe! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@103902 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CallingConv.h | 7 ++++++- lib/AsmParser/LLLexer.cpp | 1 + lib/AsmParser/LLParser.cpp | 2 ++ lib/AsmParser/LLToken.h | 2 +- lib/Target/CBackend/CBackend.cpp | 3 +++ lib/Target/MSIL/MSILWriter.cpp | 2 ++ lib/Target/X86/X86CallingConv.td | 14 ++++++++++++++ lib/Target/X86/X86FastISel.cpp | 2 ++ lib/Target/X86/X86ISelLowering.cpp | 11 +++++++++-- lib/VMCore/AsmWriter.cpp | 3 +++ lib/VMCore/Verifier.cpp | 1 + test/CodeGen/X86/fast-cc-callee-pops.ll | 8 +++++++- test/CodeGen/X86/fast-cc-pass-in-regs.ll | 18 ++++++++++++++++-- 13 files changed, 67 insertions(+), 7 deletions(-) diff --git a/include/llvm/CallingConv.h b/include/llvm/CallingConv.h index 624390d1cd8..b0481b92bae 100644 --- a/include/llvm/CallingConv.h +++ b/include/llvm/CallingConv.h @@ -74,7 +74,12 @@ namespace CallingConv { ARM_AAPCS_VFP = 68, /// MSP430_INTR - Calling convention used for MSP430 interrupt routines. - MSP430_INTR = 69 + MSP430_INTR = 69, + + /// X86_ThisCall - Similar to X86_StdCall. Passes first argument in ECX, + /// others via stack. Callee is responsible for stack cleaning. MSVC uses + /// this by default for methods in its ABI. + X86_ThisCall = 70 }; } // End CallingConv namespace diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 46f3cbcfa37..9b4370fbb4e 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -537,6 +537,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(coldcc); KEYWORD(x86_stdcallcc); KEYWORD(x86_fastcallcc); + KEYWORD(x86_thiscallcc); KEYWORD(arm_apcscc); KEYWORD(arm_aapcscc); KEYWORD(arm_aapcs_vfpcc); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 3b08ca18053..226d8d32729 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -1074,6 +1074,7 @@ bool LLParser::ParseOptionalVisibility(unsigned &Res) { /// ::= 'coldcc' /// ::= 'x86_stdcallcc' /// ::= 'x86_fastcallcc' +/// ::= 'x86_thiscallcc' /// ::= 'arm_apcscc' /// ::= 'arm_aapcscc' /// ::= 'arm_aapcs_vfpcc' @@ -1088,6 +1089,7 @@ bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) { case lltok::kw_coldcc: CC = CallingConv::Cold; break; 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_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 3ac91690067..5eed1709088 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -68,7 +68,7 @@ namespace lltok { kw_c, kw_cc, kw_ccc, kw_fastcc, kw_coldcc, - kw_x86_stdcallcc, kw_x86_fastcallcc, + kw_x86_stdcallcc, kw_x86_fastcallcc, kw_x86_thiscallcc, kw_arm_apcscc, kw_arm_aapcscc, kw_arm_aapcs_vfpcc, kw_msp430_intrcc, diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index cc9e1d74654..55b8aaa4179 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -2165,6 +2165,9 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) { case CallingConv::X86_FastCall: Out << "__attribute__((fastcall)) "; break; + case CallingConv::X86_ThisCall: + Out << "__attribute__((thiscall)) "; + break; default: break; } diff --git a/lib/Target/MSIL/MSILWriter.cpp b/lib/Target/MSIL/MSILWriter.cpp index 332a150e6c4..3de173cc26c 100644 --- a/lib/Target/MSIL/MSILWriter.cpp +++ b/lib/Target/MSIL/MSILWriter.cpp @@ -278,6 +278,8 @@ std::string MSILWriter::getConvModopt(CallingConv::ID CallingConvID) { return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvFastcall) "; case CallingConv::X86_StdCall: return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) "; + case CallingConv::X86_ThisCall: + return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) "; default: errs() << "CallingConvID = " << CallingConvID << '\n'; llvm_unreachable("Unsupported calling convention"); diff --git a/lib/Target/X86/X86CallingConv.td b/lib/Target/X86/X86CallingConv.td index fd15efd6262..a5774e1f241 100644 --- a/lib/Target/X86/X86CallingConv.td +++ b/lib/Target/X86/X86CallingConv.td @@ -307,6 +307,20 @@ def CC_X86_32_FastCall : CallingConv<[ CCDelegateTo ]>; +def CC_X86_32_ThisCall : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType>, + + // The 'nest' parameter, if any, is passed in EAX. + CCIfNest>, + + // The first integer argument is passed in ECX + CCIfType<[i32], CCAssignToReg<[ECX]>>, + + // Otherwise, same as everything else. + CCDelegateTo +]>; + def CC_X86_32_FastCC : CallingConv<[ // Handles byval parameters. Note that we can't rely on the delegation // to CC_X86_32_Common for this because that happens after code that diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 953ba182124..7f97b4860fa 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -180,6 +180,8 @@ CCAssignFn *X86FastISel::CCAssignFnForCall(CallingConv::ID CC, if (CC == CallingConv::X86_FastCall) return CC_X86_32_FastCall; + else if (CC == CallingConv::X86_ThisCall) + return CC_X86_32_ThisCall; else if (CC == CallingConv::Fast) return CC_X86_32_FastCC; else if (CC == CallingConv::GHC) diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 88ee52f9b7b..9fa7bb1d3cc 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1383,6 +1383,8 @@ bool X86TargetLowering::IsCalleePop(bool IsVarArg, return !Subtarget->is64Bit(); case CallingConv::X86_FastCall: return !Subtarget->is64Bit(); + case CallingConv::X86_ThisCall: + return !Subtarget->is64Bit(); case CallingConv::Fast: return GuaranteedTailCallOpt; case CallingConv::GHC: @@ -1404,6 +1406,8 @@ CCAssignFn *X86TargetLowering::CCAssignFnForNode(CallingConv::ID CC) const { if (CC == CallingConv::X86_FastCall) return CC_X86_32_FastCall; + else if (CC == CallingConv::X86_ThisCall) + return CC_X86_32_ThisCall; else if (CC == CallingConv::Fast) return CC_X86_32_FastCC; else if (CC == CallingConv::GHC) @@ -1595,7 +1599,8 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, // If the function takes variable number of arguments, make a frame index for // the start of the first vararg value... for expansion of llvm.va_start. if (isVarArg) { - if (Is64Bit || CallConv != CallingConv::X86_FastCall) { + if (Is64Bit || (CallConv != CallingConv::X86_FastCall && + CallConv != CallingConv::X86_ThisCall)) { FuncInfo->setVarArgsFrameIndex(MFI->CreateFixedObject(1, StackSize, true, false)); } @@ -1715,7 +1720,8 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, if (!Is64Bit) { // RegSaveFrameIndex is X86-64 only. FuncInfo->setRegSaveFrameIndex(0xAAAAAAA); - if (CallConv == CallingConv::X86_FastCall) + if (CallConv == CallingConv::X86_FastCall || + CallConv == CallingConv::X86_ThisCall) // fastcc functions can't have varargs. FuncInfo->setVarArgsFrameIndex(0xAAAAAAA); } @@ -7119,6 +7125,7 @@ SDValue X86TargetLowering::LowerTRAMPOLINE(SDValue Op, break; } case CallingConv::X86_FastCall: + case CallingConv::X86_ThisCall: case CallingConv::Fast: // Pass 'nest' parameter in EAX. // Must be kept in sync with X86CallingConv.td diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 4e8938f7b75..e48c026b774 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -1573,6 +1573,7 @@ void AssemblyWriter::printFunction(const Function *F) { case CallingConv::Cold: Out << "coldcc "; break; 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::ARM_APCS: Out << "arm_apcscc "; break; case CallingConv::ARM_AAPCS: Out << "arm_aapcscc "; break; case CallingConv::ARM_AAPCS_VFP:Out << "arm_aapcs_vfpcc "; break; @@ -1845,6 +1846,7 @@ void AssemblyWriter::printInstruction(const Instruction &I) { case CallingConv::Cold: Out << " coldcc"; break; 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::ARM_APCS: Out << " arm_apcscc "; break; case CallingConv::ARM_AAPCS: Out << " arm_aapcscc "; break; case CallingConv::ARM_AAPCS_VFP:Out << " arm_aapcs_vfpcc "; break; @@ -1897,6 +1899,7 @@ void AssemblyWriter::printInstruction(const Instruction &I) { case CallingConv::Cold: Out << " coldcc"; break; 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::ARM_APCS: Out << " arm_apcscc "; break; case CallingConv::ARM_AAPCS: Out << " arm_aapcscc "; break; case CallingConv::ARM_AAPCS_VFP:Out << " arm_aapcs_vfpcc "; break; diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index b7853492ac7..75988cca72c 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -688,6 +688,7 @@ void Verifier::visitFunction(Function &F) { case CallingConv::Fast: case CallingConv::Cold: case CallingConv::X86_FastCall: + case CallingConv::X86_ThisCall: Assert1(!F.isVarArg(), "Varargs functions must have C calling conventions!", &F); break; diff --git a/test/CodeGen/X86/fast-cc-callee-pops.ll b/test/CodeGen/X86/fast-cc-callee-pops.ll index 5e88ed7f00d..ea10897c735 100644 --- a/test/CodeGen/X86/fast-cc-callee-pops.ll +++ b/test/CodeGen/X86/fast-cc-callee-pops.ll @@ -1,7 +1,13 @@ -; RUN: llc < %s -march=x86 -x86-asm-syntax=intel -mcpu=yonah | grep {ret 20} +; RUN: llc < %s -march=x86 -x86-asm-syntax=intel -mcpu=yonah | FileCheck %s ; Check that a fastcc function pops its stack variables before returning. define x86_fastcallcc void @func(i64 %X, i64 %Y, float %G, double %Z) nounwind { ret void +; CHECK: ret{{.*}}20 +} + +define x86_thiscallcc void @func2(i32 %X, i64 %Y, float %G, double %Z) nounwind { + ret void +; CHECK: ret{{.*}}20 } diff --git a/test/CodeGen/X86/fast-cc-pass-in-regs.ll b/test/CodeGen/X86/fast-cc-pass-in-regs.ll index fe96c0c8be2..a96e5043fed 100644 --- a/test/CodeGen/X86/fast-cc-pass-in-regs.ll +++ b/test/CodeGen/X86/fast-cc-pass-in-regs.ll @@ -1,15 +1,29 @@ -; RUN: llc < %s -march=x86 -x86-asm-syntax=intel | \ -; RUN: grep {mov EDX, 1} +; RUN: llc < %s -march=x86 -x86-asm-syntax=intel | FileCheck %s ; check that fastcc is passing stuff in regs. declare x86_fastcallcc i64 @callee(i64) define i64 @caller() { %X = call x86_fastcallcc i64 @callee( i64 4294967299 ) ; [#uses=1] +; CHECK: mov{{.*}}EDX, 1 ret i64 %X } define x86_fastcallcc i64 @caller2(i64 %X) { ret i64 %X +; CHECK: mov{{.*}}EAX, ECX +} + +declare x86_thiscallcc i64 @callee2(i32) + +define i64 @caller3() { + %X = call x86_thiscallcc i64 @callee2( i32 3 ) +; CHECK: mov{{.*}}ECX, 3 + ret i64 %X +} + +define x86_thiscallcc i32 @caller4(i32 %X) { + ret i32 %X +; CHECK: mov{{.*}}EAX, ECX }