pdhaliwal created this revision.
pdhaliwal added reviewers: JonChesterfield, ronlieb, jdoerfert, ABataev, 
gregrodgers.
Herald added subscribers: kerbowa, guansong, t-tye, tpr, dstuttard, yaxunl, 
mgorny, nhaehnle, jvesely, kzhuravl.
pdhaliwal requested review of this revision.
Herald added subscribers: cfe-commits, sstefan1, wdng.
Herald added a project: clang.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D99949

Files:
  clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
  clang/tools/CMakeLists.txt
  clang/tools/amdgpu-arch/AMDGPUArch.cpp
  clang/tools/amdgpu-arch/CMakeLists.txt

Index: clang/tools/amdgpu-arch/CMakeLists.txt
===================================================================
--- /dev/null
+++ 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)
Index: clang/tools/amdgpu-arch/AMDGPUArch.cpp
===================================================================
--- /dev/null
+++ 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 <hsa.h>
+#include <string>
+#include <vector>
+
+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<HSAAgentCollector *>(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<std::string> GPUs;
+};
+
+} // namespace
+
+int main() {
+  HSAAgentCollector Collector;
+  return Collector.execute();
+}
Index: clang/tools/CMakeLists.txt
===================================================================
--- clang/tools/CMakeLists.txt
+++ 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)
Index: clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
===================================================================
--- clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
+++ 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 <algorithm>
 
 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<llvm::StringRef, 8>
+detectSystemGPUs(const ToolChain &T) {
+  auto Program = T.GetProgramPath("amdgpu-arch");
+  llvm::SmallVector<llvm::StringRef, 8> execArgs;
+  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 (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<llvm::StringRef, 8> 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.");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to