forked from OSchip/llvm-project
Support for MSVS default calling convention options (/Gd, /Gz, /Gv,
/Gr), by Alexander Makarov Patch for bug #27711 Differential Revision: http://reviews.llvm.org/D20171 llvm-svn: 269891
This commit is contained in:
parent
ff6d195c2d
commit
a7547183ec
|
@ -172,6 +172,7 @@ BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control")
|
|||
LANGOPT(CharIsSigned , 1, 1, "signed char")
|
||||
LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t")
|
||||
ENUM_LANGOPT(MSPointerToMemberRepresentationMethod, PragmaMSPointersToMembersKind, 2, PPTMK_BestCase, "member-pointer representation method")
|
||||
ENUM_LANGOPT(DefaultCallingConv, DefaultCallingConvention, 3, DCC_None, "default calling convention")
|
||||
|
||||
LANGOPT(ShortEnums , 1, 0, "short enum types")
|
||||
|
||||
|
@ -216,7 +217,6 @@ LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in l
|
|||
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
|
||||
ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
|
||||
|
||||
LANGOPT(MRTD , 1, 0, "-mrtd calling convention")
|
||||
BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing")
|
||||
LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime")
|
||||
|
||||
|
|
|
@ -65,6 +65,14 @@ public:
|
|||
PPTMK_FullGeneralityVirtualInheritance
|
||||
};
|
||||
|
||||
enum DefaultCallingConvention {
|
||||
DCC_None,
|
||||
DCC_CDecl,
|
||||
DCC_FastCall,
|
||||
DCC_StdCall,
|
||||
DCC_VectorCall
|
||||
};
|
||||
|
||||
enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off };
|
||||
|
||||
enum MSVCMajorVersion {
|
||||
|
|
|
@ -610,6 +610,8 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and
|
|||
HelpText<"Use the native __fp16 type for arguments and returns (and skip ABI-specific lowering)">;
|
||||
def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">,
|
||||
HelpText<"Allow function arguments and returns of type half">;
|
||||
def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">,
|
||||
HelpText<"Set default MS calling convention">;
|
||||
|
||||
// C++ TSes.
|
||||
def fcoroutines : Flag<["-"], "fcoroutines">,
|
||||
|
|
|
@ -268,6 +268,15 @@ def _SLASH_Y_ : CLFlag<"Y-">,
|
|||
def _SLASH_Fp : CLJoined<"Fp">,
|
||||
HelpText<"Set pch filename (with /Yc and /Yu)">, MetaVarName<"<filename>">;
|
||||
|
||||
def _SLASH_Gd : CLFlag<"Gd">,
|
||||
HelpText<"Set __cdecl as a default calling convention">;
|
||||
def _SLASH_Gr : CLFlag<"Gr">,
|
||||
HelpText<"Set __fastcall as a default calling convention">;
|
||||
def _SLASH_Gz : CLFlag<"Gz">,
|
||||
HelpText<"Set __stdcall as a default calling convention">;
|
||||
def _SLASH_Gv : CLFlag<"Gv">,
|
||||
HelpText<"Set __vectorcall as a default calling convention">;
|
||||
|
||||
// Ignored:
|
||||
|
||||
def _SLASH_analyze_ : CLIgnoredFlag<"analyze-">;
|
||||
|
@ -279,7 +288,6 @@ def _SLASH_errorReport : CLIgnoredJoined<"errorReport">;
|
|||
def _SLASH_Fd : CLIgnoredJoined<"Fd">;
|
||||
def _SLASH_FC : CLIgnoredFlag<"FC">;
|
||||
def _SLASH_FS : CLIgnoredFlag<"FS">, HelpText<"Force synchronous PDB writes">;
|
||||
def _SLASH_Gd : CLIgnoredFlag<"Gd">;
|
||||
def _SLASH_GF : CLIgnoredFlag<"GF">;
|
||||
def _SLASH_GS_ : CLIgnoredFlag<"GS-">;
|
||||
def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">;
|
||||
|
@ -324,12 +332,9 @@ def _SLASH_GL : CLFlag<"GL">;
|
|||
def _SLASH_GL_ : CLFlag<"GL-">;
|
||||
def _SLASH_Gm : CLFlag<"Gm">;
|
||||
def _SLASH_Gm_ : CLFlag<"Gm-">;
|
||||
def _SLASH_Gr : CLFlag<"Gr">;
|
||||
def _SLASH_GS : CLFlag<"GS">;
|
||||
def _SLASH_GT : CLFlag<"GT">;
|
||||
def _SLASH_Guard : CLJoined<"guard:">;
|
||||
def _SLASH_Gv : CLFlag<"Gv">;
|
||||
def _SLASH_Gz : CLFlag<"Gz">;
|
||||
def _SLASH_GZ : CLFlag<"GZ">;
|
||||
def _SLASH_H : CLFlag<"H">;
|
||||
def _SLASH_homeparams : CLFlag<"homeparams">;
|
||||
|
|
|
@ -8618,8 +8618,25 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
|
|||
if (IsCXXMethod)
|
||||
return ABI->getDefaultMethodCallConv(IsVariadic);
|
||||
|
||||
if (LangOpts.MRTD && !IsVariadic) return CC_X86StdCall;
|
||||
|
||||
switch (LangOpts.getDefaultCallingConv()) {
|
||||
case LangOptions::DCC_None:
|
||||
break;
|
||||
case LangOptions::DCC_CDecl:
|
||||
return CC_C;
|
||||
case LangOptions::DCC_FastCall:
|
||||
if (getTargetInfo().hasFeature("sse2"))
|
||||
return CC_X86FastCall;
|
||||
break;
|
||||
case LangOptions::DCC_StdCall:
|
||||
if (!IsVariadic)
|
||||
return CC_X86StdCall;
|
||||
break;
|
||||
case LangOptions::DCC_VectorCall:
|
||||
// __vectorcall cannot be applied to variadic functions.
|
||||
if (!IsVariadic)
|
||||
return CC_X86VectorCall;
|
||||
break;
|
||||
}
|
||||
return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown);
|
||||
}
|
||||
|
||||
|
|
|
@ -3964,7 +3964,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
}
|
||||
|
||||
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
|
||||
CmdArgs.push_back("-mrtd");
|
||||
CmdArgs.push_back("-fdefault-calling-conv=stdcall");
|
||||
|
||||
if (shouldUseFramePointer(Args, getToolChain().getTriple()))
|
||||
CmdArgs.push_back("-mdisable-fp-elim");
|
||||
|
@ -6160,6 +6160,15 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
|
|||
CmdArgs.push_back("-fms-memptr-rep=virtual");
|
||||
}
|
||||
|
||||
if (Args.getLastArg(options::OPT__SLASH_Gd))
|
||||
CmdArgs.push_back("-fdefault-calling-conv=cdecl");
|
||||
else if (Args.getLastArg(options::OPT__SLASH_Gr))
|
||||
CmdArgs.push_back("-fdefault-calling-conv=fastcall");
|
||||
else if (Args.getLastArg(options::OPT__SLASH_Gz))
|
||||
CmdArgs.push_back("-fdefault-calling-conv=stdcall");
|
||||
else if (Args.getLastArg(options::OPT__SLASH_Gv))
|
||||
CmdArgs.push_back("-fdefault-calling-conv=vectorcall");
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ))
|
||||
A->render(Args, CmdArgs);
|
||||
|
||||
|
|
|
@ -1826,7 +1826,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
|
||||
Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant);
|
||||
Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math);
|
||||
Opts.MRTD = Args.hasArg(OPT_mrtd);
|
||||
Opts.HexagonQdsp6Compat = Args.hasArg(OPT_mqdsp6_compat);
|
||||
Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map);
|
||||
Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype);
|
||||
|
@ -1903,6 +1902,49 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
Opts.setMSPointerToMemberRepresentationMethod(InheritanceModel);
|
||||
}
|
||||
|
||||
// Check for MS default calling conventions being specified.
|
||||
if (Arg *A = Args.getLastArg(OPT_fdefault_calling_conv_EQ)) {
|
||||
LangOptions::DefaultCallingConvention DefaultCC =
|
||||
llvm::StringSwitch<LangOptions::DefaultCallingConvention>(
|
||||
A->getValue())
|
||||
.Case("cdecl", LangOptions::DCC_CDecl)
|
||||
.Case("fastcall", LangOptions::DCC_FastCall)
|
||||
.Case("stdcall", LangOptions::DCC_StdCall)
|
||||
.Case("vectorcall", LangOptions::DCC_VectorCall)
|
||||
.Default(LangOptions::DCC_None);
|
||||
if (DefaultCC == LangOptions::DCC_None)
|
||||
Diags.Report(diag::err_drv_invalid_value)
|
||||
<< "-fdefault-calling-conv=" << A->getValue();
|
||||
|
||||
llvm::Triple T(TargetOpts.Triple);
|
||||
llvm::Triple::ArchType Arch = T.getArch();
|
||||
bool emitError = (DefaultCC == LangOptions::DCC_FastCall ||
|
||||
DefaultCC == LangOptions::DCC_StdCall) &&
|
||||
Arch != llvm::Triple::x86;
|
||||
emitError |= DefaultCC == LangOptions::DCC_VectorCall &&
|
||||
!(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64);
|
||||
if (emitError)
|
||||
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getSpelling() << T.getTriple();
|
||||
else
|
||||
Opts.setDefaultCallingConv(DefaultCC);
|
||||
}
|
||||
|
||||
// -mrtd option
|
||||
if (Arg *A = Args.getLastArg(OPT_mrtd)) {
|
||||
if (Opts.getDefaultCallingConv() != LangOptions::DCC_None)
|
||||
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getSpelling() << "-fdefault-calling-conv";
|
||||
else {
|
||||
llvm::Triple T(TargetOpts.Triple);
|
||||
if (T.getArch() != llvm::Triple::x86)
|
||||
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getSpelling() << T.getTriple();
|
||||
else
|
||||
Opts.setDefaultCallingConv(LangOptions::DCC_StdCall);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if -fopenmp is specified.
|
||||
Opts.OpenMP = Args.hasArg(options::OPT_fopenmp);
|
||||
Opts.OpenMPUseTLS =
|
||||
|
|
|
@ -3901,11 +3901,12 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
|
|||
|
||||
// This convention is not valid for the target. Use the default function or
|
||||
// method calling convention.
|
||||
TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown;
|
||||
if (FD)
|
||||
MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member :
|
||||
TargetInfo::CCMT_NonMember;
|
||||
CC = TI.getDefaultCallingConv(MT);
|
||||
bool IsCXXMethod = false, IsVariadic = false;
|
||||
if (FD) {
|
||||
IsCXXMethod = FD->isCXXInstanceMember();
|
||||
IsVariadic = FD->isVariadic();
|
||||
}
|
||||
CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
|
||||
}
|
||||
|
||||
attr.setProcessingCache((unsigned) CC);
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fdefault-calling-conv=cdecl -emit-llvm -o - %s | FileCheck %s --check-prefix=CDECL --check-prefix=ALL
|
||||
// RUN: %clang_cc1 -triple i786-unknown-linux-gnu -target-feature +sse4.2 -fdefault-calling-conv=fastcall -emit-llvm -o - %s | FileCheck %s --check-prefix=FASTCALL --check-prefix=ALL
|
||||
// RUN: %clang_cc1 -triple i486-unknown-linux-gnu -fdefault-calling-conv=stdcall -emit-llvm -o - %s | FileCheck %s --check-prefix=STDCALL --check-prefix=ALL
|
||||
// RUN: %clang_cc1 -triple i486-unknown-linux-gnu -mrtd -emit-llvm -o - %s | FileCheck %s --check-prefix=STDCALL --check-prefix=ALL
|
||||
// RUN: %clang_cc1 -triple i986-unknown-linux-gnu -fdefault-calling-conv=vectorcall -emit-llvm -o - %s | FileCheck %s --check-prefix=VECTORCALL --check-prefix=ALL
|
||||
|
||||
// CDECL: define void @_Z5test1v
|
||||
// FASTCALL: define x86_fastcallcc void @_Z5test1v
|
||||
// STDCALL: define x86_stdcallcc void @_Z5test1v
|
||||
// VECTORCALL: define x86_vectorcallcc void @_Z5test1v
|
||||
void test1() {}
|
||||
|
||||
// ALL: define void @_Z5test2v
|
||||
void __attribute__((cdecl)) test2() {}
|
||||
|
||||
// ALL: define x86_fastcallcc void @_Z5test3v
|
||||
void __attribute__((fastcall)) test3() {}
|
||||
|
||||
// ALL: define x86_stdcallcc void @_Z5test4v
|
||||
void __attribute__((stdcall)) test4() {}
|
||||
|
||||
// ALL: define x86_vectorcallcc void @_Z5test5v
|
||||
void __attribute__((vectorcall)) test5() {}
|
||||
|
||||
// ALL: define linkonce_odr void @_ZN1A11test_memberEv
|
||||
class A {
|
||||
public:
|
||||
void test_member() {}
|
||||
};
|
||||
|
||||
void test() {
|
||||
A a;
|
||||
a.test_member();
|
||||
}
|
Loading…
Reference in New Issue