diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -100,12 +100,18 @@ /// Should skip argument. bool shouldSkipArgument(const llvm::opt::Arg *Arg) const; + /// Uses HSA to get arch of the system GPU. Returns empty string + /// if unable to find one. + SmallString<8> getSystemGPUArch() const; + protected: /// Check and diagnose invalid target ID specified by -mcpu. void checkTargetID(const llvm::opt::ArgList &DriverArgs) const; /// Get GPU arch from -mcpu without checking. StringRef getGPUArch(const llvm::opt::ArgList &DriverArgs) const; + + SmallVector, 1> detectSystemGPUs() const; }; class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain { diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -13,9 +13,13 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" +#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch" + using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; @@ -715,6 +719,52 @@ } } +llvm::SmallVector, 1> AMDGPUToolChain::detectSystemGPUs() const { + std::string Program = GetProgramPath(AMDGPU_ARCH_PROGRAM_NAME); + llvm::SmallString<64> OutputFile; + llvm::sys::fs::createTemporaryFile("print-system-gpus", "" /* No Suffix */, + OutputFile); + llvm::FileRemover OutputRemover(OutputFile.c_str()); + llvm::Optional Redirects[] = { + {""}, + StringRef(OutputFile), + {""}, + }; + + if (llvm::sys::ExecuteAndWait(Program.c_str(), {}, {}, Redirects)) { + return {}; + } + + llvm::ErrorOr> OutputBuf = + llvm::MemoryBuffer::getFile(OutputFile.c_str()); + if (!OutputBuf) + return {}; + + llvm::SmallVector, 1> GPUArchs; + for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) { + GPUArchs.push_back(*LineIt); + } + return GPUArchs; +} + +SmallString<8> AMDGPUToolChain::getSystemGPUArch() const { + // detect the AMDGPU installed in system + auto GPUArchs = detectSystemGPUs(); + if (GPUArchs.empty()) { + return SmallString<8>(""); + } + if (GPUArchs.size() > 1) { + bool AllSame = std::all_of( + GPUArchs.begin(), GPUArchs.end(), + [&](const StringRef &GPUArch) { return GPUArch == GPUArchs.front(); }); + if (AllSame) + return GPUArchs.front(); + + return SmallString<8>(""); + } + return GPUArchs.front(); +} + void ROCMToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { 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 @@ -145,10 +145,16 @@ const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const ToolChain &TC = getToolChain(); assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target"); + const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC = + static_cast(TC); StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ); - assert(GPUArch.startswith("gfx") && "Unsupported sub arch"); + if (GPUArch.empty()) { + GPUArch = AMDGPUOpenMPTC.getSystemGPUArch(); + } + assert(!GPUArch.empty() && "Must have an explicit GPU arch."); // Prefix for temporary file name. std::string Prefix; @@ -187,6 +193,11 @@ HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + if (GpuArch.empty()) { + // in case no GPU arch is passed via -march, then try to detect + // the system gpu + GpuArch = getSystemGPUArch(); + } assert(!GpuArch.empty() && "Must have an explicit GPU arch."); assert(DeviceOffloadingKind == Action::OFK_OpenMP && "Only OpenMP offloading kinds are supported."); diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt --- a/clang/tools/CMakeLists.txt +++ b/clang/tools/CMakeLists.txt @@ -43,3 +43,5 @@ # libclang may require clang-tidy in clang-tools-extra. add_clang_subdirectory(libclang) + +add_clang_subdirectory(amdgpu-arch) diff --git a/clang/tools/amdgpu-arch/AMDGPUArch.cpp b/clang/tools/amdgpu-arch/AMDGPUArch.cpp new file mode 100644 --- /dev/null +++ b/clang/tools/amdgpu-arch/AMDGPUArch.cpp @@ -0,0 +1,59 @@ +//===- AMDGPUArch.cpp - list AMDGPU installed ----------*- C++ -*---------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements a tool for detecting name of AMDGPU installed in system +// using HSA. This tool is used by AMDGPU OpenMP driver. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) { + hsa_device_type_t DeviceType; + hsa_status_t Status = + hsa_agent_get_info(Agent, HSA_AGENT_INFO_DEVICE, &DeviceType); + + // continue only if device type if GPU + if (Status != HSA_STATUS_SUCCESS || DeviceType != HSA_DEVICE_TYPE_GPU) { + return Status; + } + + std::vector *GPUs = + static_cast *>(Data); + char GPUName[64]; + Status = hsa_agent_get_info(Agent, HSA_AGENT_INFO_NAME, GPUName); + if (Status != HSA_STATUS_SUCCESS) { + return Status; + } + GPUs->push_back(GPUName); + return HSA_STATUS_SUCCESS; +} + +int main() { + hsa_status_t Status = hsa_init(); + if (Status != HSA_STATUS_SUCCESS) { + fprintf(stderr, "Unable to initialize HSA\n"); + } + + std::vector GPUs; + Status = hsa_iterate_agents(iterateAgentsCallback, &GPUs); + if (Status != HSA_STATUS_SUCCESS) { + return 1; + } + + for (unsigned I = 0; I < GPUs.size(); I++) { + printf("%s\n", GPUs[I].c_str()); + } + if (GPUs.size() < 1) + return 1; + + hsa_shut_down(); + return 0; +} diff --git a/clang/tools/amdgpu-arch/CMakeLists.txt b/clang/tools/amdgpu-arch/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/clang/tools/amdgpu-arch/CMakeLists.txt @@ -0,0 +1,17 @@ +# //===----------------------------------------------------------------------===// +# // +# // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# // See https://llvm.org/LICENSE.txt for details. +# // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# // +# //===----------------------------------------------------------------------===// + +find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm) +if (NOT ${hsa-runtime64_FOUND}) + message(STATUS "Not building amdgpu-arch: hsa-runtime64 not found") + return() +endif() + +add_clang_tool(amdgpu-arch AMDGPUArch.cpp) + +clang_target_link_libraries(amdgpu-arch PRIVATE hsa-runtime64::hsa-runtime64)