[PATCH] D35259: Complex Long Double classification In RegCall calling convention
This revision was automatically updated to reflect the committed changes. Closed by commit rL308769: Complex Long Double classification In RegCall calling convention (authored by erichkeane). Changed prior to commit: https://reviews.llvm.org/D35259?vs=107667=107696#toc Repository: rL LLVM https://reviews.llvm.org/D35259 Files: cfe/trunk/lib/CodeGen/TargetInfo.cpp cfe/trunk/test/CodeGenCXX/regcall.cpp Index: cfe/trunk/test/CodeGenCXX/regcall.cpp === --- cfe/trunk/test/CodeGenCXX/regcall.cpp +++ cfe/trunk/test/CodeGenCXX/regcall.cpp @@ -73,8 +73,8 @@ // CHECK-WIN64-DAG: define x86_regcallcc zeroext i1 @"\01??8@Yw_NAEBVtest_class@@0@Z" // CHECK-WIN32-DAG: define x86_regcallcc zeroext i1 @"\01??8@Yw_NABVtest_class@@0@Z" -test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};} -// CHECK-LIN64-DAG: define x86_regcallcc %class.test_class @_Zli11_test_classy(i64) +test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};} +// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret %agg.result, i64) // CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret %agg.result, i64) // CHECK-WIN64-DAG: \01??__K_test_class@@Yw?AVtest_class@@_K@Z" // CHECK-WIN32-DAG: \01??__K_test_class@@Yw?AVtest_class@@_K@Z" @@ -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) Index: cfe/trunk/lib/CodeGen/TargetInfo.cpp === --- cfe/trunk/lib/CodeGen/TargetInfo.cpp +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp @@ -882,8 +882,14 @@ /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext , QualType Ty) { if (const BuiltinType *BT = Ty->getAs()) { -if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) +if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) { + if (BT->getKind() == BuiltinType::LongDouble) { +if (().getLongDoubleFormat() == +::APFloat::x87DoubleExtended()) + return false; + } return true; +} } else if (const VectorType *VT = Ty->getAs()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. @@ -3515,18 +3521,27 @@ unsigned FreeSSERegs = IsRegCall ? 16 : 8; unsigned NeededInt, NeededSSE; - if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && - !FI.getReturnType()->getTypePtr()->isUnionType()) { -FI.getReturnInfo() = -classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); -if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { - FreeIntRegs -= NeededInt; - FreeSSERegs -= NeededSSE; -} else { - FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); -} - } else if (!getCXXABI().classifyReturnType(FI)) -FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) { +if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && +!FI.getReturnType()->getTypePtr()->isUnionType()) { + FI.getReturnInfo() = + classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); + if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { +FreeIntRegs -= NeededInt; +FreeSSERegs -= NeededSSE; + } else { +FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); + } +} else if (IsRegCall && FI.getReturnType()->getAs()) { + // Complex Long Double Type is passed in Memory when Regcall + // calling convention is used. + const ComplexType *CT = FI.getReturnType()->getAs(); + if (getContext().getCanonicalType(CT->getElementType()) == + getContext().LongDoubleTy) +FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); +} else + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + } // If the return value is indirect, then the hidden argument is consuming one // integer register. Index: cfe/trunk/test/CodeGenCXX/regcall.cpp
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
rnk accepted this revision. rnk added a comment. This revision is now accepted and ready to land. lgtm https://reviews.llvm.org/D35259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
eandrews updated this revision to Diff 107667. eandrews added a comment. Regcall-specific checks for Lin64 now occur only if CXXABI returns false. An existing test has also been modified to verify behavior with non trivial destructors. https://reviews.llvm.org/D35259 Files: lib/CodeGen/TargetInfo.cpp test/CodeGenCXX/regcall.cpp Index: test/CodeGenCXX/regcall.cpp === --- test/CodeGenCXX/regcall.cpp +++ test/CodeGenCXX/regcall.cpp @@ -73,8 +73,8 @@ // CHECK-WIN64-DAG: define x86_regcallcc zeroext i1 @"\01??8@Yw_NAEBVtest_class@@0@Z" // CHECK-WIN32-DAG: define x86_regcallcc zeroext i1 @"\01??8@Yw_NABVtest_class@@0@Z" -test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};} -// CHECK-LIN64-DAG: define x86_regcallcc %class.test_class @_Zli11_test_classy(i64) +test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};} +// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret %agg.result, i64) // CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret %agg.result, i64) // CHECK-WIN64-DAG: \01??__K_test_class@@Yw?AVtest_class@@_K@Z" // CHECK-WIN32-DAG: \01??__K_test_class@@Yw?AVtest_class@@_K@Z" @@ -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) Index: lib/CodeGen/TargetInfo.cpp === --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -882,8 +882,14 @@ /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext , QualType Ty) { if (const BuiltinType *BT = Ty->getAs()) { -if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) +if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) { + if (BT->getKind() == BuiltinType::LongDouble) { +if (().getLongDoubleFormat() == +::APFloat::x87DoubleExtended()) + return false; + } return true; +} } else if (const VectorType *VT = Ty->getAs()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. @@ -3505,18 +3511,27 @@ unsigned FreeSSERegs = IsRegCall ? 16 : 8; unsigned NeededInt, NeededSSE; - if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && - !FI.getReturnType()->getTypePtr()->isUnionType()) { -FI.getReturnInfo() = -classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); -if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { - FreeIntRegs -= NeededInt; - FreeSSERegs -= NeededSSE; -} else { - FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); -} - } else if (!getCXXABI().classifyReturnType(FI)) -FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) { +if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && +!FI.getReturnType()->getTypePtr()->isUnionType()) { + FI.getReturnInfo() = + classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); + if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { +FreeIntRegs -= NeededInt; +FreeSSERegs -= NeededSSE; + } else { +FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); + } +} else if (IsRegCall && FI.getReturnType()->getAs()) { + // Complex Long Double Type is passed in Memory when Regcall + // calling convention is used. + const ComplexType *CT = FI.getReturnType()->getAs(); + if (getContext().getCanonicalType(CT->getElementType()) == + getContext().LongDoubleTy) +FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); +} else + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + } // If the return value is indirect, then the hidden argument is consuming one // integer register. Index: test/CodeGenCXX/regcall.cpp === --- test/CodeGenCXX/regcall.cpp +++ test/CodeGenCXX/regcall.cpp @@ -73,8 +73,8 @@ // CHECK-WIN64-DAG: define
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
rnk added inline comments. Comment at: lib/CodeGen/TargetInfo.cpp:3516 + // calling convention is used. if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && !FI.getReturnType()->getTypePtr()->isUnionType()) { This is incorrect. We should consult the CXXABI first, and then only do these regcall-specific things if it returns false. Consider adding this test case to find the bug: ``` struct NonTrivial { int x, y; ~NonTrivial(); }; NonTrivial __regcall f() { return NonTrivial(); } ``` This should not return in registers, but it does today. Comment at: lib/CodeGen/TargetInfo.cpp:3526 } + } else if (IsRegCall && FI.getReturnType()->getAs()) { +const ComplexType *CT = FI.getReturnType()->getAs(); This isn't necessarily a bug, but please always do C++ ABI classifications first so it's easy to spot the bug above. https://reviews.llvm.org/D35259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
eandrews updated this revision to Diff 107343. eandrews added a comment. As per revision comments, I moved the condition for extended precision floating type to isX86VectorTypeForVectorCall. This update will now alter behavior for complex long double type under vectorcall calling convention as well. Returns/parameters will be passed in memory. https://reviews.llvm.org/D35259 Files: lib/CodeGen/TargetInfo.cpp test/CodeGenCXX/regcall.cpp 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) Index: lib/CodeGen/TargetInfo.cpp === --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -882,8 +882,14 @@ /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext , QualType Ty) { if (const BuiltinType *BT = Ty->getAs()) { -if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) +if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) { + if (BT->getKind() == BuiltinType::LongDouble) { +if (().getLongDoubleFormat() == +::APFloat::x87DoubleExtended()) + return false; + } return true; +} } else if (const VectorType *VT = Ty->getAs()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. @@ -3505,6 +3511,8 @@ unsigned FreeSSERegs = IsRegCall ? 16 : 8; unsigned NeededInt, NeededSSE; + // Complex Long Double Type is passed in Memory when Regcall + // calling convention is used. if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && !FI.getReturnType()->getTypePtr()->isUnionType()) { FI.getReturnInfo() = @@ -3515,6 +3523,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()); 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) Index: lib/CodeGen/TargetInfo.cpp === --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -882,8 +882,14 @@ /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext , QualType Ty) { if (const BuiltinType *BT = Ty->getAs()) { -if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) +if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) { + if (BT->getKind() == BuiltinType::LongDouble) { +if (().getLongDoubleFormat() == +::APFloat::x87DoubleExtended()) + return false; + } return true; +} } else if (const VectorType *VT = Ty->getAs()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. @@ -3505,6 +3511,8 @@ unsigned FreeSSERegs = IsRegCall ? 16 : 8; unsigned NeededInt,
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
eandrews added a comment. In https://reviews.llvm.org/D35259#805415, @erichkeane wrote: > In https://reviews.llvm.org/D35259#805409, @rnk wrote: > > > In https://reviews.llvm.org/D35259#805284, @erichkeane wrote: > > > > > Oren discovered this miss to the original implementation. I'd reviewed > > > this internally quite a bit. > > > > > > The reason for the Win32ABI test is that MSVC 'long double' is actually > > > small enough for SSE registers in this case. I DO now (looking again, > > > sorry Elizabeth) wonder if there is a better way to exclude > > > extended-length LongDouble type? Could we us the 'length' of it instead? > > > @rnk : opinion? > > > > > > Yeah, you can ask clang::TargetInfo for the format of most basic FP types. > > The code to do that looks like: > > > > () == ::APFloat::x87DoubleExtended() > > > > > > Any reason you can't just add that condition to > > isX86VectorTypeForVectorCall? I assume we don't want to pass x86_fp80s in > > SSE registers for vectorcall either, right? That would eliminate the need > > for the isRegCallReturnableHA helper and the IsWin32StructABI parameter, > > which is a poorly named variable. > > > It actually WOULD make sense to apply this to vectorcall as well, wouldn't > it? I presumed we didnt want to change its behavior, however vectorcall is > MSVC-only (other than us), so the long-double issue isn't a thing over > there.@eandrews? I can apply this condition to isX86VectorTypeForVectorCall like Reid suggested. The only reason I did not do that originally was because I wasn't sure how to differentiate between the calling conventions without changing function declaration. If I don't need to explicitly differentiate between RegCall and VectorCall and can use the 'length' instead, I think this works better. Like Reid mentioned, it would eliminate the need for isRegCallReturnableHA and IsWin32StructABI. https://reviews.llvm.org/D35259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
erichkeane added a comment. In https://reviews.llvm.org/D35259#805409, @rnk wrote: > In https://reviews.llvm.org/D35259#805284, @erichkeane wrote: > > > Oren discovered this miss to the original implementation. I'd reviewed > > this internally quite a bit. > > > > The reason for the Win32ABI test is that MSVC 'long double' is actually > > small enough for SSE registers in this case. I DO now (looking again, > > sorry Elizabeth) wonder if there is a better way to exclude extended-length > > LongDouble type? Could we us the 'length' of it instead? @rnk : opinion? > > > Yeah, you can ask clang::TargetInfo for the format of most basic FP types. > The code to do that looks like: > > () == ::APFloat::x87DoubleExtended() > > > Any reason you can't just add that condition to isX86VectorTypeForVectorCall? > I assume we don't want to pass x86_fp80s in SSE registers for vectorcall > either, right? That would eliminate the need for the isRegCallReturnableHA > helper and the IsWin32StructABI parameter, which is a poorly named variable. It actually WOULD make sense to apply this to vectorcall as well, wouldn't it? I presumed we didnt want to change its behavior, however vectorcall is MSVC-only (other than us), so the long-double issue isn't a thing over there.@eandrews? https://reviews.llvm.org/D35259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
rnk added a comment. In https://reviews.llvm.org/D35259#805284, @erichkeane wrote: > Oren discovered this miss to the original implementation. I'd reviewed this > internally quite a bit. > > The reason for the Win32ABI test is that MSVC 'long double' is actually small > enough for SSE registers in this case. I DO now (looking again, sorry > Elizabeth) wonder if there is a better way to exclude extended-length > LongDouble type? Could we us the 'length' of it instead? @rnk : opinion? Yeah, you can ask clang::TargetInfo for the format of most basic FP types. The code to do that looks like: () == ::APFloat::x87DoubleExtended() Any reason you can't just add that condition to isX86VectorTypeForVectorCall? I assume we don't want to pass x86_fp80s in SSE registers for vectorcall either, right? That would eliminate the need for the isRegCallReturnableHA helper and the IsWin32StructABI parameter, which is a poorly named variable. https://reviews.llvm.org/D35259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
erichkeane added a comment. Oren discovered this miss to the original implementation. I'd reviewed this internally quite a bit. The reason for the Win32ABI test is that MSVC 'long double' is actually small enough for SSE registers in this case. I DO now (looking again, sorry Elizabeth) wonder if there is a better way to exclude extended-length LongDouble type? Could we us the 'length' of it instead? @rnk : opinion? https://reviews.llvm.org/D35259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D35259: Complex Long Double classification In RegCall calling convention
eandrews created this revision. This change is part of the RegCall calling convention support for LLVM. Existing RegCall implementation was extended to include correct handling of Complex Long Double type. Complex long double types should be returned/passed in memory and not register stack. This patch implements this behavior. https://reviews.llvm.org/D35259 Files: lib/CodeGen/ABIInfo.h lib/CodeGen/TargetInfo.cpp test/CodeGenCXX/regcall.cpp 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) 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 *, uint64_t , +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: lib/CodeGen/ABIInfo.h === --- lib/CodeGen/ABIInfo.h +++ lib/CodeGen/ABIInfo.h @@ -111,6 +111,10 @@ bool isHomogeneousAggregate(QualType Ty, const Type *, uint64_t ) const; +bool isRegcallReturnableHomogeneousAggregate(QualType Ty, const Type *, + uint64_t , + 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: 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