Index: lib/CodeGen/ABIInfo.h =================================================================== --- lib/CodeGen/ABIInfo.h +++ lib/CodeGen/ABIInfo.h @@ -111,6 +111,10 @@ bool isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t &Members) const; + bool isRegcallReturnableHomogeneousAggregate(QualType Ty, const Type *&Base, + uint64_t &Members, + bool IsWin32StructABI) const; + /// A convenience method to return an indirect ABIArgInfo with an /// expected alignment equal to the ABI alignment of the given type. CodeGen::ABIArgInfo Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -1289,9 +1289,11 @@ const Type *Base = nullptr; uint64_t NumElts = 0; - if ((State.CC == llvm::CallingConv::X86_VectorCall || - State.CC == llvm::CallingConv::X86_RegCall) && - isHomogeneousAggregate(RetTy, Base, NumElts)) { + if ((State.CC == llvm::CallingConv::X86_VectorCall && + isHomogeneousAggregate(RetTy, Base, NumElts)) || + (State.CC == llvm::CallingConv::X86_RegCall && + isRegcallReturnableHomogeneousAggregate(RetTy, Base, NumElts, + IsWin32StructABI))) { // The LLVM struct type for such an aggregate should lower properly. return ABIArgInfo::getDirect(); } @@ -1558,8 +1560,8 @@ const Type *Base = nullptr; uint64_t NumElts = 0; if (State.CC == llvm::CallingConv::X86_RegCall && - isHomogeneousAggregate(Ty, Base, NumElts)) { - + isRegcallReturnableHomogeneousAggregate(Ty, Base, NumElts, + IsWin32StructABI)) { if (State.FreeSSERegs >= NumElts) { State.FreeSSERegs -= NumElts; if (Ty->isBuiltinType() || Ty->isVectorType()) @@ -3495,6 +3497,11 @@ } else { FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); } + } else if (IsRegCall && FI.getReturnType()->getAs()) { + const ComplexType *CT = FI.getReturnType()->getAs(); + if (getContext().getCanonicalType(CT->getElementType()) == + getContext().LongDoubleTy) + FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); } else if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); @@ -4385,6 +4392,24 @@ return CharUnits::fromQuantity(8); } +/// isRegcallReturnableHomogeneousAggregate - Return true if a type is an ELFv2 +/// homogeneous aggregate that can be returned in stack for regcall. +bool ABIInfo::isRegcallReturnableHomogeneousAggregate( + QualType Ty, const Type *&Base, uint64_t &Members, + bool IsWin32StructABI) const { + if (isHomogeneousAggregate(Ty, Base, Members)) { + if (const ComplexType *CT = Ty->getAs()) { + if (!IsWin32StructABI) { + QualType ET = getContext().getCanonicalType(CT->getElementType()); + if (ET == getContext().LongDoubleTy) + return false; + } + } + return true; + } + return false; +} + /// isHomogeneousAggregate - Return true if a type is an ELFv2 homogeneous /// aggregate. Base is set to the base element type, and Members is set /// to the number of base elements. Index: test/CodeGenCXX/regcall.cpp =================================================================== --- test/CodeGenCXX/regcall.cpp +++ test/CodeGenCXX/regcall.cpp @@ -95,3 +95,11 @@ freeTempFunc(1); t3.do_thing(); } + +long double _Complex __regcall foo(long double _Complex f) { + return f; +} +// CHECK-LIN64-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval align 16 %f) +// CHECK-LIN32-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* inreg noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval align 4 %f) +// CHECK-WIN64-DAG: define x86_regcallcc { double, double } @"\01?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1) +// CHECK-WIN32-DAG: define x86_regcallcc { double, double } @"\01?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1)