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 @@ -15,7 +15,11 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include using namespace clang::driver; using namespace clang::driver::toolchains; @@ -23,6 +27,8 @@ using namespace clang; using namespace llvm::opt; +#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch" + namespace { static const char *getOutputFileName(Compilation &C, StringRef Base, @@ -66,6 +72,53 @@ CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); } } + +static llvm::SmallVector +detectSystemGPUs(const ToolChain &T) { + auto Program = T.GetProgramPath("amdgpu-arch"); + llvm::SmallVector execArgs; + 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 (const int RC = + llvm::sys::ExecuteAndWait(Program.c_str(), execArgs, {}, Redirects)) { + return {}; + } + + auto OutputBuf = llvm::MemoryBuffer::getFile(OutputFile.c_str()); + if (!OutputBuf) + return {}; + + llvm::StringRef Output = OutputBuf.get()->getBuffer().rtrim('\n'); + llvm::SmallVector GPUArchs; + Output.split(GPUArchs, ','); + return GPUArchs; +} + +llvm::StringRef getSystemGPUArch(const ToolChain &T) { + // detect the AMDGPU installed in system + auto GPUArchs = detectSystemGPUs(T); + if (GPUArchs.empty()) { + return ""; + } + if (GPUArchs.size() > 1) { + bool AllSame = std::all_of( + GPUArchs.begin() + 1, GPUArchs.end(), + [&](const StringRef &GPUArch) { return GPUArch == GPUArchs.front(); }); + if (AllSame) + return GPUArchs.front(); + + return ""; + } + return GPUArchs.front(); +} } // namespace const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( @@ -148,7 +201,11 @@ assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target"); StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ); + if (GPUArch.empty()) { + GPUArch = getSystemGPUArch(getToolChain()); + } assert(GPUArch.startswith("gfx") && "Unsupported sub arch"); + assert(!GPUArch.empty() && "Unable to detect system GPU"); // Prefix for temporary file name. std::string Prefix; @@ -187,6 +244,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(*this); + } 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,76 @@ +//===- 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 + +namespace { + +class HSAAgentCollector { +public: + 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; + } + + HSAAgentCollector *Self = static_cast(Data); + char GPUName[64]; + Status = hsa_agent_get_info(Agent, HSA_AGENT_INFO_NAME, GPUName); + if (Status != HSA_STATUS_SUCCESS) { + return Status; + } + Self->GPUs.push_back(GPUName); + return HSA_STATUS_SUCCESS; + } + + int execute() { + hsa_status_t Status = hsa_init(); + if (Status != HSA_STATUS_SUCCESS) { + fprintf(stderr, "Unable to initialize HSA\n"); + } + + Status = hsa_iterate_agents(HSAAgentCollector::iterateAgentsCallback, this); + if (Status != HSA_STATUS_SUCCESS) { + fprintf(stderr, "Error in hsa_iterate_agents\n"); + return 1; + } + + for (unsigned I = 0; I < GPUs.size(); I++) { + printf("%s", GPUs[I].c_str()); + if (I != GPUs.size() - 1) { + printf(","); + } + } + if (GPUs.size() < 1) + return 1; + + hsa_shut_down(); + return 0; + } + +private: + std::vector GPUs; +}; + +} // namespace + +int main() { + HSAAgentCollector Collector; + return Collector.execute(); +} 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,19 @@ +# //===----------------------------------------------------------------------===// +# // +# // 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 +# // +# //===----------------------------------------------------------------------===// + +include_directories(${LIBOMP_INCLUDE_DIR}) + +find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm) +if (NOT ${hsa-runtime64_FOUND}) + message(INFO "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)