Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -171,6 +171,7 @@ VALUE_LANGOPT(MaxTypeAlign , 32, 0, "default maximum alignment for types") VALUE_LANGOPT(AlignDouble , 1, 0, "Controls if doubles should be aligned to 8 bytes (x86 only)") +VALUE_LANGOPT(LongDoubleSize , 32, 0, "width of long double") COMPATIBLE_VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level") COMPATIBLE_VALUE_LANGOPT(PIE , 1, 0, "is pie") LANGOPT(ROPI , 1, 0, "Read-only position independence") Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -2023,6 +2023,8 @@ def mfancy_math_387 : Flag<["-"], "mfancy-math-387">, Group; def mlong_calls : Flag<["-"], "mlong-calls">, Group, HelpText<"Generate branches with extended addressability, usually via indirect jumps.">; +def mlong_double_64 : Flag<["-"], "mlong-double-64">, Group, Flags<[CC1Option]>, + HelpText<"Force long double to be 64 bits">; def mno_long_calls : Flag<["-"], "mno-long-calls">, Group, HelpText<"Restore the default behaviour of not generating long calls">; def mexecute_only : Flag<["-"], "mexecute-only">, Group, Index: lib/Basic/Targets/PPC.cpp =================================================================== --- lib/Basic/Targets/PPC.cpp +++ lib/Basic/Targets/PPC.cpp @@ -462,9 +462,13 @@ } void PPCTargetInfo::adjust(LangOptions &Opts) { + TargetInfo::adjust(Opts); if (HasAltivec) Opts.AltiVec = 1; - TargetInfo::adjust(Opts); + if (Opts.LongDoubleSize == 64) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } } ArrayRef PPCTargetInfo::getTargetBuiltins() const { Index: lib/Basic/Targets/X86.h =================================================================== --- lib/Basic/Targets/X86.h +++ lib/Basic/Targets/X86.h @@ -133,6 +133,8 @@ LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); } + void adjust(LangOptions &Opts) override; + unsigned getFloatEvalMethod() const override { // X87 evaluates with 80 bits "long double" precision. return SSELevel == NoSSE ? 2 : 0; Index: lib/Basic/Targets/X86.cpp =================================================================== --- lib/Basic/Targets/X86.cpp +++ lib/Basic/Targets/X86.cpp @@ -89,6 +89,15 @@ using namespace clang; using namespace clang::targets; +void X86TargetInfo::adjust(LangOptions &Opts) { + TargetInfo::adjust(Opts); + if (Opts.LongDoubleSize == 64) { + LongDoubleWidth = 64; + LongDoubleAlign = DoubleAlign; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } +} + bool X86TargetInfo::setFPMath(StringRef Name) { if (Name == "387") { FPMath = FP_387; Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4001,6 +4001,17 @@ RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_mlong_double_64)) { + if (TC.getArch() == llvm::Triple::x86 || + TC.getArch() == llvm::Triple::x86_64 || + TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) { + CmdArgs.push_back("-mlong-double-64"); + } else { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } + // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault(); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2738,6 +2738,7 @@ Opts.PackStruct = getLastArgIntValue(Args, OPT_fpack_struct_EQ, 0, Diags); Opts.MaxTypeAlign = getLastArgIntValue(Args, OPT_fmax_type_align_EQ, 0, Diags); Opts.AlignDouble = Args.hasArg(OPT_malign_double); + Opts.LongDoubleSize = Args.hasArg(OPT_mlong_double_64) ? 64 : 0; Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.ROPI = Args.hasArg(OPT_fropi); Opts.RWPI = Args.hasArg(OPT_frwpi); Index: test/CodeGen/long-double-x86.c =================================================================== --- test/CodeGen/long-double-x86.c +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | grep x86_fp80 - -long double x = 0; -int checksize[sizeof(x) == 16 ? 1 : -1]; Index: test/CodeGen/ppc64-align-long-double.c =================================================================== --- test/CodeGen/ppc64-align-long-double.c +++ /dev/null @@ -1,16 +0,0 @@ -// REQUIRES: powerpc-registered-target -// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s - -struct S { - double a; - long double b; -}; - -// CHECK: %struct.{{[a-zA-Z0-9]+}} = type { double, ppc_fp128 } - -long double test (struct S x) -{ - return x.b; -} - -// CHECK: %{{[0-9]}} = load ppc_fp128, ppc_fp128* %{{[a-zA-Z0-9]+}}, align 16 Index: test/CodeGen/ppc64-long-double.c =================================================================== --- /dev/null +++ test/CodeGen/ppc64-long-double.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple powerpc64-linux-musl -emit-llvm -o - %s -mlong-double-64 | \ +// RUN: FileCheck --check-prefix=FP64 %s +// RUN: %clang_cc1 -triple powerpc64-linux-musl -emit-llvm -o - %s | \ +// RUN: FileCheck --check-prefix=IBM128 %s + +struct S { + char a; + long double b; +}; + +// FP64: %struct.{{[a-zA-Z0-9]+}} = type { i8, double } +// IBM128: %struct.{{[a-zA-Z0-9]+}} = type { i8, ppc_fp128 } + +long double load(struct S x) { + return x.b; +} + +// FP64: %{{[0-9]}} = load double, double* %{{[a-zA-Z0-9]+}}, align 8 +// IBM128: %{{[0-9]}} = load ppc_fp128, ppc_fp128* %{{[a-zA-Z0-9]+}}, align 16 Index: test/CodeGen/x86-long-double.c =================================================================== --- /dev/null +++ test/CodeGen/x86-long-double.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 -mlong-double-64 | \ +// RUN: FileCheck --check-prefix=FP64-X32 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | \ +// RUN: FileCheck --check-prefix=FP80 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-linux-musl -mlong-double-64 | \ +// RUN: FileCheck --check-prefix=FP64-X64 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-linux-musl | \ +// RUN: FileCheck --check-prefix=FP80 %s + +long double x = 0; +int size = sizeof(x); + +// FP64-X32: @x = global double {{.*}}, align 4 +// FP64-X32: @size = global i32 8 +// FP64-X64: @x = global double {{.*}}, align 8 +// FP64-X64: @size = global i32 8 +// FP80: @x = global x86_fp80 {{.*}}, align 16 +// FP80: @size = global i32 16 Index: test/Driver/mlong-double-64.c =================================================================== --- /dev/null +++ test/Driver/mlong-double-64.c @@ -0,0 +1,11 @@ +// RUN: %clang -target powerpc-linux-musl -c -### %s -mlong-double-64 2>&1 | FileCheck %s +// RUN: %clang -target powerpc64-pc-freebsd12 -c -### %s -mlong-double-64 2>&1 | FileCheck %s +// RUN: %clang -target powerpc64le-linux-musl -c -### %s -mlong-double-64 2>&1 | FileCheck %s +// RUN: %clang -target i686-linux-gnu -c -### %s -mlong-double-64 2>&1 | FileCheck %s +// RUN: %clang -target x86_64-linux-musl -c -### %s -mlong-double-64 2>&1 | FileCheck %s + +// CHECK: "-mlong-double-64" + +// RUN: %clang -target aarch64 -c -### %s -mlong-double-64 2>&1 | FileCheck --check-prefix=ERR %s + +// ERR: error: unsupported option '-mlong-double-64' for target 'aarch64'