Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -2025,6 +2025,8 @@ 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 mlong_double_128 : Flag<["-"], "mlong-double-128">, Group, Flags<[CC1Option]>, + HelpText<"Force long double to be 128 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/TargetInfo.cpp =================================================================== --- lib/Basic/TargetInfo.cpp +++ lib/Basic/TargetInfo.cpp @@ -373,10 +373,15 @@ LongDoubleFormat = &llvm::APFloat::IEEEquad(); } - if (Opts.LongDoubleSize && Opts.LongDoubleSize == DoubleWidth) { - LongDoubleWidth = DoubleWidth; - LongDoubleAlign = DoubleAlign; - LongDoubleFormat = DoubleFormat; + if (Opts.LongDoubleSize) { + if (Opts.LongDoubleSize == DoubleWidth) { + LongDoubleWidth = DoubleWidth; + LongDoubleAlign = DoubleAlign; + LongDoubleFormat = DoubleFormat; + } else if (Opts.LongDoubleSize == 128) { + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + } } if (Opts.NewAlignOverride) Index: lib/Basic/Targets/PPC.cpp =================================================================== --- lib/Basic/Targets/PPC.cpp +++ lib/Basic/Targets/PPC.cpp @@ -465,6 +465,8 @@ if (HasAltivec) Opts.AltiVec = 1; TargetInfo::adjust(Opts); + if (LongDoubleFormat != &llvm::APFloat::IEEEdouble()) + LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); } ArrayRef PPCTargetInfo::getTargetBuiltins() const { Index: lib/Basic/Targets/X86.h =================================================================== --- lib/Basic/Targets/X86.h +++ lib/Basic/Targets/X86.h @@ -133,6 +133,10 @@ LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); } + const char *getLongDoubleMangling() const override { + return LongDoubleFormat == &llvm::APFloat::IEEEquad() ? "g" : "e"; + } + unsigned getFloatEvalMethod() const override { // X87 evaluates with 80 bits "long double" precision. return SSELevel == NoSSE ? 2 : 0; @@ -845,8 +849,6 @@ : LinuxTargetInfo(Triple, Opts) { LongDoubleFormat = &llvm::APFloat::IEEEquad(); } - - const char *getLongDoubleMangling() const override { return "g"; } }; } // namespace targets } // namespace clang Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4012,15 +4012,15 @@ RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs); - if (Arg *A = Args.getLastArg(options::OPT_mlong_double_64)) { + if (Arg *A = Args.getLastArg(options::OPT_mlong_double_64, + options::OPT_mlong_double_128)) { 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 { + TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) + A->render(Args, CmdArgs); + 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 Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2742,7 +2742,9 @@ 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.LongDoubleSize = Args.hasArg(OPT_mlong_double_128) + ? 128 + : 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/ppc64-long-double.cpp =================================================================== --- test/CodeGen/ppc64-long-double.cpp +++ test/CodeGen/ppc64-long-double.cpp @@ -2,8 +2,11 @@ // RUN: FileCheck --check-prefix=FP64 %s // RUN: %clang_cc1 -triple powerpc64-linux-gnu -emit-llvm -o - %s -mlong-double-64 | \ // RUN: FileCheck --check-prefix=FP64 %s + // RUN: %clang_cc1 -triple powerpc64-linux-gnu -emit-llvm -o - %s | \ // RUN: FileCheck --check-prefix=IBM128 %s +// RUN: %clang_cc1 -triple powerpc64-linux-musl -emit-llvm -o - -mlong-double-128 %s | \ +// RUN: FileCheck --check-prefix=IBM128 %s long double x = 0; int size = sizeof(x); Index: test/CodeGen/x86-long-double.cpp =================================================================== --- test/CodeGen/x86-long-double.cpp +++ test/CodeGen/x86-long-double.cpp @@ -16,6 +16,15 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin -mlong-double-64 | \ // RUN: FileCheck --check-prefixes=FP64,FP64-X64 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686 -mlong-double-128 | \ +// RUN: FileCheck --check-prefix=FP128 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin -mlong-double-128 | \ +// RUN: FileCheck --check-prefix=FP128 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64 -mlong-double-128 | \ +// RUN: FileCheck --check-prefix=FP128 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin -mlong-double-128 | \ +// RUN: FileCheck --check-prefix=FP128 %s + // Check -malign-double increases the alignment from 4 to 8 on x86-32. // RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686 -mlong-double-64 \ // RUN: -malign-double | FileCheck --check-prefixes=FP64,FP64-X64 %s @@ -37,7 +46,11 @@ // FP64-X64: @x = global double {{.*}}, align 8 // FP64-X64: @size = global i32 8 +// FP128: @x = global fp128 {{.*}}, align 16 +// FP128: @size = global i32 16 + long double foo(long double d) { return d; } // FP64: double @_Z3fooe(double %d) // FP80: x86_fp80 @_Z3fooe(x86_fp80 %d) +// FP128: fp128 @_Z3foog(fp128 %d) Index: test/Driver/mlong-double-128.c =================================================================== --- /dev/null +++ test/Driver/mlong-double-128.c @@ -0,0 +1,11 @@ +// RUN: %clang -target powerpc-linux-musl -c -### %s -mlong-double-128 2>&1 | FileCheck %s +// RUN: %clang -target powerpc64-pc-freebsd12 -c -### %s -mlong-double-128 2>&1 | FileCheck %s +// RUN: %clang -target powerpc64le-linux-musl -c -### %s -mlong-double-128 2>&1 | FileCheck %s +// RUN: %clang -target i686-linux-gnu -c -### %s -mlong-double-128 2>&1 | FileCheck %s +// RUN: %clang -target x86_64-linux-musl -c -### %s -mlong-double-128 2>&1 | FileCheck %s + +// CHECK: "-mlong-double-128" + +// RUN: %clang -target aarch64 -c -### %s -mlong-double-128 2>&1 | FileCheck --check-prefix=ERR %s + +// ERR: error: unsupported option '-mlong-double-128' for target 'aarch64'