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:
Alexey Bataev 2016-05-18 09:06:38 +00:00
parent ff6d195c2d
commit a7547183ec
9 changed files with 132 additions and 14 deletions

View File

@ -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")

View File

@ -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 {

View File

@ -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">,

View File

@ -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">;

View File

@ -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);
}

View File

@ -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);

View File

@ -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 =

View File

@ -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);

View File

@ -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();
}