diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index f801c15ec8f6d..44aaadf123b87 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1676,6 +1676,42 @@ static void findRISCVMultilibs(const Driver &D, Result.Multilibs = RISCVMultilibs; } +static void findXtensaMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, StringRef Path, + const ArgList &Args, DetectedMultilibs &Result) { + + MultilibSet XtensaMultilibs = MultilibSet(); + bool IsESP32 = Args.getLastArgValue(options::OPT_mcpu_EQ, "esp32").equals("esp32"); + + XtensaMultilibs.push_back(Multilib()); + if (IsESP32) + XtensaMultilibs.push_back(Multilib("esp32-psram", {}, {}, 2) + .flag("+mfix-esp32-psram-cache-issue")); + + XtensaMultilibs.push_back( + Multilib("no-rtti", {}, {}, 1).flag("+fno-rtti").flag("-frtti")); + + if (IsESP32) + XtensaMultilibs.push_back(Multilib("esp32-psram/no-rtti", {}, {}, 3) + .flag("+fno-rtti") + .flag("-frtti") + .flag("+mfix-esp32-psram-cache-issue")); + + Multilib::flags_list Flags; + addMultilibFlag( + Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, false), "frtti", + Flags); + + if (IsESP32) + addMultilibFlag(Args.hasFlag(options::OPT_mfix_esp32_psram_cache_issue, + options::OPT_mfix_esp32_psram_cache_issue, + false), + "mfix-esp32-psram-cache-issue", Flags); + + if (XtensaMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = XtensaMultilibs; +} + static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -2198,7 +2234,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "s390x-suse-linux", "s390x-redhat-linux"}; static const char *const XtensaLibDirs[] = {"/lib"}; - static const char *const XtensaTriples[] = {"xtensa-unknown-elf"}; + static const char *const XtensaTriples[] = { + "xtensa-unknown-elf", "xtensa-esp32-elf", "xtensa-esp32s2-elf", + "xtensa-esp32s3-elf"}; using std::begin; using std::end; @@ -2502,6 +2540,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( findMSP430Multilibs(D, TargetTriple, Path, Args, Detected); } else if (TargetArch == llvm::Triple::avr) { // AVR has no multilibs. + } else if (TargetArch == llvm::Triple::xtensa) { + findXtensaMultilibs(D, TargetTriple, Path, Args, Detected); } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, NeedsBiarchSuffix, Detected)) { return false; diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 4e7d72e821ecc..c9739a0eddbe2 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -10,7 +10,6 @@ #include "Xtensa.h" #include "CommonArgs.h" -#include "clang/Driver/InputInfo.h" #include "clang/Basic/Cuda.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" @@ -31,58 +30,23 @@ using namespace llvm::opt; using tools::addMultilibFlag; -XtensaGCCToolchainDetector::XtensaGCCToolchainDetector( - const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args) { - std::string InstalledDir; - InstalledDir = D.getInstalledDir(); - StringRef CPUName = XtensaToolChain::GetTargetCPUVersion(Args); - std::string Dir; - std::string ToolchainName; - std::string ToolchainDir; - - if (CPUName.equals("esp32")) - ToolchainName = "xtensa-esp32-elf"; - else if (CPUName.equals("esp32-s2")) - ToolchainName = "xtensa-esp32s2-elf"; - else if (CPUName.equals("esp32-s3")) - ToolchainName = "xtensa-esp32s3-elf"; - else if (CPUName.equals("esp8266")) - ToolchainName = "xtensa-lx106-elf"; - - Slash = llvm::sys::path::get_separator().str(); - - ToolchainDir = InstalledDir + Slash + ".."; - Dir = ToolchainDir + Slash + "lib" + Slash + "gcc" + Slash + ToolchainName + - Slash; - GCCLibAndIncVersion = ""; - - if (D.getVFS().exists(Dir)) { - std::error_code EC; - for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - auto GCCVersion = Generic_GCC::GCCVersion::Parse(VersionText); - if (GCCVersion.Major == -1) - continue; - GCCLibAndIncVersion = GCCVersion.Text; - } - if (GCCLibAndIncVersion == "") - llvm_unreachable("Unexpected Xtensa GCC toolchain version"); - - } else { - // Unable to find Xtensa GCC toolchain; - GCCToolchainName = ""; - return; - } - GCCToolchainDir = ToolchainDir; - GCCToolchainName = ToolchainName; -} - /// Xtensa Toolchain XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args), XtensaGCCToolchain(D, getTriple(), Args) { + : Generic_ELF(D, Triple, Args) { + + GCCInstallation.init(Triple, Args); + + if (!GCCInstallation.isValid()) { + llvm_unreachable("Unexpected Xtensa GCC toolchain version"); + } + + GCCLibAndIncVersion = GCCInstallation.getVersion().Text; + GCCToolchainName = GCCInstallation.getTriple().str(); + SmallString<128> Path(GCCInstallation.getParentLibPath()); + llvm::sys::path::append(Path, ".."); + GCCToolchainDir = Path.c_str(); + for (auto *A : Args) { std::string Str = A->getAsString(Args); if (!Str.compare("-mlongcalls")) @@ -109,45 +73,18 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, IsIntegratedAsm = false; } - bool IsESP32 = XtensaToolChain::GetTargetCPUVersion(Args).equals("esp32"); - Multilibs.push_back(Multilib()); - if (IsESP32) - Multilibs.push_back(Multilib("esp32-psram", {}, {}, 2) - .flag("+mfix-esp32-psram-cache-issue")); - - Multilibs.push_back( - Multilib("no-rtti", {}, {}, 1).flag("+fno-rtti").flag("-frtti")); - - if (IsESP32) - Multilibs.push_back(Multilib("esp32-psram/no-rtti", {}, {}, 3) - .flag("+fno-rtti") - .flag("-frtti") - .flag("+mfix-esp32-psram-cache-issue")); - - Multilib::flags_list Flags; - addMultilibFlag( - Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, false), "frtti", - Flags); - - if (IsESP32) - addMultilibFlag(Args.hasFlag(options::OPT_mfix_esp32_psram_cache_issue, - options::OPT_mfix_esp32_psram_cache_issue, - false), - "mfix-esp32-psram-cache-issue", Flags); - - Multilibs.select(Flags, SelectedMultilib); - - const std::string Slash = XtensaGCCToolchain.Slash; - std::string Libs = - XtensaGCCToolchain.GCCToolchainDir + Slash + "lib" + Slash + "gcc" + - Slash + XtensaGCCToolchain.GCCToolchainName + Slash + - XtensaGCCToolchain.GCCLibAndIncVersion + SelectedMultilib.gccSuffix(); - getFilePaths().push_back(Libs); - - Libs = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + "lib" + - SelectedMultilib.gccSuffix(); - getFilePaths().push_back(Libs); + SmallString<128> Libs1(GCCToolchainDir); + llvm::sys::path::append(Libs1, "lib", "gcc", GCCToolchainName, + GCCLibAndIncVersion); + if (!SelectedMultilib.gccSuffix().empty()) + llvm::sys::path::append(Libs1, SelectedMultilib.gccSuffix()); + getFilePaths().push_back(Libs1.c_str()); + + SmallString<128> Libs2(GCCToolchainDir); + llvm::sys::path::append(Libs2, GCCToolchainName, "lib"); + if (!SelectedMultilib.gccSuffix().empty()) + llvm::sys::path::append(Libs2, SelectedMultilib.gccSuffix()); + getFilePaths().push_back(Libs2.c_str()); } Tool *XtensaToolChain::buildLinker() const { @@ -164,17 +101,15 @@ void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - if (!XtensaGCCToolchain.IsValid()) + if (!GCCInstallation.isValid()) return; - std::string Slash = XtensaGCCToolchain.Slash; - - std::string Path1 = getDriver().ResourceDir.c_str() + Slash + "include"; - std::string Path2 = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + - "sys-include"; - std::string Path3 = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + "include"; + SmallString<128> Path1(getDriver().ResourceDir); + llvm::sys::path::append(Path1, "include"); + SmallString<128> Path2(GCCToolchainDir); + llvm::sys::path::append(Path2, GCCToolchainName, "sys-include"); + SmallString<128> Path3(GCCToolchainDir); + llvm::sys::path::append(Path3, GCCToolchainName, "include"); const StringRef Paths[] = {Path1, Path2, Path3}; addSystemIncludes(DriverArgs, CC1Args, Paths); @@ -183,20 +118,20 @@ void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void XtensaToolChain::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - if (!XtensaGCCToolchain.IsValid()) + if (!GCCInstallation.isValid()) return; - std::string Slash = XtensaGCCToolchain.Slash; + SmallString<128> BaseDir(GCCToolchainDir); + llvm::sys::path::append(BaseDir, GCCToolchainName, "include", "c++", + GCCLibAndIncVersion); + SmallString<128> TargetDir(BaseDir); + llvm::sys::path::append(TargetDir, GCCToolchainName); + SmallString<128> TargetDirBackward(BaseDir); + llvm::sys::path::append(TargetDirBackward, "backward"); - std::string BaseDir = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + - "include" + Slash + "c++" + Slash + - XtensaGCCToolchain.GCCLibAndIncVersion; - std::string TargetDir = BaseDir + Slash + XtensaGCCToolchain.GCCToolchainName; addLibStdCXXIncludePaths(BaseDir, "", "", DriverArgs, CC1Args); addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); - TargetDir = BaseDir + Slash + "backward"; - addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); + addLibStdCXXIncludePaths(TargetDirBackward, "", "", DriverArgs, CC1Args); } ToolChain::CXXStdlibType @@ -212,6 +147,11 @@ XtensaToolChain::GetCXXStdlibType(const ArgList &Args) const { return ToolChain::CST_Libstdcxx; } +ToolChain::UnwindLibType +XtensaToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + return ToolChain::UNW_None; +} + const StringRef XtensaToolChain::GetTargetCPUVersion(const ArgList &Args) { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { StringRef CPUName = A->getValue(); @@ -228,7 +168,7 @@ void tools::Xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const auto &TC = static_cast(getToolChain()); - if (!TC.XtensaGCCToolchain.IsValid()) + if (TC.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC assembler"); claimNoWarnArgs(Args); @@ -255,13 +195,13 @@ void tools::Xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - std::string Slash = TC.XtensaGCCToolchain.Slash; + SmallString<128> Asm(TC.GCCToolchainDir); + llvm::sys::path::append(Asm, "bin", + TC.GCCToolchainName + "-" + getShortName()); - const char *Asm = - Args.MakeArgString(getToolChain().getDriver().Dir + Slash + - TC.XtensaGCCToolchain.GCCToolchainName + "-as"); - C.addCommand(std::make_unique( - JA, *this, ResponseFileSupport::AtFileCurCP(), Asm, CmdArgs, Inputs)); + C.addCommand( + std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Asm), CmdArgs, Inputs)); } void Xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -269,31 +209,63 @@ void Xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const auto &TC = - static_cast(getToolChain()); - std::string Slash = TC.XtensaGCCToolchain.Slash; + ArgStringList CmdArgs; + SmallString<128> Linker; + bool WantCRTs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + const auto &ToolChain = + static_cast(getToolChain()); - if (!TC.XtensaGCCToolchain.IsValid()) + if (ToolChain.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC linker"); - std::string Linker = getToolChain().getDriver().Dir + Slash + - TC.XtensaGCCToolchain.GCCToolchainName + "-ld"; - ArgStringList CmdArgs; + if (Args.hasArg(options::OPT_fuse_ld_EQ)) { + Linker.assign(ToolChain.GetLinkerPath()); + } else { + Linker.assign(ToolChain.GCCToolchainDir); + llvm::sys::path::append(Linker, "bin", + ToolChain.GCCToolchainName + "-" + getShortName()); + } - Args.AddAllArgs(CmdArgs, options::OPT_L); - TC.AddFilePathLibArgs(Args, CmdArgs); + const char *crtbegin, *crtend; + auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); + if (RuntimeLib == ToolChain::RLT_Libgcc) { + crtbegin = "crtbegin.o"; + crtend = "crtend.o"; + } else { + assert (RuntimeLib == ToolChain::RLT_CompilerRT); + crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", + ToolChain::FT_Object); + crtend = ToolChain.getCompilerRTArgString(Args, "crtend", + ToolChain::FT_Object); + } + + if (WantCRTs) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_u_Group}); + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + } - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - CmdArgs.push_back("-lgcc"); + if (WantCRTs) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand( - std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), - Args.MakeArgString(Linker), CmdArgs, Inputs)); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), + CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/ToolChains/Xtensa.h b/clang/lib/Driver/ToolChains/Xtensa.h index 663dc63f6d279..e2dff67c1a1b2 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.h +++ b/clang/lib/Driver/ToolChains/Xtensa.h @@ -20,19 +20,6 @@ namespace clang { namespace driver { namespace toolchains { -class XtensaGCCToolchainDetector { -public: - std::string GCCLibAndIncVersion; - std::string GCCToolchainName; - std::string GCCToolchainDir; - std::string Slash; - - XtensaGCCToolchainDetector(const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args); - - bool IsValid() const { return GCCToolchainName != ""; } -}; - class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { protected: Tool *buildLinker() const override; @@ -48,14 +35,18 @@ class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + bool IsIntegratedAssemblerDefault() const override { - return (IsIntegratedAsm || (XtensaGCCToolchain.GCCToolchainName == "")); + return (IsIntegratedAsm || (GCCToolchainName == "")); } static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); - XtensaGCCToolchainDetector XtensaGCCToolchain; bool IsIntegratedAsm = true; + std::string GCCLibAndIncVersion = ""; + std::string GCCToolchainName = ""; + std::string GCCToolchainDir = ""; }; } // end namespace toolchains @@ -65,7 +56,7 @@ namespace Xtensa { class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: Linker(const ToolChain &TC) - : Tool("Xtensa::Linker", "xtensa-esp32-elf-ld", TC) {} + : Tool("Xtensa::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, @@ -77,7 +68,7 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: Assembler(const ToolChain &TC) - : Tool("Xtensa::Assembler", "xtensa-esp32-elf-as", TC) {} + : Tool("Xtensa::Assembler", "as", TC) {} bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld new file mode 100755 index 0000000000000..b23e55619b2ff --- /dev/null +++ b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/xtensa-toolchain.c b/clang/test/Driver/xtensa-toolchain.c new file mode 100644 index 0000000000000..245e09902f0f8 --- /dev/null +++ b/clang/test/Driver/xtensa-toolchain.c @@ -0,0 +1,42 @@ +// A basic clang -cc1 command-line, and simple environment check. + +// RUN: %clang %s -### -no-canonical-prefixes -target xtensa \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=CC1 %s +// CC1: clang{{.*}} "-cc1" "-triple" "xtensa" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL %s + +// C-XTENSA-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" +// C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -frtti 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-RTTI %s + +// C-XTENSA-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0" +// C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM %s + +// C-XTENSA-BAREMETAL-PSRAM: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram/no-rtti" +// C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue -frtti 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM-RTTI %s + +// C-XTENSA-BAREMETAL-PSRAM-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram" +// C-XTENSA-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram" diff --git a/lld/ELF/Arch/Xtensa.cpp b/lld/ELF/Arch/Xtensa.cpp new file mode 100644 index 0000000000000..b122fb590e11e --- /dev/null +++ b/lld/ELF/Arch/Xtensa.cpp @@ -0,0 +1,125 @@ +//===- Xtensa.cpp ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { + +class Xtensa final : public TargetInfo { +public: + Xtensa(); + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; +}; + +} // namespace + +Xtensa::Xtensa() { noneRel = R_XTENSA_NONE; } + +RelExpr Xtensa::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_XTENSA_32: + return R_ABS; + case R_XTENSA_SLOT0_OP: + // This relocation is used for various instructions, with varying ways to + // calculate the relocation value. This is unlike most ELF architectures, + // and is arguably bad design (see the comment on R_386_GOT32 in X86.cpp). + // But that's what compilers emit, so it needs to be supported. + // + // We work around this by returning R_PC here and calculating the PC address + // in Xtensa::relocate based on the relative value. That's ugly. A better + // solution would be to look at the instruction here and emit various + // Xtensa-specific RelTypes, but that has another problem: the RelExpr enum + // is at its maximum size of 64. This will need to be fixed eventually, but + // for now hack around it and return R_PC. + return R_PC; + case R_XTENSA_ASM_EXPAND: + // This relocation appears to be emitted by the GNU Xtensa compiler as a + // linker relaxation hint. For example, for the following code: + // + // .section .foo + // .align 4 + // foo: + // nop + // nop + // call0 bar + // .align 4 + // bar: + // + // The call0 instruction is compiled to a l32r and callx0 instruction. + // The LLVM Xtensa backend does not emit this relocation. + // Because it's a relaxation hint, this relocation can be ignored for now + // until linker relaxations are implemented. + return R_NONE; + default: + error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + + ") against symbol " + toString(s)); + return R_NONE; + } +} + +void Xtensa::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + switch (rel.type) { + case R_XTENSA_32: + write32le(loc, val); + break; + case R_XTENSA_SLOT0_OP: { + // HACK: calculate the instruction location based on the PC-relative + // relocation value. + uint64_t dest = rel.sym->getVA(rel.addend); + uint64_t p = dest - val; + + // This relocation is used for various instructions. + // Look at the instruction to determine how to do the relocation. + uint8_t opcode = loc[0] & 0x0f; + if (opcode == 0b0001) { // l32r + uint64_t val = dest - ((p + 3) & (uint64_t)0xfffffffc); + checkInt(loc, static_cast(val) >> 2, 16, rel); + checkAlignment(loc, val, 4, rel); + write16le(loc + 1, static_cast(val) >> 2); + } else if (opcode == 0b0101) { // call0, call4, call8, call12 + uint64_t val = dest - ((p + 4) & (uint64_t)0xfffffffc); + checkInt(loc, static_cast(val) >> 2, 18, rel); + checkAlignment(loc, val, 4, rel); + const int64_t target = static_cast(val) >> 2; + loc[0] = (loc[0] & 0b0011'1111) | ((target & 0b0000'0011) << 6); + loc[1] = target >> 2; + loc[2] = target >> 10; + } else if ((loc[0] & 0x3f) == 0b00'0110) { // j + uint64_t val = dest - p + 4; + checkInt(loc, static_cast(val), 18, rel); + loc[0] = (loc[0] & 0b0011'1111) | ((val & 0b0000'0011) << 6); + loc[1] = val >> 2; + loc[2] = val >> 10; + } else { + error(getErrorLocation(loc) + + "unknown opcode for relocation: " + std::to_string(opcode)); + } + break; + } + default: + llvm_unreachable("unknown relocation"); + } +} + +TargetInfo *elf::getXtensaTargetInfo() { + static Xtensa target; + return ⌖ +} diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index f85d0fb9f55e3..58076511c1b98 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -18,6 +18,7 @@ add_lld_library(lldELF Arch/SPARCV9.cpp Arch/X86.cpp Arch/X86_64.cpp + Arch/Xtensa.cpp ARMErrataFix.cpp CallGraphSort.cpp DWARF.cpp diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index d5b9efbe18fc5..a4cb398622517 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1649,6 +1649,8 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) { return t.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; + case Triple::xtensa: + return EM_XTENSA; default: error(path + ": could not infer e_machine from bitcode target triple " + t.str()); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index d3e54f7387d7d..043fc10a863b5 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -87,6 +87,8 @@ TargetInfo *elf::getTarget() { return getSPARCV9TargetInfo(); case EM_X86_64: return getX86_64TargetInfo(); + case EM_XTENSA: + return getXtensaTargetInfo(); } llvm_unreachable("unknown target machine"); } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 1fe3217c6d1dc..88e69a8f65778 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -183,6 +183,7 @@ TargetInfo *getRISCVTargetInfo(); TargetInfo *getSPARCV9TargetInfo(); TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); +TargetInfo *getXtensaTargetInfo(); template TargetInfo *getMipsTargetInfo(); struct ErrorPlace { diff --git a/lld/test/ELF/xtensa-reloc.s b/lld/test/ELF/xtensa-reloc.s new file mode 100644 index 0000000000000..7007756aa2a89 --- /dev/null +++ b/lld/test/ELF/xtensa-reloc.s @@ -0,0 +1,17 @@ +# REQUIRES: xtensa +# RUN: llvm-mc -filetype=obj -triple=xtensa -mcpu=esp32 %s -o %t.o +# RUN: ld.lld %t.o --defsym=a=0x2000 --section-start=.CALL=0x1000 --defsym=b=40 -o %t +# RUN: llvm-objdump -d --print-imm-hex %t | FileCheck %s + +.section .CALL,"ax",@progbits +# CHECK-LABEL: section .CALL: +# CHECK: call0 . +4096 +# CHECK-NEXT: call0 . +4096 +# CHECK-NEXT: call0 . +4092 +# CHECK-NEXT: call0 . +4088 +# CHECK-NEXT: call0 . -4068 + call0 a + call0 a + call0 a + call0 a + call0 b diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py index 225104243bf26..654450e018f04 100644 --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -76,7 +76,8 @@ 'RISCV': 'riscv', 'Sparc': 'sparc', 'WebAssembly': 'wasm', - 'X86': 'x86'}) + 'X86': 'x86', + 'Xtensa': 'xtensa'}) ]) # Set a fake constant version so that we get consistent output.