diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -198,7 +198,8 @@ FTP); } -static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) { +static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, + bool IsWindows) { // Set the appropriate calling convention for the Function. if (D->hasAttr()) return CC_X86StdCall; @@ -3818,6 +3819,24 @@ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None); } +// Check if the call is going to use the inalloca convention. This needs to +// agree with CGFunctionInfo::usesInAlloca. The CGFunctionInfo is arranged +// later, so we can't check it directly. +static bool hasInAllocaArgs(CodeGenModule &CGM, CallingConv ExplicitCC, + ArrayRef ArgTypes) { + // The Swift calling convention doesn't go through the target-specific + // argument classification, so it never uses inalloca. + // TODO: Consider limiting inalloca use to only calling conventions supported + // by MSVC. + if (ExplicitCC == CC_Swift) + return false; + if (!CGM.getTarget().getCXXABI().isMicrosoft()) + return false; + return llvm::any_of(ArgTypes, [&](QualType Ty) { + return isInAllocaArgument(CGM.getCXXABI(), Ty); + }); +} + #ifndef NDEBUG // Determine whether the given argument is an Objective-C method // that may have type parameters in its signature. @@ -3845,17 +3864,27 @@ assert((ParamsToSkip == 0 || Prototype.P) && "Can't skip parameters if type info is not provided"); - // First, use the argument types that the type info knows about + // This variable only captures *explicitly* written conventions, not those + // applied by default via command line flags or target defaults, such as + // thiscall, aapcs, stdcall via -mrtd, etc. Computing that correctly would + // require knowing if this is a C++ instance method or being able to see + // unprototyped FunctionTypes. + CallingConv ExplicitCC = CC_C; + + // First, if a prototype was provided, use those argument types. bool IsVariadic = false; if (Prototype.P) { const auto *MD = Prototype.P.dyn_cast(); if (MD) { IsVariadic = MD->isVariadic(); + ExplicitCC = getCallingConventionForDecl( + MD, CGM.getTarget().getTriple().isOSWindows()); ArgTypes.assign(MD->param_type_begin() + ParamsToSkip, MD->param_type_end()); } else { const auto *FPT = Prototype.P.get(); IsVariadic = FPT->isVariadic(); + ExplicitCC = FPT->getExtInfo().getCC(); ArgTypes.assign(FPT->param_type_begin() + ParamsToSkip, FPT->param_type_end()); } @@ -3923,15 +3952,10 @@ }; // Insert a stack save if we're going to need any inalloca args. - bool HasInAllocaArgs = false; - if (CGM.getTarget().getCXXABI().isMicrosoft()) { - for (ArrayRef::iterator I = ArgTypes.begin(), E = ArgTypes.end(); - I != E && !HasInAllocaArgs; ++I) - HasInAllocaArgs = isInAllocaArgument(CGM.getCXXABI(), *I); - if (HasInAllocaArgs) { - assert(getTarget().getTriple().getArch() == llvm::Triple::x86); - Args.allocateArgumentMemory(*this); - } + if (hasInAllocaArgs(CGM, ExplicitCC, ArgTypes)) { + assert(getTarget().getTriple().getArch() == llvm::Triple::x86 && + "inalloca only supported on x86"); + Args.allocateArgumentMemory(*this); } // Evaluate each argument in the appropriate order. diff --git a/clang/test/CodeGenCXX/windows-x86-swiftcall.cpp b/clang/test/CodeGenCXX/windows-x86-swiftcall.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/windows-x86-swiftcall.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-windows -emit-llvm -target-cpu core2 -o - %s | FileCheck %s + +#define SWIFTCALL __attribute__((swiftcall)) +#define OUT __attribute__((swift_indirect_result)) +#define ERROR __attribute__((swift_error_result)) +#define CONTEXT __attribute__((swift_context)) + +/*****************************************************************************/ +/****************************** PARAMETER ABIS *******************************/ +/*****************************************************************************/ + +// Swift doesn't use inalloca like windows x86 normally does. +struct NonTrivial { + NonTrivial(); + NonTrivial(const NonTrivial &); + int o; +}; + +SWIFTCALL int receiveNonTrivial(NonTrivial o) { return o.o; } + +// CHECK-LABEL: define dso_local swiftcc i32 @"?receiveNonTrivial@@YSHUNonTrivial@@@Z"(%struct.NonTrivial* %o) + +int passNonTrivial() { + return receiveNonTrivial({}); +} + +// CHECK-LABEL: define dso_local i32 @"?passNonTrivial@@YAHXZ"() +// CHECK-NOT: stacksave +// CHECK: call swiftcc i32 @"?receiveNonTrivial@@YSHUNonTrivial@@@Z"(%struct.NonTrivial* %{{.*}})