diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -92,6 +92,10 @@ for (const auto &II : Inputs) if (II.isFilename()) CmdArgs.push_back(II.getFilename()); + AddStaticDeviceLibs(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn", + SubArchName, + /* bitcode SDL?*/ true, + /* PostClang Link? */ false); // Add an intermediate output file. CmdArgs.push_back("-o"); const char *OutputFileName = diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -49,6 +49,38 @@ llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); +void AddStaticDeviceLibs(Compilation &C, const Tool &T, const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, StringRef ArchName, + StringRef GPUArch, bool isBitCodeSDL, + bool postClangLink); +void AddStaticDeviceLibs(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, StringRef ArchName, + StringRef GPUArch, bool isBitCodeSDL, + bool postClangLink); +void AddStaticDeviceLibs(Compilation *C, const Tool *T, const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, StringRef ArchName, + StringRef GPUArch, bool isBitCodeSDL, + bool postClangLink); + +bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + SmallVector LibraryPaths, std::string libname, + StringRef ArchName, StringRef GPUArch, bool isBitCodeSDL, + bool postClangLink); + +bool GetSDLFromOffloadArchive(Compilation &C, const Driver &D, const Tool &T, + const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + SmallVector LibraryPaths, + std::string libname, StringRef ArchName, + StringRef GPUArch, bool isBitCodeSDL, + bool postClangLink); + const char *SplitDebugName(const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1587,6 +1587,236 @@ } } +/// SDLSearch: Search for Static Device Library +bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + SmallVector LibraryPaths, + std::string libname, StringRef ArchName, + StringRef GPUArch, bool isBitCodeSDL, + bool postClangLink) { + std::string archname = ArchName.str(); + std::string Target = GPUArch.str(); + + SmallVector SDL_FileNames; + if (isBitCodeSDL) { + // For bitcode SDL, search for these 12 relative SDL filenames + SDL_FileNames.push_back(std::string("/libdevice/libbc-" + libname + "-" + + archname + "-" + Target + ".a")); + SDL_FileNames.push_back(std::string("/libbc-" + libname + "-" + archname + + "-" + Target + ".a")); + SDL_FileNames.push_back( + std::string("/libdevice/libbc-" + libname + "-" + archname + ".a")); + SDL_FileNames.push_back( + std::string("/libbc-" + libname + "-" + archname + ".a")); + SDL_FileNames.push_back(std::string("/libdevice/libbc-" + libname + ".a")); + SDL_FileNames.push_back(std::string("/libbc-" + libname + ".a")); + SDL_FileNames.push_back(std::string("/libdevice/lib" + libname + "-" + + archname + "-" + Target + ".bc")); + SDL_FileNames.push_back( + std::string("/lib" + libname + "-" + archname + "-" + Target + ".bc")); + SDL_FileNames.push_back( + std::string("/libdevice/lib" + libname + "-" + archname + ".bc")); + SDL_FileNames.push_back( + std::string("/lib" + libname + "-" + archname + ".bc")); + SDL_FileNames.push_back(std::string("/libdevice/lib" + libname + ".bc")); + SDL_FileNames.push_back(std::string("/lib" + libname + ".bc")); + } else { + // Otherwise only 4 names to search for machine-code SDL + SDL_FileNames.push_back(std::string("/libdevice/lib" + libname + "-" + + archname + "-" + Target + ".a")); + SDL_FileNames.push_back( + std::string("/lib" + libname + "-" + archname + "-" + Target + ".a")); + SDL_FileNames.push_back( + std::string("/libdevice/lib" + libname + "-" + archname + ".a")); + SDL_FileNames.push_back( + std::string("/lib" + libname + "-" + archname + ".a")); + } + + // Add file for archive of bundles, this is the final fallback + bool FoundSDL = false; + for (std::string LibraryPath : LibraryPaths) { + for (std::string SDL_FileName : SDL_FileNames) { + std::string FullName = std::string(LibraryPath + SDL_FileName); + if (llvm::sys::fs::exists(FullName)) { + if (postClangLink) + CC1Args.push_back("-mlink-builtin-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(FullName)); + FoundSDL = true; + break; + } + } + if (FoundSDL) + break; + } + + return FoundSDL; +} + +bool tools::GetSDLFromOffloadArchive( + Compilation &C, const Driver &D, const Tool &T, const JobAction &JA, + const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, SmallVector LibraryPaths, + std::string libname, StringRef ArchName, StringRef GPUArch, + bool isBitCodeSDL, bool postClangLink) { + std::string archname = ArchName.str(); + std::string gpuname = GPUArch.str(); + + // We don't support bitcode archive bundles for nvptx + if (isBitCodeSDL && archname == "nvptx") + return false; + + bool FoundAOB = false; + SmallVector AOBFileNames; + std::string ArchiveOfBundles; + for (std::string LibraryPath : LibraryPaths) { + AOBFileNames.push_back( + std::string(LibraryPath + "/libdevice/lib" + libname + ".a")); + AOBFileNames.push_back(std::string(LibraryPath + "/lib" + libname + ".a")); + + for (auto AOB : AOBFileNames) { + if (llvm::sys::fs::exists(AOB)) { + ArchiveOfBundles = AOB; + FoundAOB = true; + break; + } + } + + if (FoundAOB) { + std::string Err; + std::string OutputLib = D.GetTemporaryPath( + isBitCodeSDL ? "libbc-" + libname + "-" + archname + "-" + gpuname + : "lib" + libname + "-" + archname + "-" + gpuname, + "a"); + + C.addTempFile(C.getArgs().MakeArgString(OutputLib.c_str())); + + ArgStringList CmdArgs; + SmallString<128> DeviceTriple; + DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); + DeviceTriple += "-"; + std::string NormalizedTriple = T.getToolChain().getTriple().normalize(); + DeviceTriple += NormalizedTriple; + if (!GPUArch.empty()) { + // If GPUArch is present it can only appear as the 6th hypen + // sepearated field of Bundle Entry ID. So, pad required number of + // hyphens in Triple. + for (int i = 4 - StringRef(NormalizedTriple).count("-"); i > 0; i--) + DeviceTriple += "-"; + DeviceTriple += GPUArch; + } + + std::string UnbundleArg("-unbundle"); + std::string TypeArg("-type=a"); + std::string InputArg("-inputs=" + ArchiveOfBundles); + std::string OffloadArg("-targets=" + std::string(DeviceTriple)); + std::string OutputArg("-outputs=" + OutputLib); + + const char *UBProgram = DriverArgs.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + + ArgStringList UBArgs; + UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(TypeArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(InputArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(OutputArg.c_str())); + + // Add this flag to not exit from clang-offload-bundler if no compatible + // code object is found in heterogenous archive library. + std::string AdditionalArgs("-allow-missing-bundles"); + UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs.c_str())); + + C.addCommand(std::make_unique( + JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, + InputInfo(&JA, C.getArgs().MakeArgString(OutputLib.c_str())))); + if (postClangLink) + CC1Args.push_back("-mlink-builtin-bitcode"); + + CC1Args.push_back(DriverArgs.MakeArgString(OutputLib)); + break; + } + } + + return FoundAOB; +} + +void tools::AddStaticDeviceLibs(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef ArchName, StringRef GPUArch, + bool isBitCodeSDL, bool postClangLink) { + AddStaticDeviceLibs(&C, &T, &JA, &Inputs, C.getDriver(), DriverArgs, CC1Args, + ArchName, GPUArch, isBitCodeSDL, postClangLink); +} + +void tools::AddStaticDeviceLibs(const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef ArchName, StringRef GPUArch, + bool isBitCodeSDL, bool postClangLink) { + AddStaticDeviceLibs(nullptr, nullptr, nullptr, nullptr, D, DriverArgs, + CC1Args, ArchName, GPUArch, isBitCodeSDL, postClangLink); +} + +void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T, + const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef ArchName, StringRef GPUArch, + bool isBitCodeSDL, bool postClangLink) { + + SmallVector LibraryPaths; + // Add search directories from LIBRARY_PATH env variable + llvm::Optional LibPath = + llvm::sys::Process::GetEnv("LIBRARY_PATH"); + if (LibPath) { + SmallVector Frags; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + llvm::SplitString(*LibPath, Frags, EnvPathSeparatorStr); + for (StringRef Path : Frags) + LibraryPaths.emplace_back(Path.trim()); + } + + // Add directories from user-specified -L options + for (std::string Search_Dir : DriverArgs.getAllArgValues(options::OPT_L)) + LibraryPaths.emplace_back(Search_Dir); + + // Add path to lib-debug folders + SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); + llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); + LibraryPaths.emplace_back(DefaultLibPath.c_str()); + + // Build list of Static Device Libraries SDLs specified by -l option + SmallVector SDL_Names; + for (std::string SDL_Name : DriverArgs.getAllArgValues(options::OPT_l)) { + // No Device specific SDL for these libs: omp,cudart,m,gcc,gcc_s,pthread + if (SDL_Name != "omp" && SDL_Name != "cudart" && SDL_Name != "m" && + SDL_Name != "gcc" && SDL_Name != "gcc_s" && SDL_Name != "pthread" && + SDL_Name != "hip_hcc") { + bool inSDL_Names = false; + for (std::string OldName : SDL_Names) { + if (OldName == SDL_Name) + inSDL_Names = true; + } + if (!inSDL_Names) // Avoid duplicates in list of SDL_Names + SDL_Names.emplace_back(SDL_Name); + } + } + + for (std::string SDL_Name : SDL_Names) { + // THIS IS THE ONLY CALL TO SDLSearch + if (!(SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDL_Name, ArchName, + GPUArch, isBitCodeSDL, postClangLink))) { + GetSDLFromOffloadArchive(*C, D, *T, *JA, *Inputs, DriverArgs, CC1Args, + LibraryPaths, SDL_Name, ArchName, GPUArch, + isBitCodeSDL, postClangLink); + } + } +} + static llvm::opt::Arg * getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) { // The last of -mcode-object-v3, -mno-code-object-v3 and diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -632,6 +632,9 @@ CmdArgs.push_back(CubinF); } + AddStaticDeviceLibs(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", GPUArch, + false, false); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); C.addCommand(std::make_unique( @@ -754,6 +757,8 @@ std::string BitcodeSuffix = "nvptx-" + GpuArch.str(); addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, getTriple()); + AddStaticDeviceLibs(getDriver(), DriverArgs, CC1Args, "nvptx", GpuArch, + /* bitcode SDL?*/ true, /* PostClang Link? */ true); } }