Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -586,6 +586,10 @@ def fcuda_short_ptr : Flag<["-"], "fcuda-short-ptr">, Flags<[CC1Option]>, HelpText<"Use 32-bit pointers for accessing const/local/shared address spaces.">; def fno_cuda_short_ptr : Flag<["-"], "fno-cuda-short-ptr">; +def hip_device_lib_path_EQ : Joined<["--"], "hip-device-lib-path=">, Group, + HelpText<"HIP device library path">; +def hip_device_lib_EQ : Joined<["--"], "hip-device-lib=">, Group, + HelpText<"HIP device library">; def fhip_dump_offload_linker_script : Flag<["-"], "fhip-dump-offload-linker-script">, Group, Flags<[NoArgumentUnused, HelpHidden]>; def dA : Flag<["-"], "dA">, Group; Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -45,6 +45,7 @@ ToolChains/Fuchsia.cpp ToolChains/Gnu.cpp ToolChains/Haiku.cpp + ToolChains/HIP.cpp ToolChains/Hexagon.cpp ToolChains/Linux.cpp ToolChains/MipsLinux.cpp Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -12,6 +12,7 @@ #include "ToolChains/AMDGPU.h" #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" +#include "ToolChains/BareMetal.h" #include "ToolChains/Clang.h" #include "ToolChains/CloudABI.h" #include "ToolChains/Contiki.h" @@ -22,15 +23,15 @@ #include "ToolChains/FreeBSD.h" #include "ToolChains/Fuchsia.h" #include "ToolChains/Gnu.h" -#include "ToolChains/BareMetal.h" +#include "ToolChains/HIP.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" #include "ToolChains/Lanai.h" #include "ToolChains/Linux.h" +#include "ToolChains/MSVC.h" #include "ToolChains/MinGW.h" #include "ToolChains/Minix.h" #include "ToolChains/MipsLinux.h" -#include "ToolChains/MSVC.h" #include "ToolChains/Myriad.h" #include "ToolChains/NaCl.h" #include "ToolChains/NetBSD.h" @@ -70,9 +71,9 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/StringSaver.h" #include #include #include @@ -540,7 +541,7 @@ // // CUDA/HIP // - // We need to generate a CUDA toolchain if any of the inputs has a CUDA + // We need to generate a CUDA/HIP toolchain if any of the inputs has a CUDA // or HIP type. However, mixed CUDA/HIP compilation is not supported. bool IsCuda = llvm::any_of(Inputs, [](std::pair &I) { @@ -556,21 +557,15 @@ Diag(clang::diag::err_drv_mix_cuda_hip); return; } - if (IsCuda || IsHIP) { + if (IsCuda) { const ToolChain *HostTC = C.getSingleOffloadToolChain(); const llvm::Triple &HostTriple = HostTC->getTriple(); StringRef DeviceTripleStr; - auto OFK = IsHIP ? Action::OFK_HIP : Action::OFK_Cuda; - if (IsHIP) { - // HIP is only supported on amdgcn. - DeviceTripleStr = "amdgcn-amd-amdhsa"; - } else { - // CUDA is only supported on nvptx. - DeviceTripleStr = HostTriple.isArch64Bit() ? "nvptx64-nvidia-cuda" - : "nvptx-nvidia-cuda"; - } + auto OFK = Action::OFK_Cuda; + DeviceTripleStr = + HostTriple.isArch64Bit() ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda"; llvm::Triple CudaTriple(DeviceTripleStr); - // Use the CUDA/HIP and host triples as the key into the ToolChains map, + // Use the CUDA and host triples as the key into the ToolChains map, // because the device toolchain we create depends on both. auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()]; if (!CudaTC) { @@ -578,6 +573,21 @@ *this, CudaTriple, *HostTC, C.getInputArgs(), OFK); } C.addOffloadDeviceToolChain(CudaTC.get(), OFK); + } else if (IsHIP) { + const ToolChain *HostTC = C.getSingleOffloadToolChain(); + const llvm::Triple &HostTriple = HostTC->getTriple(); + StringRef DeviceTripleStr; + auto OFK = Action::OFK_HIP; + DeviceTripleStr = "amdgcn-amd-amdhsa"; + llvm::Triple HIPTriple(DeviceTripleStr); + // Use the HIP and host triples as the key into the ToolChains map, + // because the device toolchain we create depends on both. + auto &HIPTC = ToolChains[HIPTriple.str() + "/" + HostTriple.str()]; + if (!HIPTC) { + HIPTC = llvm::make_unique( + *this, HIPTriple, *HostTC, C.getInputArgs()); + } + C.addOffloadDeviceToolChain(HIPTC.get(), OFK); } // Index: lib/Driver/ToolChains/HIP.h =================================================================== --- /dev/null +++ lib/Driver/ToolChains/HIP.h @@ -0,0 +1,123 @@ +//===--- HIP.h - HIP ToolChain Implementations ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H + +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Tool.h" + +namespace clang { +namespace driver { + +namespace tools { + +namespace AMDGCN { +// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with +// device library, then compiles it to ISA in a shared object. +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("AMDGCN::Linker", "amdgcn-link", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; + +private: + /// \return llvm-link output file name. + const char *constructLLVMLinkCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix) const; + + /// \return opt output file name. + const char *constructOptCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix, + const char *InputFileName) const; + + /// \return llc output file name. + const char *constructLlcCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix, + const char *InputFileName) const; + + void constructLldCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, const InputInfo &Output, + const llvm::opt::ArgList &Args, + const char *InputFileName) const; +}; + +} // end namespace AMDGCN +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HIPToolChain : public ToolChain { +public: + HIPToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + + bool useIntegratedAs() const override { return true; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + bool IsMathErrnoDefault() const override { return false; } + + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; + void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + SanitizerMask getSupportedSanitizers() const override; + + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + + const ToolChain &HostTC; + +protected: + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H Index: lib/Driver/ToolChains/HIP.cpp =================================================================== --- /dev/null +++ lib/Driver/ToolChains/HIP.cpp @@ -0,0 +1,351 @@ +//===--- HIP.cpp - HIP Tool and ToolChain Implementations -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "HIP.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Basic/Cuda.h" +#include "clang/Driver/Compilation.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; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +namespace { + +static bool addBCLib(Compilation &C, const ArgList &Args, + ArgStringList &CmdArgs, ArgStringList LibraryPaths, + StringRef BCName) { + StringRef FullName; + bool FoundLibDevice = false; + for (std::string LibraryPath : LibraryPaths) { + SmallString<128> Path(LibraryPath); + llvm::sys::path::append(Path, BCName); + FullName = Path; + if (llvm::sys::fs::exists(FullName)) { + FoundLibDevice = true; + break; + } + } + if (!FoundLibDevice) + C.getDriver().Diag(diag::err_drv_no_such_file) << BCName; + CmdArgs.push_back(Args.MakeArgString(FullName)); + return FoundLibDevice; +} + +} // namespace + +const char *AMDGCN::Linker::constructLLVMLinkCommand( + Compilation &C, const JobAction &JA, const InputInfoList &Inputs, + const ArgList &Args, StringRef SubArchName, + StringRef OutputFilePrefix) const { + ArgStringList CmdArgs; + // Add the input bc's created by compile step. + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + ArgStringList LibraryPaths; + + // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. + for (auto Path : Args.getAllArgValues(options::OPT_hip_device_lib_path_EQ)) + LibraryPaths.push_back(Args.MakeArgString(Path)); + + addDirectoryList(Args, LibraryPaths, "-L", "HIP_DEVICE_LIB_PATH"); + + llvm::SmallVector BCLibs; + + // Add bitcode library in --hip-device-lib. + for (auto Lib : Args.getAllArgValues(options::OPT_hip_device_lib_EQ)) { + BCLibs.push_back(Args.MakeArgString(Lib)); + } + + // If --hip-device-lib is not set, add the default bitcode libraries. + if (BCLibs.empty()) { + // Get the bc lib file name for ISA version. For example, + // gfx803 => oclc_isa_version_803.amdgcn.bc. + std::string ISAVerBC = "oclc_isa_version_"; + ISAVerBC = ISAVerBC + SubArchName.drop_front(3).str(); + ISAVerBC = ISAVerBC + ".amdgcn.bc"; + + BCLibs.append({"hip.amdgcn.bc", "opencl.amdgcn.bc", "ockl.amdgcn.bc", + "irif.amdgcn.bc", "ocml.amdgcn.bc", + "oclc_finite_only_off.amdgcn.bc", + "oclc_daz_opt_off.amdgcn.bc", + "oclc_correctly_rounded_sqrt_on.amdgcn.bc", + "oclc_unsafe_math_off.amdgcn.bc", "hc.amdgcn.bc", ISAVerBC}); + } + for (auto Lib : BCLibs) + addBCLib(C, Args, CmdArgs, LibraryPaths, Lib); + + // Add an intermediate output file. + CmdArgs.push_back("-o"); + std::string TmpName = + C.getDriver().GetTemporaryPath(OutputFilePrefix.str() + "-linked", "bc"); + const char *OutputFileName = + C.addTempFile(C.getArgs().MakeArgString(TmpName)); + CmdArgs.push_back(OutputFileName); + SmallString<128> ExecPath(C.getDriver().Dir); + llvm::sys::path::append(ExecPath, "llvm-link"); + const char *Exec = Args.MakeArgString(ExecPath); + C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); + return OutputFileName; +} + +const char *AMDGCN::Linker::constructOptCommand( + Compilation &C, const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix, const char *InputFileName) const { + // Construct opt command. + ArgStringList OptArgs; + // The input to opt is the output from llvm-link. + OptArgs.push_back(InputFileName); + // Pass optimization arg to opt. + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + StringRef OOpt = "3"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) { + // -Os, -Oz, and -O(anything else) map to -O2 + OOpt = llvm::StringSwitch(A->getValue()) + .Case("1", "1") + .Case("2", "2") + .Case("3", "3") + .Case("s", "2") + .Case("z", "2") + .Default("2"); + } + OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + } + OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); + OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); + OptArgs.push_back("-o"); + std::string TmpFileName = C.getDriver().GetTemporaryPath( + OutputFilePrefix.str() + "-optimized", "bc"); + const char *OutputFileName = + C.addTempFile(C.getArgs().MakeArgString(TmpFileName)); + OptArgs.push_back(OutputFileName); + SmallString<128> OptPath(C.getDriver().Dir); + llvm::sys::path::append(OptPath, "opt"); + const char *OptExec = Args.MakeArgString(OptPath); + C.addCommand(llvm::make_unique(JA, *this, OptExec, OptArgs, Inputs)); + return OutputFileName; +} + +const char *AMDGCN::Linker::constructLlcCommand( + Compilation &C, const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix, const char *InputFileName) const { + // Construct llc command. + ArgStringList LlcArgs; + LlcArgs.push_back(InputFileName); + LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); + LlcArgs.push_back("-filetype=obj"); + LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); + LlcArgs.push_back("-o"); + std::string LlcOutputFileName = + C.getDriver().GetTemporaryPath(OutputFilePrefix, "o"); + const char *LlcOutputFile = + C.addTempFile(C.getArgs().MakeArgString(LlcOutputFileName)); + LlcArgs.push_back(LlcOutputFile); + SmallString<128> LlcPath(C.getDriver().Dir); + llvm::sys::path::append(LlcPath, "llc"); + const char *Llc = Args.MakeArgString(LlcPath); + C.addCommand(llvm::make_unique(JA, *this, Llc, LlcArgs, Inputs)); + return LlcOutputFile; +} + +void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args, + const char *InputFileName) const { + // Construct lld command. + ArgStringList LldArgs; + // The output from ld.lld is an HSA code object file. + LldArgs.append({"-flavor", "gnu", "--no-undefined", "-shared", "-o"}); + LldArgs.push_back(Output.getFilename()); + LldArgs.push_back(InputFileName); + SmallString<128> LldPath(C.getDriver().Dir); + llvm::sys::path::append(LldPath, "lld"); + const char *Lld = Args.MakeArgString(LldPath); + C.addCommand(llvm::make_unique(JA, *this, Lld, LldArgs, Inputs)); +} + +// For amdgcn the inputs of the linker job are device bitcode and output is +// object file. It calls llvm-link, opt, llc, then lld steps. +void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + + const auto &TC = + static_cast(getToolChain()); + assert(TC.getTriple().getArch() == llvm::Triple::amdgcn && + "Unsupported target"); + + std::string SubArchName = JA.getOffloadingArch(); + assert(StringRef(SubArchName).startswith("gfx") && "Unsupported sub arch"); + + // Prefix for temporary file name. + std::string Prefix = + llvm::sys::path::stem(Inputs[0].getFilename()).str() + "-" + SubArchName; + + const char *TempFile = + constructLLVMLinkCommand(C, JA, Inputs, Args, SubArchName, Prefix); + TempFile = + constructOptCommand(C, JA, Inputs, Args, SubArchName, Prefix, TempFile); + TempFile = + constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, TempFile); + constructLldCommand(C, JA, Inputs, Output, Args, TempFile); +} + +HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) + : ToolChain(D, Triple, Args), HostTC(HostTC) { + // Lookup binaries into the driver directory, this is used to + // discover the clang-offload-bundler executable. + getProgramPaths().push_back(getDriver().Dir); +} + +void HIPToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); + + StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GpuArch.empty() && "Must have an explicit GPU arch."); + assert(DeviceOffloadingKind == Action::OFK_HIP && + "Only HIP offloading kinds are supported for GPUs."); + + CC1Args.push_back("-fcuda-is-device"); + + if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, false)) + CC1Args.push_back("-fcuda-flush-denormals-to-zero"); + + if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, + options::OPT_fno_cuda_approx_transcendentals, false)) + CC1Args.push_back("-fcuda-approx-transcendentals"); + + if (DriverArgs.hasFlag(options::OPT_fcuda_rdc, options::OPT_fno_cuda_rdc, + false)) + CC1Args.push_back("-fcuda-rdc"); +} + +llvm::opt::DerivedArgList * +HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_Xarch__)) { + // Skip this argument unless the architecture matches BoundArch + if (BoundArch.empty() || A->getValue(0) != BoundArch) + continue; + + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + unsigned Prev = Index; + std::unique_ptr XarchArg(Opts.ParseOneArg(Args, Index)); + + // If the argument parsing failed or more than one argument was + // consumed, the -Xarch_ argument's parameter tried to consume + // extra arguments. Emit an error and ignore. + // + // We also want to disallow any options which would alter the + // driver behavior; that isn't going to work in our model. We + // use isDriverOption() as an approximation, although things + // like -O4 are going to slip through. + if (!XarchArg || Index > Prev + 1) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) + << A->getAsString(Args); + continue; + } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) + << A->getAsString(Args); + continue; + } + XarchArg->setBaseArg(A); + A = XarchArg.release(); + DAL->AddSynthesizedArg(A); + } + DAL->append(A); + } + + if (!BoundArch.empty()) { + DAL->eraseArg(options::OPT_march_EQ); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + } + + return DAL; +} + +Tool *HIPToolChain::buildLinker() const { + assert(getTriple().getArch() == llvm::Triple::amdgcn); + return new tools::AMDGCN::Linker(*this); +} + +void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +HIPToolChain::GetCXXStdlibType(const ArgList &Args) const { + return HostTC.GetCXXStdlibType(Args); +} + +void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +SanitizerMask HIPToolChain::getSupportedSanitizers() const { + // The HIPToolChain only supports sanitizers in the sense that it allows + // sanitizer arguments on the command line if they are supported by the host + // toolchain. The HIPToolChain will actually ignore any command line + // arguments for any of these "supported" sanitizers. That means that no + // sanitization of device code is actually supported at this time. + // + // This behavior is necessary because the host and device toolchains + // invocations often share the command line, so the device toolchain must + // tolerate flags meant only for the host toolchain. + return HostTC.getSupportedSanitizers(); +} + +VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + return HostTC.computeMSVCVersion(D, Args); +} Index: test/Driver/hip-toolchain.hip =================================================================== --- /dev/null +++ test/Driver/hip-toolchain.hip @@ -0,0 +1,84 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: %clang -### -target x86_64-linux-gnu \ +// RUN: -x hip --cuda-gpu-arch=gfx803 --cuda-gpu-arch=gfx900 \ +// RUN: --hip-device-lib=lib1.bc --hip-device-lib=lib2.bc \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib1 \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib2 \ +// RUN: -fuse-ld=lld \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: %S/Inputs/hip_multiple_inputs/b.hip \ +// RUN: 2>&1 | FileCheck %s + +// CHECK: [[CLANG:".*clang.*"]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64--linux-gnu" "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "a.cu" {{.*}} "-fcuda-is-device" +// CHECK-SAME: {{.*}} "-o" [[A_BC:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[A_SRC:".*a.cu"]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64--linux-gnu" "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "b.hip" {{.*}} "-fcuda-is-device" +// CHECK-SAME: {{.*}} "-o" [[B_BC:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[B_SRC:".*b.hip"]] + +// CHECK: [[LLVM_LINK:"*.llvm-link"]] [[A_BC]] [[B_BC]] +// CHECK-SAME: "{{.*}}lib1.bc" "{{.*}}lib2.bc" +// CHECK-SAME: "-o" [[LINKED_BC_DEV1:".*-gfx803-linked-.*bc"]] + +// CHECK: [[OPT:".*opt"]] [[LINKED_BC_DEV1]] "-mtriple=amdgcn-amd-amdhsa" +// CHECK-SAME: "-mcpu=gfx803" +// CHECK-SAME: "-o" [[OPT_BC_DEV1:".*-gfx803-optimized.*bc"]] + +// CHECK: [[LLC: ".*llc"]] [[OPT_BC_DEV1]] "-mtriple=amdgcn-amd-amdhsa" +// CHECK-SAME: "-filetype=obj" "-mcpu=gfx803" "-o" [[OBJ_DEV1:".*-gfx803-.*o"]] + +// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "--no-undefined" "-shared" +// CHECK-SAME: "-o" "[[IMG_DEV1:.*out]]" [[OBJ_DEV1]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64--linux-gnu" "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "a.cu" {{.*}} "-fcuda-is-device" +// CHECK-SAME: {{.*}} "-o" [[A_BC:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[A_SRC]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64--linux-gnu" "-emit-llvm-bc" +// CHECK-SAME: {{.*}} "-main-file-name" "b.hip" {{.*}} "-fcuda-is-device" +// CHECK-SAME: {{.*}} "-o" [[B_BC:".*bc"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[B_SRC]] + +// CHECK: [[LLVM_LINK]] [[A_BC]] [[B_BC]] +// CHECK-SAME: "{{.*}}lib1.bc" "{{.*}}lib2.bc" +// CHECK-SAME: "-o" [[LINKED_BC_DEV2:".*-gfx900-linked-.*bc"]] + +// CHECK: [[OPT]] [[LINKED_BC_DEV2]] "-mtriple=amdgcn-amd-amdhsa" +// CHECK-SAME: "-mcpu=gfx900" +// CHECK-SAME: "-o" [[OPT_BC_DEV2:".*-gfx900-optimized.*bc"]] + +// CHECK: [[LLC]] [[OPT_BC_DEV2]] "-mtriple=amdgcn-amd-amdhsa" +// CHECK-SAME: "-filetype=obj" "-mcpu=gfx900" "-o" [[OBJ_DEV2:".*-gfx900-.*o"]] + +// CHECK: [[LLD]] "-flavor" "gnu" "--no-undefined" "-shared" +// CHECK-SAME: "-o" "[[IMG_DEV2:.*out]]" [[OBJ_DEV2]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "x86_64--linux-gnu" +// CHECK-SAME: "-aux-triple" "amdgcn-amd-amdhsa" "-emit-obj" +// CHECK-SAME: {{.*}} "-main-file-name" "a.cu" +// CHECK-SAME: {{.*}} "-o" [[A_OBJ_HOST:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[A_SRC]] + +// CHECK: [[CLANG]] "-cc1" "-triple" "x86_64--linux-gnu" +// CHECK-SAME: "-aux-triple" "amdgcn-amd-amdhsa" "-emit-obj" +// CHECK-SAME: {{.*}} "-main-file-name" "b.hip" +// CHECK-SAME: {{.*}} "-o" [[B_OBJ_HOST:".*o"]] "-x" "hip" +// CHECK-SAME: {{.*}} [[B_SRC]] + +// CHECK: [[BUNDLER:".*clang-offload-bundler"]] "-type=o" +// CHECK-SAME: "-targets={{.*}},hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" +// CHECK-SAME: "-inputs={{.*}},[[IMG_DEV1]],[[IMG_DEV2]]" "-outputs=[[BUNDLE:.*o]]" + +// CHECK: [[LD:".*ld.lld"]] {{.*}} [[A_OBJ_HOST]] [[B_OBJ_HOST]] +// CHECK-SAME: {{.*}} "-T" "{{.*}}.lk"