class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
MinGWX86_64TargetInfo(const llvm::Triple &Triple)
- : WindowsX86_64TargetInfo(Triple) {}
+ : WindowsX86_64TargetInfo(Triple) {
+ // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks
+ // with x86 FP ops. Weird.
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
+ }
+
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
/// WinX86_64ABIInfo - The Windows X86_64 ABI information.
class WinX86_64ABIInfo : public ABIInfo {
-
- ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs,
- bool IsReturnType) const;
-
public:
- WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
+ WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT)
+ : ABIInfo(CGT),
+ IsMingw64(getTarget().getTriple().isWindowsGNUEnvironment()) {}
void computeInfo(CGFunctionInfo &FI) const override;
// FIXME: Assumes vectorcall is in use.
return isX86VectorCallAggregateSmallEnough(NumMembers);
}
+
+private:
+ ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs,
+ bool IsReturnType) const;
+
+ bool IsMingw64;
};
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
TypeInfo Info = getContext().getTypeInfo(Ty);
uint64_t Width = Info.Width;
- unsigned Align = getContext().toCharUnitsFromBits(Info.Align).getQuantity();
+ CharUnits Align = getContext().toCharUnitsFromBits(Info.Align);
const RecordType *RT = Ty->getAs<RecordType>();
if (RT) {
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
// FIXME: mingw-w64-gcc emits 128-bit struct as i128
- if (Width == 128 && getTarget().getTriple().isWindowsGNUEnvironment())
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- Width));
+ if (Width == 128 && IsMingw64)
+ return ABIArgInfo::getDirect(
+ llvm::IntegerType::get(getVMContext(), Width));
}
// vectorcall adds the concept of a homogenous vector aggregate, similar to
return ABIArgInfo::getDirect();
return ABIArgInfo::getExpand();
}
- return ABIArgInfo::getIndirect(CharUnits::fromQuantity(Align),
- /*ByVal=*/false);
+ return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
}
if (BT && BT->getKind() == BuiltinType::Bool)
return ABIArgInfo::getExtend();
+ // Mingw64 GCC uses the old 80 bit extended precision floating point unit. It
+ // passes them indirectly through memory.
+ if (IsMingw64 && BT && BT->getKind() == BuiltinType::LongDouble) {
+ const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
+ if (LDF == &llvm::APFloat::x87DoubleExtended)
+ return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
+ }
+
return ABIArgInfo::getDirect();
}
-// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 -triple i686-pc-windows-gnu -S %s -o - | FileCheck %s -check-prefix=CHECK_I686
-// CHECK_I686: _lda,12
-// CHECK_I686: _lds,16
-// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu -S %s -o - | FileCheck %s -check-prefix=CHECK_X86_64
-// CHECK_X86_64: lda,16
-// CHECK_X86_64: lds,32
-long double lda;
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=GNU32
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=GNU64
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=MSC64
+
struct {
char c;
long double ldb;
-} lds;
+} agggregate_LD = {};
+// GNU32: %struct.anon = type { i8, x86_fp80 }
+// GNU32: @agggregate_LD = global %struct.anon zeroinitializer, align 4
+// GNU64: %struct.anon = type { i8, x86_fp80 }
+// GNU64: @agggregate_LD = global %struct.anon zeroinitializer, align 16
+// MSC64: %struct.anon = type { i8, double }
+// MSC64: @agggregate_LD = global %struct.anon zeroinitializer, align 8
+
+long double dataLD = 1.0L;
+// GNU32: @dataLD = global x86_fp80 0xK3FFF8000000000000000, align 4
+// GNU64: @dataLD = global x86_fp80 0xK3FFF8000000000000000, align 16
+// MSC64: @dataLD = global double 1.000000e+00, align 8
+
+long double _Complex dataLDC = {1.0L, 1.0L};
+// GNU32: @dataLDC = global { x86_fp80, x86_fp80 } { x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK3FFF8000000000000000 }, align 4
+// GNU64: @dataLDC = global { x86_fp80, x86_fp80 } { x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK3FFF8000000000000000 }, align 16
+// MSC64: @dataLDC = global { double, double } { double 1.000000e+00, double 1.000000e+00 }, align 8
+
+long double TestLD(long double x) {
+ return x * x;
+}
+// GNU32: define x86_fp80 @TestLD(x86_fp80 %x)
+// GNU64: define void @TestLD(x86_fp80* noalias sret %agg.result, x86_fp80*)
+// MSC64: define double @TestLD(double %x)
+
+long double _Complex TestLDC(long double _Complex x) {
+ return x * x;
+}
+// GNU32: define void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval align 4 %x)
+// GNU64: define void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* %x)
+// MSC64: define void @TestLDC({ double, double }* noalias sret %agg.result, { double, double }* %x)