Index: cfe/trunk/include/clang/Basic/LangOptions.h =================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.h +++ cfe/trunk/include/clang/Basic/LangOptions.h @@ -65,6 +65,14 @@ PPTMK_FullGeneralityVirtualInheritance }; + enum DefaultCallingConvention { + DCC_None, + DCC_CDecl, + DCC_FastCall, + DCC_StdCall, + DCC_VectorCall + }; + enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off }; enum MSVCMajorVersion { Index: cfe/trunk/include/clang/Basic/LangOptions.def =================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.def +++ cfe/trunk/include/clang/Basic/LangOptions.def @@ -172,6 +172,7 @@ 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(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") Index: cfe/trunk/include/clang/Driver/CC1Options.td =================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td +++ cfe/trunk/include/clang/Driver/CC1Options.td @@ -610,6 +610,8 @@ 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">, Index: cfe/trunk/include/clang/Driver/CLCompatOptions.td =================================================================== --- cfe/trunk/include/clang/Driver/CLCompatOptions.td +++ cfe/trunk/include/clang/Driver/CLCompatOptions.td @@ -268,6 +268,15 @@ def _SLASH_Fp : CLJoined<"Fp">, HelpText<"Set pch filename (with /Yc and /Yu)">, MetaVarName<"">; +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_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_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">; Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -8618,8 +8618,25 @@ 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); } Index: cfe/trunk/lib/Driver/Tools.cpp =================================================================== --- cfe/trunk/lib/Driver/Tools.cpp +++ cfe/trunk/lib/Driver/Tools.cpp @@ -3964,7 +3964,7 @@ } 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 @@ 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); Index: cfe/trunk/lib/Frontend/CompilerInvocation.cpp =================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp @@ -1826,7 +1826,6 @@ 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 @@ 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( + 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 = Index: cfe/trunk/lib/Sema/SemaDeclAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp @@ -3901,11 +3901,12 @@ // 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); Index: cfe/trunk/test/CodeGenCXX/default_calling_conv.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/default_calling_conv.cpp +++ cfe/trunk/test/CodeGenCXX/default_calling_conv.cpp @@ -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(); +}