diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -380,6 +380,9 @@ "argument '%0' is deprecated, use '%1' instead">, InGroup; def warn_drv_assuming_mfloat_abi_is : Warning< "unknown platform, assuming -mfloat-abi=%0">; +def warn_drv_unsupported_float_abi_by_lib : Warning< + "float ABI '%0' is not supported by current library">, + InGroup>; def warn_ignoring_ftabstop_value : Warning< "ignoring invalid -ftabstop value '%0', using default value %1">; def warn_drv_overriding_flag_option : Warning< diff --git a/clang/lib/Driver/ToolChains/PPCLinux.h b/clang/lib/Driver/ToolChains/PPCLinux.h --- a/clang/lib/Driver/ToolChains/PPCLinux.h +++ b/clang/lib/Driver/ToolChains/PPCLinux.h @@ -18,12 +18,15 @@ class LLVM_LIBRARY_VISIBILITY PPCLinuxToolChain : public Linux { public: PPCLinuxToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : Linux(D, Triple, Args) {} + const llvm::opt::ArgList &Args); void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + +private: + bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp --- a/clang/lib/Driver/ToolChains/PPCLinux.cpp +++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -8,11 +8,50 @@ #include "PPCLinux.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" using namespace clang::driver::toolchains; using namespace llvm::opt; +using namespace llvm::sys; + +// Glibc older than 2.32 doesn't fully support IEEE float128. Here we check +// glibc version by looking at dynamic linker name. +static bool GlibcSupportsFloat128(const std::string &Linker) { + llvm::SmallVector Path; + + // Resolve potential symlinks to linker. + if (fs::real_path(Linker, Path)) + return false; + llvm::StringRef LinkerName = + path::filename(llvm::StringRef(Path.data(), Path.size())); + + // Since glibc 2.34, the installed .so file is not symlink anymore. But we can + // still safely assume it's newer than 2.32. + if (LinkerName.startswith("ld64.so")) + return true; + + if (!LinkerName.startswith("ld-2.")) + return false; + unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0'); + if (Minor < 32) + return false; + + return true; +} + +PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Linux(D, Triple, Args) { + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + StringRef ABIName = A->getValue(); + if (ABIName == "ieeelongdouble" && !SupportIEEEFloat128(D, Triple, Args)) + D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName; + } +} void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { @@ -26,3 +65,20 @@ Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args); } + +bool PPCLinuxToolChain::SupportIEEEFloat128( + const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const { + if (!Triple.isLittleEndian() || !Triple.isPPC64()) + return false; + + if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) + return true; + + bool HasUnsupportedCXXLib = + ToolChain::GetCXXStdlibType(Args) == CST_Libcxx && + GCCInstallation.getVersion().isOlderThan(12, 1, 0); + + return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) && + !(D.CCCIsCXX() && HasUnsupportedCXXLib); +} diff --git a/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/lib/gcc/powerpc64le-linux-gnu/11.2.0/.keep b/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/lib/gcc/powerpc64le-linux-gnu/11.2.0/.keep new file mode 100644 diff --git a/clang/test/Driver/ppc-float-abi-warning.cpp b/clang/test/Driver/ppc-float-abi-warning.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Driver/ppc-float-abi-warning.cpp @@ -0,0 +1,13 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang -### --driver-mode=g++ -target powerpc64le-linux-gnu %s \ +// RUN: --gcc-toolchain=%S/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0 \ +// RUN: -mabi=ieeelongdouble -stdlib=libstdc++ 2>&1 | FileCheck %s +// RUN: %clang -### --driver-mode=g++ -target powerpc64le-linux-gnu %s \ +// RUN: -mabi=ieeelongdouble -stdlib=libc++ 2>&1 | FileCheck %s +// RUN: %clang -### --driver-mode=g++ -target powerpc64le-linux-gnu %s\ +// RUN: -mabi=ieeelongdouble -stdlib=libc++ -Wno-unsupported-abi 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NOWARN + +// CHECK: warning: float ABI 'ieeelongdouble' is not supported by current library +// NOWARN-NOT: warning: float ABI 'ieeelongdouble' is not supported by current library +long double foo(long double x) { return x; }