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
KEYWORD(coldcc);
KEYWORD(x86_stdcallcc);
KEYWORD(x86_fastcallcc);
+ KEYWORD(x86_thiscallcc);
KEYWORD(arm_apcscc);
KEYWORD(arm_aapcscc);
KEYWORD(arm_aapcs_vfpcc);
/// ::= 'coldcc'
/// ::= 'x86_stdcallcc'
/// ::= 'x86_fastcallcc'
+/// ::= 'x86_thiscallcc'
/// ::= 'arm_apcscc'
/// ::= 'arm_aapcscc'
/// ::= 'arm_aapcs_vfpcc'
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;
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,
case CallingConv::X86_FastCall:
Out << "__attribute__((fastcall)) ";
break;
+ case CallingConv::X86_ThisCall:
+ Out << "__attribute__((thiscall)) ";
+ break;
default:
break;
}
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");
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
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)
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:
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)
// 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));
}
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);
}
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
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;
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;
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;
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;
-; 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
}
-; 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
}