mstorsjo created this revision. mstorsjo added reviewers: rnk, mati865. Herald added a subscriber: pengfei. mstorsjo requested review of this revision. Herald added a project: clang.
On x86_64 mingw, long doubles are always passed indirectly as arguments (see an existing case in WinX86_64ABIInfo::classify); we need to take this into account when manually reading back arguments with `va_arg` too. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D103452 Files: clang/lib/CodeGen/TargetInfo.cpp clang/test/CodeGen/mingw-long-double.c Index: clang/test/CodeGen/mingw-long-double.c =================================================================== --- clang/test/CodeGen/mingw-long-double.c +++ clang/test/CodeGen/mingw-long-double.c @@ -45,3 +45,16 @@ // GNU32: declare dso_local void @__mulxc3 // GNU64: declare dso_local void @__mulxc3 // MSC64: declare dso_local void @__muldc3 + +void VarArgLD(int a, ...) { + // GNU32-LABEL: define{{.*}} void @VarArgLD + // GNU64-LABEL: define{{.*}} void @VarArgLD + // MSC64-LABEL: define{{.*}} void @VarArgLD + __builtin_va_list ap; + __builtin_va_start(ap, a); + long double LD = __builtin_va_arg(ap, long double); + // GNU32: bitcast i8* %argp.cur to x86_fp80* + // GNU64: bitcast i8* %argp.cur to x86_fp80** + // MSC64: bitcast i8* %argp.cur to double* + __builtin_va_end(ap); +} Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -4366,6 +4366,16 @@ if (isAggregateTypeForABI(Ty) || Ty->isMemberPointerType()) { uint64_t Width = getContext().getTypeSize(Ty); IsIndirect = Width > 64 || !llvm::isPowerOf2_64(Width); + } else if (IsMingw64) { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble) { + // Mingw64 GCC uses the old 80 bit extended precision floating point + // unit. It passes them indirectly through memory. + const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); + if (LDF == &llvm::APFloat::x87DoubleExtended()) + IsIndirect = true; + } + } } return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
Index: clang/test/CodeGen/mingw-long-double.c =================================================================== --- clang/test/CodeGen/mingw-long-double.c +++ clang/test/CodeGen/mingw-long-double.c @@ -45,3 +45,16 @@ // GNU32: declare dso_local void @__mulxc3 // GNU64: declare dso_local void @__mulxc3 // MSC64: declare dso_local void @__muldc3 + +void VarArgLD(int a, ...) { + // GNU32-LABEL: define{{.*}} void @VarArgLD + // GNU64-LABEL: define{{.*}} void @VarArgLD + // MSC64-LABEL: define{{.*}} void @VarArgLD + __builtin_va_list ap; + __builtin_va_start(ap, a); + long double LD = __builtin_va_arg(ap, long double); + // GNU32: bitcast i8* %argp.cur to x86_fp80* + // GNU64: bitcast i8* %argp.cur to x86_fp80** + // MSC64: bitcast i8* %argp.cur to double* + __builtin_va_end(ap); +} Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -4366,6 +4366,16 @@ if (isAggregateTypeForABI(Ty) || Ty->isMemberPointerType()) { uint64_t Width = getContext().getTypeSize(Ty); IsIndirect = Width > 64 || !llvm::isPowerOf2_64(Width); + } else if (IsMingw64) { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble) { + // Mingw64 GCC uses the old 80 bit extended precision floating point + // unit. It passes them indirectly through memory. + const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); + if (LDF == &llvm::APFloat::x87DoubleExtended()) + IsIndirect = true; + } + } } return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits