[clang] 7029cff - [AMDGPU][OpenMP] Add amdgpu-arch tool to list AMD GPUs installed

Pushpinder Singh via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 15 22:26:36 PDT 2021


Author: Pushpinder Singh
Date: 2021-04-16T05:26:20Z
New Revision: 7029cffc4e78556cfe820791c612968bb15b2ffb

URL: https://github.com/llvm/llvm-project/commit/7029cffc4e78556cfe820791c612968bb15b2ffb
DIFF: https://github.com/llvm/llvm-project/commit/7029cffc4e78556cfe820791c612968bb15b2ffb.diff

LOG: [AMDGPU][OpenMP] Add amdgpu-arch tool to list AMD GPUs installed

This patch adds new clang tool named amdgpu-arch which uses
HSA to detect installed AMDGPU and report back latter's march.
This tool is built only if system has HSA installed.

The value printed by amdgpu-arch is used to fill -march when
latter is not explicitly provided in -Xopenmp-target.

Reviewed By: JonChesterfield, gregrodgers

Differential Revision: https://reviews.llvm.org/D99949

Added: 
    clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_different
    clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_fail
    clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx906
    clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx908_gfx908
    clang/test/Driver/amdgpu-openmp-system-arch-fail.c
    clang/test/Driver/amdgpu-openmp-system-arch.c
    clang/tools/amdgpu-arch/AMDGPUArch.cpp
    clang/tools/amdgpu-arch/CMakeLists.txt

Modified: 
    clang/include/clang/Basic/DiagnosticDriverKinds.td
    clang/include/clang/Driver/Options.td
    clang/lib/Driver/ToolChains/AMDGPU.cpp
    clang/lib/Driver/ToolChains/AMDGPU.h
    clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
    clang/tools/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 5e580cc4fbb7a..aa3b00c231cbe 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -67,6 +67,8 @@ def err_drv_no_hip_runtime : Error<
   "cannot find HIP runtime. Provide its path via --rocm-path, or pass "
   "-nogpuinc to build without HIP runtime.">;
 
+def err_drv_undetermined_amdgpu_arch : Error<
+  "Cannot determine AMDGPU architecture. Consider passing it via -march">;
 def err_drv_cuda_version_unsupported : Error<
   "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), "
   "but installation at %3 is %4. Use --cuda-path to specify a 
diff erent CUDA "

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 9e15712eb2d51..5fbcd64b69376 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -918,6 +918,8 @@ def rocm_path_EQ : Joined<["--"], "rocm-path=">, Group<i_Group>,
   HelpText<"ROCm installation path, used for finding and automatically linking required bitcode libraries.">;
 def hip_path_EQ : Joined<["--"], "hip-path=">, Group<i_Group>,
   HelpText<"HIP runtime installation path, used for finding HIP version and adding HIP include path.">;
+def amdgpu_arch_tool_EQ : Joined<["--"], "amdgpu-arch-tool=">, Group<i_Group>,
+  HelpText<"Tool used for detecting AMD GPU arch in the system.">;
 def rocm_device_lib_path_EQ : Joined<["--"], "rocm-device-lib-path=">, Group<Link_Group>,
   HelpText<"ROCm device library path. Alternative to rocm-path.">;
 def : Joined<["--"], "hip-device-lib-path=">, Alias<rocm_device_lib_path_EQ>;

diff  --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index dc9c9751c851d..37da2c05dcf67 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -12,10 +12,15 @@
 #include "clang/Basic/TargetID.h"
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.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 +720,57 @@ void AMDGPUToolChain::checkTargetID(
   }
 }
 
+llvm::SmallVector<SmallString<8>, 1>
+AMDGPUToolChain::detectSystemGPUs(const ArgList &Args) const {
+  std::string Program;
+  if (Arg *A = Args.getLastArg(options::OPT_amdgpu_arch_tool_EQ))
+    Program = A->getValue();
+  else
+    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<llvm::StringRef> Redirects[] = {
+      {""},
+      StringRef(OutputFile),
+      {""},
+  };
+
+  if (llvm::sys::ExecuteAndWait(Program.c_str(), {}, {}, Redirects)) {
+    return {};
+  }
+
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
+      llvm::MemoryBuffer::getFile(OutputFile.c_str());
+  if (!OutputBuf)
+    return {};
+
+  llvm::SmallVector<SmallString<8>, 1> GPUArchs;
+  for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) {
+    GPUArchs.push_back(*LineIt);
+  }
+  return GPUArchs;
+}
+
+SmallString<8> AMDGPUToolChain::getSystemGPUArch(const ArgList &Args) const {
+  // detect the AMDGPU installed in system
+  auto GPUArchs = detectSystemGPUs(Args);
+  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/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h
index 1aa0849ee9223..17552536468af 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.h
+++ b/clang/lib/Driver/ToolChains/AMDGPU.h
@@ -100,12 +100,19 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
   /// Should skip argument.
   bool shouldSkipArgument(const llvm::opt::Arg *Arg) const;
 
+  /// Uses amdgpu_arch tool to get arch of the system GPU. Returns empty string
+  /// if unable to find one.
+  SmallString<8> getSystemGPUArch(const llvm::opt::ArgList &Args) 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<SmallString<8>, 1>
+  detectSystemGPUs(const llvm::opt::ArgList &Args) const;
 };
 
 class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain {

diff  --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
index 38abd2f483681..625dda9a44355 100644
--- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
@@ -10,6 +10,7 @@
 #include "AMDGPU.h"
 #include "CommonArgs.h"
 #include "InputInfo.h"
+#include "clang/Basic/DiagnosticDriver.h"
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
@@ -145,10 +146,19 @@ void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
                                         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<const toolchains::AMDGPUOpenMPToolChain &>(TC);
   StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ);
-  assert(GPUArch.startswith("gfx") && "Unsupported sub arch");
+  if (GPUArch.empty()) {
+    GPUArch = AMDGPUOpenMPTC.getSystemGPUArch(Args);
+  }
+  if (GPUArch.empty()) {
+    TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch);
+    return;
+  }
 
   // Prefix for temporary file name.
   std::string Prefix;
@@ -187,7 +197,16 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions(
   HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
 
   StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
-  assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
+  if (GpuArch.empty()) {
+    // in case no GPU arch is passed via -march, then try to detect
+    // the system gpu
+    GpuArch = getSystemGPUArch(DriverArgs);
+  }
+  if (GpuArch.empty()) {
+    getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch);
+    return;
+  }
+
   assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
          "Only OpenMP offloading kinds are supported.");
 

diff  --git a/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_
diff erent b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_
diff erent
new file mode 100755
index 0000000000000..6e30711c4ba57
--- /dev/null
+++ b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_
diff erent
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+echo gfx908
+echo gfx906
+return 0
\ No newline at end of file

diff  --git a/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_fail b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_fail
new file mode 100755
index 0000000000000..360ac43efc9a3
--- /dev/null
+++ b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_fail
@@ -0,0 +1,2 @@
+#!/usr/bin/env sh
+return 1
\ No newline at end of file

diff  --git a/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx906 b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx906
new file mode 100755
index 0000000000000..fdc0886e7570c
--- /dev/null
+++ b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx906
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+echo "gfx906"
+return 0

diff  --git a/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx908_gfx908 b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx908_gfx908
new file mode 100755
index 0000000000000..83c58476f2356
--- /dev/null
+++ b/clang/test/Driver/Inputs/amdgpu-arch/amdgpu_arch_gfx908_gfx908
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+echo gfx908
+echo gfx908
+return 0

diff  --git a/clang/test/Driver/amdgpu-openmp-system-arch-fail.c b/clang/test/Driver/amdgpu-openmp-system-arch-fail.c
new file mode 100644
index 0000000000000..8e97fab3249be
--- /dev/null
+++ b/clang/test/Driver/amdgpu-openmp-system-arch-fail.c
@@ -0,0 +1,13 @@
+// REQUIRES: system-linux
+// REQUIRES: x86-registered-target
+// REQUIRES: amdgpu-registered-target
+
+// case when amdgpu_arch returns nothing or fails
+// RUN:   %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -nogpulib --amdgpu-arch-tool=%S/Inputs/amdgpu-arch/amdgpu_arch_fail %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=NO-OUTPUT-ERROR
+// NO-OUTPUT-ERROR: error: Cannot determine AMDGPU architecture. Consider passing it via -march
+
+// case when amdgpu_arch returns multiple gpus but all are 
diff erent
+// RUN:   %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -nogpulib --amdgpu-arch-tool=%S/Inputs/amdgpu-arch/amdgpu_arch_
diff erent %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=MULTIPLE-OUTPUT-ERROR
+// MULTIPLE-OUTPUT-ERROR: error: Cannot determine AMDGPU architecture. Consider passing it via -march

diff  --git a/clang/test/Driver/amdgpu-openmp-system-arch.c b/clang/test/Driver/amdgpu-openmp-system-arch.c
new file mode 100644
index 0000000000000..48d0ecc4e460e
--- /dev/null
+++ b/clang/test/Driver/amdgpu-openmp-system-arch.c
@@ -0,0 +1,15 @@
+// REQUIRES: system-linux
+// REQUIRES: x86-registered-target
+// REQUIRES: amdgpu-registered-target
+// RUN:   %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -nogpulib --amdgpu-arch-tool=%S/Inputs/amdgpu-arch/amdgpu_arch_gfx906 %s 2>&1 \
+// RUN:   | FileCheck %s
+// CHECK: clang{{.*}}"-cc1"{{.*}}"-triple" "amdgcn-amd-amdhsa"{{.*}}"-target-cpu" "[[GFX:gfx906]]"
+// CHECK: llvm-link{{.*}}"-o" "{{.*}}amdgpu-openmp-system-arch-{{.*}}-[[GFX]]-linked-{{.*}}.bc"
+// CHECK: llc{{.*}}amdgpu-openmp-system-arch-{{.*}}-[[GFX]]-linked-{{.*}}.bc" "-mtriple=amdgcn-amd-amdhsa" "-mcpu=[[GFX]]" "-filetype=obj" "-o"{{.*}}amdgpu-openmp-system-arch-{{.*}}-[[GFX]]-{{.*}}.o"
+
+// case when amdgpu_arch returns multiple gpus but of same arch
+// RUN:   %clang -### --target=x86_64-unknown-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -nogpulib --amdgpu-arch-tool=%S/Inputs/amdgpu-arch/amdgpu_arch_gfx908_gfx908 %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-MULTIPLE
+// CHECK-MULTIPLE: clang{{.*}}"-cc1"{{.*}}"-triple" "amdgcn-amd-amdhsa"{{.*}}"-target-cpu" "[[GFX:gfx908]]"
+// CHECK-MULTIPLE: llvm-link{{.*}}"-o" "{{.*}}amdgpu-openmp-system-arch-{{.*}}-[[GFX]]-linked-{{.*}}.bc"
+// CHECK-MULTIPLE: llc{{.*}}amdgpu-openmp-system-arch-{{.*}}-[[GFX]]-linked-{{.*}}.bc" "-mtriple=amdgcn-amd-amdhsa" "-mcpu=[[GFX]]" "-filetype=obj" "-o"{{.*}}amdgpu-openmp-system-arch-{{.*}}-[[GFX]]-{{.*}}.o"

diff  --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt
index 52fd02529b46f..32359178066c9 100644
--- a/clang/tools/CMakeLists.txt
+++ b/clang/tools/CMakeLists.txt
@@ -43,3 +43,5 @@ add_llvm_external_project(clang-tools-extra extra)
 
 # 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
index 0000000000000..29f9c8bc23974
--- /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 <hsa.h>
+#include <string>
+#include <vector>
+
+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<std::string> *GPUs =
+      static_cast<std::vector<std::string> *>(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) {
+    return 1;
+  }
+
+  std::vector<std::string> GPUs;
+  Status = hsa_iterate_agents(iterateAgentsCallback, &GPUs);
+  if (Status != HSA_STATUS_SUCCESS) {
+    return 1;
+  }
+
+  for (const auto &GPU : GPUs)
+    printf("%s\n", GPU.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
index 0000000000000..fca58c4060edd
--- /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)


        


More information about the cfe-commits mailing list