1 //===-- PPCLinux.cpp - PowerPC ToolChain Implementations --------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "PPCLinux.h" 10 #include "clang/Driver/Driver.h" 11 #include "clang/Driver/DriverDiagnostic.h" 12 #include "clang/Driver/Options.h" 13 #include "llvm/Support/FileSystem.h" 14 #include "llvm/Support/Path.h" 15 16 using namespace clang::driver; 17 using namespace clang::driver::toolchains; 18 using namespace llvm::opt; 19 using namespace llvm::sys; 20 21 // Glibc older than 2.32 doesn't fully support IEEE float128. Here we check 22 // glibc version by looking at dynamic linker name. 23 static bool GlibcSupportsFloat128(const std::string &Linker) { 24 llvm::SmallVector<char, 16> Path; 25 26 // Resolve potential symlinks to linker. 27 if (fs::real_path(Linker, Path)) 28 return false; 29 llvm::StringRef LinkerName = 30 path::filename(llvm::StringRef(Path.data(), Path.size())); 31 32 // Since glibc 2.34, the installed .so file is not symlink anymore. But we can 33 // still safely assume it's newer than 2.32. 34 if (LinkerName.starts_with("ld64.so")) 35 return true; 36 37 if (!LinkerName.starts_with("ld-2.")) 38 return false; 39 unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0'); 40 if (Minor < 32) 41 return false; 42 43 return true; 44 } 45 46 PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D, 47 const llvm::Triple &Triple, 48 const llvm::opt::ArgList &Args) 49 : Linux(D, Triple, Args) { 50 if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { 51 StringRef ABIName = A->getValue(); 52 53 if ((ABIName == "ieeelongdouble" && 54 !SupportIEEEFloat128(D, Triple, Args)) || 55 (ABIName == "ibmlongdouble" && !supportIBMLongDouble(D, Args))) 56 D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName; 57 } 58 } 59 60 void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 61 ArgStringList &CC1Args) const { 62 if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) && 63 !DriverArgs.hasArg(options::OPT_nobuiltininc)) { 64 const Driver &D = getDriver(); 65 SmallString<128> P(D.ResourceDir); 66 llvm::sys::path::append(P, "include", "ppc_wrappers"); 67 addSystemInclude(DriverArgs, CC1Args, P); 68 } 69 70 Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args); 71 } 72 73 bool PPCLinuxToolChain::supportIBMLongDouble( 74 const Driver &D, const llvm::opt::ArgList &Args) const { 75 if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) 76 return true; 77 78 CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); 79 if (StdLib == CST_Libstdcxx) 80 return true; 81 82 return StdLib == CST_Libcxx && !defaultToIEEELongDouble(); 83 } 84 85 bool PPCLinuxToolChain::SupportIEEEFloat128( 86 const Driver &D, const llvm::Triple &Triple, 87 const llvm::opt::ArgList &Args) const { 88 if (!Triple.isLittleEndian() || !Triple.isPPC64()) 89 return false; 90 91 if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) 92 return true; 93 94 CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); 95 bool HasUnsupportedCXXLib = 96 (StdLib == CST_Libcxx && !defaultToIEEELongDouble()) || 97 (StdLib == CST_Libstdcxx && 98 GCCInstallation.getVersion().isOlderThan(12, 1, 0)); 99 100 std::string Linker = Linux::getDynamicLinker(Args); 101 return GlibcSupportsFloat128((Twine(D.DyldPrefix) + Linker).str()) && 102 !(D.CCCIsCXX() && HasUnsupportedCXXLib); 103 } 104