mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
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
This commit is contained in:
parent
4878b8415f
commit
ded05e34b6
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -307,6 +307,20 @@ def CC_X86_32_FastCall : CallingConv<[
|
||||
CCDelegateTo<CC_X86_32_Common>
|
||||
]>;
|
||||
|
||||
def CC_X86_32_ThisCall : CallingConv<[
|
||||
// Promote i8/i16 arguments to i32.
|
||||
CCIfType<[i8, i16], CCPromoteToType<i32>>,
|
||||
|
||||
// The 'nest' parameter, if any, is passed in EAX.
|
||||
CCIfNest<CCAssignToReg<[EAX]>>,
|
||||
|
||||
// The first integer argument is passed in ECX
|
||||
CCIfType<[i32], CCAssignToReg<[ECX]>>,
|
||||
|
||||
// Otherwise, same as everything else.
|
||||
CCDelegateTo<CC_X86_32_Common>
|
||||
]>;
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 ) ; <i64> [#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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user