Index: clang/lib/Driver/ToolChains/AVR.h =================================================================== --- clang/lib/Driver/ToolChains/AVR.h +++ clang/lib/Driver/ToolChains/AVR.h @@ -33,12 +33,14 @@ llvm::Optional findAVRLibcInstallation() const; StringRef getGCCInstallPath() const { return GCCInstallPath; } + std::string getCompilerRTPath() const override; protected: Tool *buildLinker() const override; private: StringRef GCCInstallPath; + std::string MCU; }; } // end namespace toolchains Index: clang/lib/Driver/ToolChains/AVR.cpp =================================================================== --- clang/lib/Driver/ToolChains/AVR.cpp +++ clang/lib/Driver/ToolChains/AVR.cpp @@ -19,6 +19,7 @@ #include "llvm/MC/SubtargetFeature.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -369,8 +370,8 @@ : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); - std::string CPU = getCPUName(D, Args, Triple); - if (CPU.empty()) + MCU = getCPUName(D, Args, Triple); + if (MCU.empty()) D.Diag(diag::warn_drv_avr_mcu_not_specified); // Only add default libraries if the user hasn't explicitly opted out. @@ -418,6 +419,19 @@ return new tools::AVR::Linker(getTriple(), *this); } +std::string AVRToolChain::getCompilerRTPath() const { + // Return the default path appended with device family name, such as + // `$RESOURCE_DIR/lib/avr5`, since we expect each device family has its + // own optimized compiler-rt library files. + // If no `-mmcu=` is specified, it falls back to the default path. However + // this is unexpected, since avr can not be a host environment. + SmallString<128> Path(ToolChain::getCompilerRTPath()); + Optional FamilyName = GetMCUFamilyName(MCU); + if (FamilyName) + llvm::sys::path::append(Path, *FamilyName); + return std::string(Path.str()); +} + void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -447,6 +461,12 @@ Args.AddAllArgs(CmdArgs, options::OPT_L); getToolChain().AddFilePathLibArgs(Args, CmdArgs); + // Currently we only support libgcc and compiler-rt. + auto RtLib = TC.GetRuntimeLibType(Args); + assert( + (RtLib == ToolChain::RLT_Libgcc || RtLib == ToolChain::RLT_CompilerRT) && + "unknown runtime library"); + // Only add default libraries if the user hasn't explicitly opted out. bool LinkStdlib = false; if (!Args.hasArg(options::OPT_nostdlib) && @@ -462,10 +482,13 @@ D.Diag(diag::warn_drv_avr_libc_not_found); } else { std::string SubPath = GetMCUSubPath(CPU); + // Add path of avr-libc. CmdArgs.push_back( Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath)); - CmdArgs.push_back( - Args.MakeArgString("-L" + TC.getGCCInstallPath() + "/" + SubPath)); + // Add path of libgcc. + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back(Args.MakeArgString("-L" + TC.getGCCInstallPath() + + "/" + SubPath)); LinkStdlib = true; } } @@ -494,7 +517,11 @@ std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); CmdArgs.push_back(Args.MakeArgString(CrtFileName)); - CmdArgs.push_back("-lgcc"); + // Link to libgcc. + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back("-lgcc"); + + // Link to generic libraries of avr-libc. CmdArgs.push_back("-lm"); CmdArgs.push_back("-lc"); @@ -503,6 +530,14 @@ CmdArgs.push_back("--end-group"); + // Link to compiler-rt. + if (RtLib == ToolChain::RLT_CompilerRT) { + std::string RtLib = + getToolChain().getCompilerRT(Args, "builtins", ToolChain::FT_Static); + if (llvm::sys::fs::exists(RtLib)) + CmdArgs.push_back(Args.MakeArgString(RtLib)); + } + // Add user specified linker script. Args.AddAllArgs(CmdArgs, options::OPT_T); Index: clang/test/Driver/avr-toolchain.c =================================================================== --- clang/test/Driver/avr-toolchain.c +++ clang/test/Driver/avr-toolchain.c @@ -72,3 +72,17 @@ // RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree -mmcu=atmega328 %s -fuse-ld=lld -T avr.lds 2>&1 | FileCheck --check-prefix=LDS1 %s // LDS1: "-T" "avr.lds" // LDS1-NOT: "-mavr5" + +// RUN: %clang %s -### --target=avr -mmcu=atmega328 --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir 2>&1 | FileCheck --check-prefix=LIBGCC %s +// RUN: %clang %s -### --target=avr -mmcu=atmega328 --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=libgcc 2>&1 | FileCheck --check-prefix=LIBGCC %s +// LIBGCC: "-lgcc" +// LIBGCC-NOT: libclang_rt + +// RUN: %clang %s -### --target=avr -mmcu=atmega328 --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=compiler-rt 2>&1 | FileCheck --check-prefix=COMRT %s +// COMRT: avr5/libclang_rt.builtins-avr.a +// COMRT-NOT: "-lgcc" + +// RUN: %clang %s -### --target=avr --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=compiler-rt 2>&1 | FileCheck --check-prefix=NOMCU %s +// RUN: %clang %s -### --target=avr --sysroot=%S/Inputs/basic_avr_tree/ -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir --rtlib=libgcc 2>&1 | FileCheck --check-prefix=NOMCU %s +// NOMCU-NOT: libclang_rt +// NOMCU-NOT: "-lgcc"