/// The clang::CallingConv that this was originally created with.
unsigned ASTCallingConvention : 8;
+ /// Whether this is an instance method.
+ unsigned InstanceMethod : 1;
+
/// Whether this function is noreturn.
unsigned NoReturn : 1;
public:
static CGFunctionInfo *create(unsigned llvmCC,
+ bool InstanceMethod,
const FunctionType::ExtInfo &extInfo,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
bool isVariadic() const { return Required.allowsOptionalArgs(); }
RequiredArgs getRequiredArgs() const { return Required; }
+ bool isInstanceMethod() const { return InstanceMethod; }
+
bool isNoReturn() const { return NoReturn; }
/// In ARC, whether this function retains its return value. This
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getASTCallingConvention());
+ ID.AddBoolean(InstanceMethod);
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
it->type.Profile(ID);
}
static void Profile(llvm::FoldingSetNodeID &ID,
+ bool InstanceMethod,
const FunctionType::ExtInfo &info,
RequiredArgs required,
CanQualType resultType,
ArrayRef<CanQualType> argTypes) {
ID.AddInteger(info.getCC());
+ ID.AddBoolean(InstanceMethod);
ID.AddBoolean(info.getNoReturn());
ID.AddBoolean(info.getProducesResult());
ID.AddBoolean(info.getHasRegParm());
CanQual<FunctionNoProtoType> Ty);
const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
- const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
+ const CGFunctionInfo &arrangeFreeFunctionCall(CanQualType returnType,
llvm::ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args);
// Create the function declaration.
const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType();
- const CGFunctionInfo &fnInfo = CGM.getTypes().arrangeFunctionDeclaration(
+ const CGFunctionInfo &fnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
fnType->getReturnType(), args, fnType->getExtInfo(),
fnType->isVariadic());
if (CGM.ReturnTypeUsesSRet(fnInfo))
ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
args.push_back(&srcDecl);
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
// FIXME: it would be nice if these were mergeable with things with
// identical semantics.
ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
args.push_back(&srcDecl);
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
args.push_back(&src);
- const CGFunctionInfo &FI =
- CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGF.CGM.getTypes().arrangeFreeFunctionDeclaration(
+ R, args, FunctionType::ExtInfo(), /*variadic=*/false);
CodeGenTypes &Types = CGF.CGM.getTypes();
llvm::FunctionType *LTy = Types.GetFunctionType(FI);
ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
args.push_back(&src);
- const CGFunctionInfo &FI =
- CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGF.CGM.getTypes().arrangeFreeFunctionDeclaration(
+ R, args, FunctionType::ExtInfo(), /*variadic=*/false);
CodeGenTypes &Types = CGF.CGM.getTypes();
llvm::FunctionType *LTy = Types.GetFunctionType(FI);
// When translating an unprototyped function type, always use a
// variadic type.
return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(),
- None, FTNP->getExtInfo(), RequiredArgs(0));
+ false, None, FTNP->getExtInfo(),
+ RequiredArgs(0));
}
/// Arrange the LLVM function layout for a value of the given function
/// type, on top of any implicit parameters already stored. Use the
/// given ExtInfo instead of the ExtInfo from the function type.
static const CGFunctionInfo &arrangeLLVMFunctionInfo(CodeGenTypes &CGT,
+ bool IsInstanceMethod,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP,
FunctionType::ExtInfo extInfo) {
for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i)
prefix.push_back(FTP->getParamType(i));
CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
- return CGT.arrangeLLVMFunctionInfo(resultType, prefix, extInfo, required);
+ return CGT.arrangeLLVMFunctionInfo(resultType, IsInstanceMethod, prefix,
+ extInfo, required);
}
/// Arrange the argument and result information for a free function (i.e.
static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
- return arrangeLLVMFunctionInfo(CGT, prefix, FTP, FTP->getExtInfo());
+ return arrangeLLVMFunctionInfo(CGT, false, prefix, FTP, FTP->getExtInfo());
}
/// Arrange the argument and result information for a free function (i.e.
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
+ return arrangeLLVMFunctionInfo(CGT, true, prefix, FTP, extInfo);
}
/// Arrange the argument and result information for a value of the
(D->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All);
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
+ return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required);
}
/// Arrange the argument and result information for a declaration,
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
+ return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo,
RequiredArgs::All);
}
// non-variadic type.
if (isa<FunctionNoProtoType>(FTy)) {
CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
- return arrangeLLVMFunctionInfo(noProto->getReturnType(), None,
+ return arrangeLLVMFunctionInfo(noProto->getReturnType(), false, None,
noProto->getExtInfo(), RequiredArgs::All);
}
RequiredArgs required =
(MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All);
- return arrangeLLVMFunctionInfo(GetReturnType(MD->getReturnType()), argTys,
- einfo, required);
+ return arrangeLLVMFunctionInfo(GetReturnType(MD->getReturnType()), false,
+ argTys, einfo, required);
}
const CGFunctionInfo &
for (CallArgList::const_iterator i = args.begin(), e = args.end();
i != e; ++i)
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
- return arrangeLLVMFunctionInfo(GetReturnType(resultType), argTypes, info,
- required);
+ return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes,
+ info, required);
}
/// Arrange a call to a C++ method, passing the given arguments.
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
FunctionType::ExtInfo info = FPT->getExtInfo();
- return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), argTypes,
- info, required);
+ return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), true,
+ argTypes, info, required);
}
-const CGFunctionInfo &
-CodeGenTypes::arrangeFunctionDeclaration(QualType resultType,
- const FunctionArgList &args,
- const FunctionType::ExtInfo &info,
- bool isVariadic) {
+const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration(
+ QualType resultType, const FunctionArgList &args,
+ const FunctionType::ExtInfo &info, bool isVariadic) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> argTypes;
for (FunctionArgList::const_iterator i = args.begin(), e = args.end();
RequiredArgs required =
(isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All);
- return arrangeLLVMFunctionInfo(GetReturnType(resultType), argTypes, info,
+ return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, info,
required);
}
const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
- return arrangeLLVMFunctionInfo(getContext().VoidTy, None,
+ return arrangeLLVMFunctionInfo(getContext().VoidTy, false, None,
FunctionType::ExtInfo(), RequiredArgs::All);
}
/// above functions ultimately defer to.
const CGFunctionInfo &
CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
+ bool IsInstanceMethod,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs required) {
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, info, required, resultType, argTypes);
+ CGFunctionInfo::Profile(ID, IsInstanceMethod, info, required, resultType,
+ argTypes);
void *insertPos = 0;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
return *FI;
// Construct the function info. We co-allocate the ArgInfos.
- FI = CGFunctionInfo::create(CC, info, resultType, argTypes, required);
+ FI = CGFunctionInfo::create(CC, IsInstanceMethod, info, resultType, argTypes,
+ required);
FunctionInfos.InsertNode(FI, insertPos);
bool inserted = FunctionsBeingProcessed.insert(FI); (void)inserted;
}
CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
+ bool IsInstanceMethod,
const FunctionType::ExtInfo &info,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
FI->CallingConvention = llvmCC;
FI->EffectiveCallingConvention = llvmCC;
FI->ASTCallingConvention = info.getCC();
+ FI->InstanceMethod = IsInstanceMethod;
FI->NoReturn = info.getNoReturn();
FI->ReturnsRetained = info.getProducesResult();
FI->Required = required;
FunctionArgList args;
ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
args.push_back(&dst);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(getContext().VoidTy, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ getContext().VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
args.push_back(&dstDecl);
ImplicitParamDecl srcDecl(FD, SourceLocation(), 0, SrcTy);
args.push_back(&srcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- RequiredArgs::All);
-
+
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), RequiredArgs::All);
+
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
args.push_back(&dstDecl);
ImplicitParamDecl srcDecl(FD, SourceLocation(), 0, SrcTy);
args.push_back(&srcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- RequiredArgs::All);
-
+
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), RequiredArgs::All);
+
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, false, Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
Params.push_back(IdType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
const char *name;
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
}
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
// Create the function declaration.
FunctionType::ExtInfo ExtInfo;
const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo,
- /*IsVariadic=*/false);
+ CGM.getTypes().arrangeFreeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo,
+ /*IsVariadic=*/false);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Function *F =
}
const CGFunctionInfo &
-CodeGenABITypes::arrangeLLVMFunctionInfo(CanQualType returnType,
+CodeGenABITypes::arrangeFreeFunctionCall(CanQualType returnType,
llvm::ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args) {
- return CGM->getTypes().arrangeLLVMFunctionInfo(returnType, argTypes,
- info, args);
+ return CGM->getTypes().arrangeLLVMFunctionInfo(
+ returnType, /*IsInstanceMethod=*/false, argTypes, info, args);
}
const CGFunctionInfo &arrangeGlobalDeclaration(GlobalDecl GD);
const CGFunctionInfo &arrangeFunctionDeclaration(const FunctionDecl *FD);
- const CGFunctionInfo &arrangeFunctionDeclaration(QualType ResTy,
- const FunctionArgList &Args,
- const FunctionType::ExtInfo &Info,
- bool isVariadic);
+ const CGFunctionInfo &
+ arrangeFreeFunctionDeclaration(QualType ResTy, const FunctionArgList &Args,
+ const FunctionType::ExtInfo &Info,
+ bool isVariadic);
const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD);
const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
///
/// \param argTypes - must all actually be canonical as params
const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
+ bool IsInstanceMethod,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args);
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
}
- static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
- unsigned callingConvention);
+ bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
+ bool IsInstanceMethod) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
Class classify(QualType Ty) const;
- ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
+ ABIArgInfo classifyReturnType(QualType RetTy, CCState &State,
+ bool IsInstanceMethod) const;
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
/// shouldReturnTypeInRegister - Determine if the given type should be
/// passed in a register (for the Darwin ABI).
-bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
- ASTContext &Context,
- unsigned callingConvention) {
+bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
+ bool IsInstanceMethod) const {
uint64_t Size = Context.getTypeSize(Ty);
// Type must be register sized.
// Arrays are treated like records.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
return shouldReturnTypeInRegister(AT->getElementType(), Context,
- callingConvention);
+ IsInstanceMethod);
// Otherwise, it must be a record type.
const RecordType *RT = Ty->getAs<RecordType>();
// For thiscall conventions, structures will never be returned in
// a register. This is for compatibility with the MSVC ABI
- if (callingConvention == llvm::CallingConv::X86_ThisCall &&
- RT->isStructureType()) {
+ if (IsWin32StructABI && IsInstanceMethod && RT->isStructureType())
return false;
- }
// Structure types are passed in register if all fields would be
// passed in a register.
continue;
// Check fields recursively.
- if (!shouldReturnTypeInRegister(FD->getType(), Context,
- callingConvention))
+ if (!shouldReturnTypeInRegister(FD->getType(), Context, IsInstanceMethod))
return false;
}
return true;
return ABIArgInfo::getIndirect(/*Align=*/0, /*ByVal=*/false);
}
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
- CCState &State) const {
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State,
+ bool IsInstanceMethod) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
// Small structures which are register sized are generally returned
// in a register.
- if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(),
- State.CC)) {
+ if (shouldReturnTypeInRegister(RetTy, getContext(), IsInstanceMethod)) {
uint64_t Size = getContext().getTypeSize(RetTy);
// As a special-case, if the struct is a "single-element" struct, and
else
State.FreeRegs = DefaultNumRegisterParameters;
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State);
+ FI.getReturnInfo() =
+ classifyReturnType(FI.getReturnType(), State, FI.isInstanceMethod());
+
+ // On win32, use the x86_cdeclmethodcc convention for cdecl methods that use
+ // sret. This convention swaps the order of the first two parameters behind
+ // the scenes to match MSVC.
+ if (IsWin32StructABI && FI.isInstanceMethod() &&
+ FI.getCallingConvention() == llvm::CallingConv::C &&
+ FI.getReturnInfo().isIndirect())
+ FI.setEffectiveCallingConvention(llvm::CallingConv::X86_CDeclMethod);
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
--- /dev/null
+// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s
+
+// PR15768
+
+// A trivial 12 byte struct is returned indirectly.
+struct S {
+ S();
+ int a, b, c;
+};
+
+struct C {
+ S variadic_sret(const char *f, ...);
+ S __cdecl cdecl_sret();
+ S __cdecl byval_and_sret(S a);
+ int c;
+};
+
+S C::variadic_sret(const char *f, ...) { return S(); }
+S C::cdecl_sret() { return S(); }
+S C::byval_and_sret(S a) { return S(); }
+
+// CHECK: define x86_cdeclmethodcc void @"\01?variadic_sret@C@@QAA?AUS@@PBDZZ"(%struct.S* noalias sret %agg.result, %struct.C* %this, i8* %f, ...)
+// CHECK: define x86_cdeclmethodcc void @"\01?cdecl_sret@C@@QAA?AUS@@XZ"(%struct.S* noalias sret %agg.result, %struct.C* %this)
+// CHECK: define x86_cdeclmethodcc void @"\01?byval_and_sret@C@@QAA?AUS@@U2@@Z"(%struct.S* noalias sret %agg.result, %struct.C* %this, %struct.S* byval align 4 %a)
+
+int main() {
+ C c;
+ c.variadic_sret("asdf");
+ c.cdecl_sret();
+ c.byval_and_sret(S());
+}
+// CHECK-LABEL: define i32 @main()
+// CHECK: call x86_cdeclmethodcc void {{.*}} @"\01?variadic_sret@C@@QAA?AUS@@PBDZZ"
+// CHECK: call x86_cdeclmethodcc void @"\01?cdecl_sret@C@@QAA?AUS@@XZ"
+// CHECK: call x86_cdeclmethodcc void @"\01?byval_and_sret@C@@QAA?AUS@@U2@@Z"
Small __cdecl cdecl_method_small() { return Small(); }
// LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
- // FIXME: Interesting, cdecl returns structures differently for instance
- // methods and global functions. This is not supported by Clang yet...
- // FIXME: Replace WIN32-NOT with WIN32 when this is fixed.
- // WIN32-NOT: define {{.*}} void @"\01?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this)
+ // WIN32: define {{.*}} void @"\01?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this)
Big __cdecl cdecl_method_big() { return Big(); }
// LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this)