mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Target/X86: Add explicit Win64 and System V/x86-64 calling conventions.
Summary: This patch adds explicit calling convention types for the Win64 and System V/x86-64 ABIs. This allows code to override the default, and use the Win64 convention on a target that wants to use SysV (and vice-versa). This is needed to implement the `ms_abi` and `sysv_abi` GNU attributes. Reviewers: CC: llvm-svn: 186144
This commit is contained in:
parent
8e9b7d6d74
commit
2b2075f834
@ -119,8 +119,17 @@ namespace CallingConv {
|
||||
SPIR_KERNEL = 76,
|
||||
|
||||
/// Intel_OCL_BI - Calling conventions for Intel OpenCL built-ins
|
||||
Intel_OCL_BI = 77
|
||||
Intel_OCL_BI = 77,
|
||||
|
||||
/// \brief The C convention as specified in the x86-64 supplement to the
|
||||
/// System V ABI, used on most non-Windows systems.
|
||||
X86_64_SysV = 78,
|
||||
|
||||
/// \brief The C convention as implemented on Windows/x86-64. This
|
||||
/// convention differs from the more common \c X86_64_SysV convention
|
||||
/// in a number of ways, most notably in that XMM registers used to pass
|
||||
/// arguments are shadowed by GPRs, and vice versa.
|
||||
X86_64_Win64 = 79
|
||||
};
|
||||
} // End CallingConv namespace
|
||||
|
||||
|
@ -556,6 +556,8 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(spir_kernel);
|
||||
KEYWORD(spir_func);
|
||||
KEYWORD(intel_ocl_bicc);
|
||||
KEYWORD(x86_64_sysvcc);
|
||||
KEYWORD(x86_64_win64cc);
|
||||
|
||||
KEYWORD(cc);
|
||||
KEYWORD(c);
|
||||
|
@ -1344,6 +1344,8 @@ bool LLParser::ParseOptionalVisibility(unsigned &Res) {
|
||||
/// ::= 'ptx_device'
|
||||
/// ::= 'spir_func'
|
||||
/// ::= 'spir_kernel'
|
||||
/// ::= 'x86_64_sysvcc'
|
||||
/// ::= 'x86_64_win64cc'
|
||||
/// ::= 'cc' UINT
|
||||
///
|
||||
bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) {
|
||||
@ -1364,6 +1366,8 @@ bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) {
|
||||
case lltok::kw_spir_kernel: CC = CallingConv::SPIR_KERNEL; break;
|
||||
case lltok::kw_spir_func: CC = CallingConv::SPIR_FUNC; break;
|
||||
case lltok::kw_intel_ocl_bicc: CC = CallingConv::Intel_OCL_BI; break;
|
||||
case lltok::kw_x86_64_sysvcc: CC = CallingConv::X86_64_SysV; break;
|
||||
case lltok::kw_x86_64_win64cc: CC = CallingConv::X86_64_Win64; break;
|
||||
case lltok::kw_cc: {
|
||||
unsigned ArbitraryCC;
|
||||
Lex.Lex();
|
||||
|
@ -84,12 +84,13 @@ namespace lltok {
|
||||
kw_c,
|
||||
|
||||
kw_cc, kw_ccc, kw_fastcc, kw_coldcc,
|
||||
kw_intel_ocl_bicc,
|
||||
kw_intel_ocl_bicc,
|
||||
kw_x86_stdcallcc, kw_x86_fastcallcc, kw_x86_thiscallcc,
|
||||
kw_arm_apcscc, kw_arm_aapcscc, kw_arm_aapcs_vfpcc,
|
||||
kw_msp430_intrcc,
|
||||
kw_ptx_kernel, kw_ptx_device,
|
||||
kw_spir_kernel, kw_spir_func,
|
||||
kw_x86_64_sysvcc, kw_x86_64_win64cc,
|
||||
|
||||
// Attributes:
|
||||
kw_attributes,
|
||||
|
@ -84,6 +84,8 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) {
|
||||
case CallingConv::MSP430_INTR: Out << "msp430_intrcc"; break;
|
||||
case CallingConv::PTX_Kernel: Out << "ptx_kernel"; break;
|
||||
case CallingConv::PTX_Device: Out << "ptx_device"; break;
|
||||
case CallingConv::X86_64_SysV: Out << "x86_64_sysvcc"; break;
|
||||
case CallingConv::X86_64_Win64: Out << "x86_64_win64cc"; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,11 @@ def RetCC_X86_32 : CallingConv<[
|
||||
def RetCC_X86_64 : CallingConv<[
|
||||
// HiPE uses RetCC_X86_64_HiPE
|
||||
CCIfCC<"CallingConv::HiPE", CCDelegateTo<RetCC_X86_64_HiPE>>,
|
||||
|
||||
// Handle explicit CC selection
|
||||
CCIfCC<"CallingConv::X86_64_Win64", CCDelegateTo<RetCC_X86_Win64_C>>,
|
||||
CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo<RetCC_X86_64_C>>,
|
||||
|
||||
// Mingw64 and native Win64 use Win64 CC
|
||||
CCIfSubtarget<"isTargetWin64()", CCDelegateTo<RetCC_X86_Win64_C>>,
|
||||
|
||||
@ -489,6 +494,8 @@ def CC_X86_32 : CallingConv<[
|
||||
def CC_X86_64 : CallingConv<[
|
||||
CCIfCC<"CallingConv::GHC", CCDelegateTo<CC_X86_64_GHC>>,
|
||||
CCIfCC<"CallingConv::HiPE", CCDelegateTo<CC_X86_64_HiPE>>,
|
||||
CCIfCC<"CallingConv::X86_64_Win64", CCDelegateTo<CC_X86_Win64_C>>,
|
||||
CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo<CC_X86_64_C>>,
|
||||
|
||||
// Mingw64 and native Win64 use Win64 CC
|
||||
CCIfSubtarget<"isTargetWin64()", CCDelegateTo<CC_X86_Win64_C>>,
|
||||
|
@ -712,10 +712,11 @@ bool X86FastISel::X86SelectRet(const Instruction *I) {
|
||||
CallingConv::ID CC = F.getCallingConv();
|
||||
if (CC != CallingConv::C &&
|
||||
CC != CallingConv::Fast &&
|
||||
CC != CallingConv::X86_FastCall)
|
||||
CC != CallingConv::X86_FastCall &&
|
||||
CC != CallingConv::X86_64_SysV)
|
||||
return false;
|
||||
|
||||
if (Subtarget->isTargetWin64())
|
||||
if (Subtarget->isCallingConvWin64(CC))
|
||||
return false;
|
||||
|
||||
// Don't handle popping bytes on return for now.
|
||||
@ -1705,9 +1706,6 @@ bool X86FastISel::FastLowerArguments() {
|
||||
if (!FuncInfo.CanLowerReturn)
|
||||
return false;
|
||||
|
||||
if (Subtarget->isTargetWin64())
|
||||
return false;
|
||||
|
||||
const Function *F = FuncInfo.Fn;
|
||||
if (F->isVarArg())
|
||||
return false;
|
||||
@ -1715,7 +1713,10 @@ bool X86FastISel::FastLowerArguments() {
|
||||
CallingConv::ID CC = F->getCallingConv();
|
||||
if (CC != CallingConv::C)
|
||||
return false;
|
||||
|
||||
|
||||
if (Subtarget->isCallingConvWin64(CC))
|
||||
return false;
|
||||
|
||||
if (!Subtarget->is64Bit())
|
||||
return false;
|
||||
|
||||
@ -1817,8 +1818,10 @@ bool X86FastISel::DoSelectCall(const Instruction *I, const char *MemIntName) {
|
||||
// Handle only C and fastcc calling conventions for now.
|
||||
ImmutableCallSite CS(CI);
|
||||
CallingConv::ID CC = CS.getCallingConv();
|
||||
bool isWin64 = Subtarget->isCallingConvWin64(CC);
|
||||
if (CC != CallingConv::C && CC != CallingConv::Fast &&
|
||||
CC != CallingConv::X86_FastCall)
|
||||
CC != CallingConv::X86_FastCall && CC != CallingConv::X86_64_Win64 &&
|
||||
CC != CallingConv::X86_64_SysV)
|
||||
return false;
|
||||
|
||||
// fastcc with -tailcallopt is intended to provide a guaranteed
|
||||
@ -1832,7 +1835,7 @@ bool X86FastISel::DoSelectCall(const Instruction *I, const char *MemIntName) {
|
||||
|
||||
// Don't know how to handle Win64 varargs yet. Nothing special needed for
|
||||
// x86-32. Special handling for x86-64 is implemented.
|
||||
if (isVarArg && Subtarget->isTargetWin64())
|
||||
if (isVarArg && isWin64)
|
||||
return false;
|
||||
|
||||
// Fast-isel doesn't know about callee-pop yet.
|
||||
@ -1962,7 +1965,7 @@ bool X86FastISel::DoSelectCall(const Instruction *I, const char *MemIntName) {
|
||||
I->getParent()->getContext());
|
||||
|
||||
// Allocate shadow area for Win64
|
||||
if (Subtarget->isTargetWin64())
|
||||
if (isWin64)
|
||||
CCInfo.AllocateStack(32, 8);
|
||||
|
||||
CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CC_X86);
|
||||
@ -2078,7 +2081,7 @@ bool X86FastISel::DoSelectCall(const Instruction *I, const char *MemIntName) {
|
||||
X86::EBX).addReg(Base);
|
||||
}
|
||||
|
||||
if (Subtarget->is64Bit() && isVarArg && !Subtarget->isTargetWin64()) {
|
||||
if (Subtarget->is64Bit() && isVarArg && !isWin64) {
|
||||
// Count the number of XMM registers allocated.
|
||||
static const uint16_t XMMArgRegs[] = {
|
||||
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
|
||||
@ -2147,7 +2150,7 @@ bool X86FastISel::DoSelectCall(const Instruction *I, const char *MemIntName) {
|
||||
if (Subtarget->isPICStyleGOT())
|
||||
MIB.addReg(X86::EBX, RegState::Implicit);
|
||||
|
||||
if (Subtarget->is64Bit() && isVarArg && !Subtarget->isTargetWin64())
|
||||
if (Subtarget->is64Bit() && isVarArg && !isWin64)
|
||||
MIB.addReg(X86::AL, RegState::Implicit);
|
||||
|
||||
// Add implicit physical register uses to the call.
|
||||
|
@ -1880,13 +1880,19 @@ static bool IsTailCallConvention(CallingConv::ID CC) {
|
||||
CC == CallingConv::HiPE);
|
||||
}
|
||||
|
||||
/// \brief Return true if the calling convention is a C calling convention.
|
||||
static bool IsCCallConvention(CallingConv::ID CC) {
|
||||
return (CC == CallingConv::C || CC == CallingConv::X86_64_Win64 ||
|
||||
CC == CallingConv::X86_64_SysV);
|
||||
}
|
||||
|
||||
bool X86TargetLowering::mayBeEmittedAsTailCall(CallInst *CI) const {
|
||||
if (!CI->isTailCall() || getTargetMachine().Options.DisableTailCalls)
|
||||
return false;
|
||||
|
||||
CallSite CS(CI);
|
||||
CallingConv::ID CalleeCC = CS.getCallingConv();
|
||||
if (!IsTailCallConvention(CalleeCC) && CalleeCC != CallingConv::C)
|
||||
if (!IsTailCallConvention(CalleeCC) && !IsCCallConvention(CalleeCC))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -1961,7 +1967,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
bool Is64Bit = Subtarget->is64Bit();
|
||||
bool IsWindows = Subtarget->isTargetWindows();
|
||||
bool IsWin64 = Subtarget->isTargetWin64();
|
||||
bool IsWin64 = Subtarget->isCallingConvWin64(CallConv);
|
||||
|
||||
assert(!(isVarArg && IsTailCallConvention(CallConv)) &&
|
||||
"Var args not supported with calling convention fastcc, ghc or hipe");
|
||||
@ -1972,9 +1978,8 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
ArgLocs, *DAG.getContext());
|
||||
|
||||
// Allocate shadow area for Win64
|
||||
if (IsWin64) {
|
||||
if (IsWin64)
|
||||
CCInfo.AllocateStack(32, 8);
|
||||
}
|
||||
|
||||
CCInfo.AnalyzeFormalArguments(Ins, CC_X86);
|
||||
|
||||
@ -2287,7 +2292,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
bool Is64Bit = Subtarget->is64Bit();
|
||||
bool IsWin64 = Subtarget->isTargetWin64();
|
||||
bool IsWin64 = Subtarget->isCallingConvWin64(CallConv);
|
||||
bool IsWindows = Subtarget->isTargetWindows();
|
||||
StructReturnType SR = callIsStructReturn(Outs);
|
||||
bool IsSibcall = false;
|
||||
@ -2320,9 +2325,8 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
ArgLocs, *DAG.getContext());
|
||||
|
||||
// Allocate shadow area for Win64
|
||||
if (IsWin64) {
|
||||
if (IsWin64)
|
||||
CCInfo.AllocateStack(32, 8);
|
||||
}
|
||||
|
||||
CCInfo.AnalyzeCallOperands(Outs, CC_X86);
|
||||
|
||||
@ -2833,13 +2837,12 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
|
||||
const SmallVectorImpl<SDValue> &OutVals,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
SelectionDAG &DAG) const {
|
||||
if (!IsTailCallConvention(CalleeCC) &&
|
||||
CalleeCC != CallingConv::C)
|
||||
if (!IsTailCallConvention(CalleeCC) && !IsCCallConvention(CalleeCC))
|
||||
return false;
|
||||
|
||||
// If -tailcallopt is specified, make fastcc functions tail-callable.
|
||||
const MachineFunction &MF = DAG.getMachineFunction();
|
||||
const Function *CallerF = DAG.getMachineFunction().getFunction();
|
||||
const Function *CallerF = MF.getFunction();
|
||||
|
||||
// If the function return type is x86_fp80 and the callee return type is not,
|
||||
// then the FP_EXTEND of the call result is not a nop. It's not safe to
|
||||
@ -2849,6 +2852,8 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
|
||||
|
||||
CallingConv::ID CallerCC = CallerF->getCallingConv();
|
||||
bool CCMatch = CallerCC == CalleeCC;
|
||||
bool IsCalleeWin64 = Subtarget->isCallingConvWin64(CalleeCC);
|
||||
bool IsCallerWin64 = Subtarget->isCallingConvWin64(CallerCC);
|
||||
|
||||
if (getTargetMachine().Options.GuaranteedTailCallOpt) {
|
||||
if (IsTailCallConvention(CalleeCC) && CCMatch)
|
||||
@ -2882,7 +2887,7 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
|
||||
|
||||
// Optimizing for varargs on Win64 is unlikely to be safe without
|
||||
// additional testing.
|
||||
if (Subtarget->isTargetWin64())
|
||||
if (IsCalleeWin64 || IsCallerWin64)
|
||||
return false;
|
||||
|
||||
SmallVector<CCValAssign, 16> ArgLocs;
|
||||
@ -2957,9 +2962,8 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
|
||||
getTargetMachine(), ArgLocs, *DAG.getContext());
|
||||
|
||||
// Allocate shadow area for Win64
|
||||
if (Subtarget->isTargetWin64()) {
|
||||
if (IsCalleeWin64)
|
||||
CCInfo.AllocateStack(32, 8);
|
||||
}
|
||||
|
||||
CCInfo.AnalyzeCallOperands(Outs, CC_X86);
|
||||
if (CCInfo.getNextStackOffset()) {
|
||||
|
@ -338,7 +338,13 @@ public:
|
||||
}
|
||||
bool isPICStyleStubAny() const {
|
||||
return PICStyle == PICStyles::StubDynamicNoPIC ||
|
||||
PICStyle == PICStyles::StubPIC; }
|
||||
PICStyle == PICStyles::StubPIC;
|
||||
}
|
||||
|
||||
bool isCallingConvWin64(CallingConv::ID CC) const {
|
||||
return (isTargetWin64() && CC != CallingConv::X86_64_SysV) ||
|
||||
CC == CallingConv::X86_64_Win64;
|
||||
}
|
||||
|
||||
/// ClassifyGlobalReference - Classify a global variable reference for the
|
||||
/// current subtarget according to how we should reference it in a non-pcrel
|
||||
|
@ -1,4 +1,5 @@
|
||||
; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s
|
||||
; RUN: llc < %s -mtriple=x86_64-pc-linux | FileCheck %s -check-prefix=LINUX
|
||||
|
||||
; Verify that the 5th and 6th parameters are coming from the correct location
|
||||
; on the stack.
|
||||
@ -6,6 +7,30 @@ define i32 @f6(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6) nounwind re
|
||||
entry:
|
||||
; CHECK: movl 48(%rsp), %eax
|
||||
; CHECK: addl 40(%rsp), %eax
|
||||
; LINUX: addl %r9d, %r8d
|
||||
; LINUX: movl %r8d, %eax
|
||||
%add = add nsw i32 %p6, %p5
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
define x86_64_win64cc i32 @f7(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6) nounwind readnone optsize {
|
||||
entry:
|
||||
; CHECK: movl 48(%rsp), %eax
|
||||
; CHECK: addl 40(%rsp), %eax
|
||||
; LINUX: movl 48(%rsp), %eax
|
||||
; LINUX: addl 40(%rsp), %eax
|
||||
%add = add nsw i32 %p6, %p5
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
; Verify that even though we're compiling for Windows, parameters behave as
|
||||
; on other platforms here (note the x86_64_sysvcc calling convention).
|
||||
define x86_64_sysvcc i32 @f8(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6) nounwind readnone optsize {
|
||||
entry:
|
||||
; CHECK: addl %r9d, %r8d
|
||||
; CHECK: movl %r8d, %eax
|
||||
; LINUX: addl %r9d, %r8d
|
||||
; LINUX: movl %r8d, %eax
|
||||
%add = add nsw i32 %p6, %p5
|
||||
ret i32 %add
|
||||
}
|
||||
|
@ -45,3 +45,16 @@ entry:
|
||||
%array128 = alloca [128 x i8], align 16 ; <[128 x i8]*> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Make sure we don't call __chkstk or __alloca on non-Windows even if the
|
||||
; caller has the Win64 calling convention.
|
||||
define x86_64_win64cc i32 @main4k_win64() nounwind {
|
||||
entry:
|
||||
; WIN_X32: calll __chkstk
|
||||
; WIN_X64: callq __chkstk
|
||||
; MINGW_X32: calll __alloca
|
||||
; MINGW_X64: callq ___chkstk
|
||||
; LINUX-NOT: call __chkstk
|
||||
%array4096 = alloca [4096 x i8], align 16 ; <[4096 x i8]*> [#uses=0]
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -50,12 +50,13 @@ syn keyword llvmKeyword msp430_intrcc naked nest noalias nocapture
|
||||
syn keyword llvmKeyword noimplicitfloat noinline nonlazybind noredzone noreturn
|
||||
syn keyword llvmKeyword nounwind optsize personality private protected
|
||||
syn keyword llvmKeyword ptx_device ptx_kernel readnone readonly release
|
||||
syn keyword llvmKeyword returns_twice section seq_cst sideeffect signext
|
||||
syn keyword llvmKeyword singlethread spir_func spir_kernel sret ssp sspreq
|
||||
syn keyword llvmKeyword sspstrong tail target thread_local to triple
|
||||
syn keyword llvmKeyword unnamed_addr unordered uwtable volatile weak weak_odr
|
||||
syn keyword llvmKeyword x86_fastcallcc x86_stdcallcc x86_thiscallcc zeroext
|
||||
syn keyword llvmKeyword sanitize_thread sanitize_memory
|
||||
syn keyword llvmKeyword returns_twice sanitize_thread sanitize_memory
|
||||
syn keyword llvmKeyword section seq_cst sideeffect signext singlethread
|
||||
syn keyword llvmKeyword spir_func spir_kernel sret ssp sspreq sspstrong
|
||||
syn keyword llvmKeyword tail target thread_local to triple unnamed_addr
|
||||
syn keyword llvmKeyword unordered uwtable volatile weak weak_odr
|
||||
syn keyword llvmKeyword x86_fastcallcc x86_stdcallcc x86_thiscallcc x86_64_sysvcc
|
||||
syn keyword llvmKeyword x86_64_win64cc zeroext
|
||||
|
||||
" Obsolete keywords.
|
||||
syn keyword llvmError getresult begin end
|
||||
|
Loading…
x
Reference in New Issue
Block a user