Author: A. Cauble
Date: 2026-09-18T10:09:54-05:00
New Revision: cb9d4cdf5e415d17aaa54a094939249c15871d2d

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

LOG: [offload-arch] Report gfx1250-strict to match rocminfo (#224480)

## Motivation

offload-arch would print gfx1250, but rocminfo reports gfx1250-strict on
revision 0s. We want to print the gfx1250-strict too.

Note: This is based off a [similar PR in
rocm-systems](https://github.com/ROCm/rocm-systems/pull/11639).

## Required Changes

* llvm already can parse the gfx1250 -strict target, so no changes
necessary there.
* offload-arch already printed gfx1250, so just needed to get the ASIC
Revision, which is in bits 25:22 in the capability property.
* If ASIC Revision is 0 and gfx_target_version is gfx1250, then report
"gfx1250-strict"

## Testing

* Tested this on a gfx1250-strict and offload-arch reports correctly.
* Added two unit tests to check for "gfx1250" v "gfx1250-strict"
depending on ASIC revision and guard against accidental parsing of
"capability2"

Added: 
    

Modified: 
    clang/tools/offload-arch/AMDGPUArchByKFD.cpp
    clang/unittests/offload-arch/OffloadArchTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/tools/offload-arch/AMDGPUArchByKFD.cpp 
b/clang/tools/offload-arch/AMDGPUArchByKFD.cpp
index 8e4284eb5f8de..5720c5a0958b4 100644
--- a/clang/tools/offload-arch/AMDGPUArchByKFD.cpp
+++ b/clang/tools/offload-arch/AMDGPUArchByKFD.cpp
@@ -19,11 +19,13 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 #include <memory>
+#include <tuple>
 
 using namespace llvm;
 
 constexpr static const char *KFD_SYSFS_NODE_PATH =
     "/sys/devices/virtual/kfd/kfd/topology/nodes";
+constexpr static long GFX1250_VERSION = 120500;
 
 // See the ROCm implementation for how this is handled.
 // 
https://github.com/ROCm/ROCT-Thunk-Interface/blob/master/src/libhsakmt.h#L126
@@ -31,9 +33,20 @@ constexpr static long getMajor(long Ver) { return (Ver / 
10000) % 100; }
 constexpr static long getMinor(long Ver) { return (Ver / 100) % 100; }
 constexpr static long getStep(long Ver) { return Ver % 100; }
 
+// For A0, print gfx1250-strict to match rocminfo
+static StringRef getRevisionSuffix(long GFXVersion, long ASICRevision) {
+  return (GFXVersion == GFX1250_VERSION && ASICRevision == 0) ? "-strict" : "";
+}
+
 // Exposed for testing
 int printGPUsByKFD(StringRef NodePath) {
-  SmallVector<std::pair<long, long>> Devices;
+  struct KFDNode {
+    long Node;
+    long GFXVersion;
+    long ASICRevision;
+  };
+
+  SmallVector<KFDNode> Devices;
   std::error_code EC;
   sys::fs::directory_iterator Begin(NodePath, EC), End;
 
@@ -58,6 +71,7 @@ int printGPUsByKFD(StringRef NodePath) {
       return 1;
 
     long GFXVersion = 0;
+    uint64_t Capability = 0;
     for (line_iterator Lines(**BufferOrErr, false); !Lines.is_at_end();
          ++Lines) {
       StringRef Line(*Lines);
@@ -65,21 +79,29 @@ int printGPUsByKFD(StringRef NodePath) {
         if (Line.drop_while([](char C) { return std::isspace(C); })
                 .consumeInteger(10, GFXVersion))
           return 1;
-        break;
+        // Differentiate between capability and capability2
+      } else if (Line.consume_front("capability") && !Line.starts_with('2')) {
+        if (Line.drop_while([](char C) { return std::isspace(C); })
+                .consumeInteger(10, Capability))
+          return 1;
       }
     }
 
     // If this is zero the node is a CPU.
     if (GFXVersion == 0)
       continue;
-    Devices.emplace_back(Node, GFXVersion);
+    // ASIC revision is bits 25:22 in capability
+    long ASICRevision = (Capability >> 22) & 0xf;
+    Devices.push_back({Node, GFXVersion, ASICRevision});
   }
 
   // Sort the devices by their node to make sure it prints in order.
-  llvm::sort(Devices, [](auto &L, auto &R) { return L.first < R.first; });
-  for (const auto &[Node, GFXVersion] : Devices)
+  llvm::sort(Devices, [](auto &L, auto &R) { return L.Node < R.Node; });
+  for (const auto &[Node, GFXVersion, ASICRevision] : Devices) {
     outs() << "gfx" << getMajor(GFXVersion) << getMinor(GFXVersion)
-           << format_hex_no_prefix(getStep(GFXVersion), 1) << '\n';
+           << format_hex_no_prefix(getStep(GFXVersion), 1)
+           << getRevisionSuffix(GFXVersion, ASICRevision) << '\n';
+  }
 
   return 0;
 }

diff  --git a/clang/unittests/offload-arch/OffloadArchTest.cpp 
b/clang/unittests/offload-arch/OffloadArchTest.cpp
index 5f5e49f5c72cc..8132a6ca10847 100644
--- a/clang/unittests/offload-arch/OffloadArchTest.cpp
+++ b/clang/unittests/offload-arch/OffloadArchTest.cpp
@@ -142,6 +142,19 @@ void addGPUNode(StringRef Dir, unsigned Node, StringRef 
GFXVersion) {
   addNode(Dir, Node, ("gfx_target_version " + GFXVersion + "\n").str());
 }
 
+// Write a node describing a GPU with the given gfx_target_version and
+// capabilities. Write capability2 before and after to catch accidental
+// reads of something other than "capability"
+void addGPUNodeWithCapability(StringRef Dir, unsigned Node,
+                              StringRef GFXVersion, uint64_t Capability,
+                              uint64_t Capability2) {
+  addNode(Dir, Node,
+          ("gfx_target_version " + GFXVersion + "\n" + "capability2 " +
+           Twine(Capability2) + "\n" + "capability " + Twine(Capability) +
+           "\n" + "capability2 " + Twine(Capability2) + "\n")
+              .str());
+}
+
 // Run printGPUsByKFD, collecting what it writes to stdout.
 int printGPUsByKFDCapturingStdout(StringRef NodePath, std::string &Output) {
   testing::internal::CaptureStdout();
@@ -207,3 +220,25 @@ TEST(KFDTopology, MultipleGPUsArePrintedInNodeOrder) {
   EXPECT_EQ(printGPUsByKFDCapturingStdout(Dir.path(), Output), 0);
   EXPECT_EQ(Output, "gfx1101\ngfx90a\n");
 }
+
+// Make sure that A0 of gfx1250 is printed as gfx1250-strict. Happens when
+// ASIC revision is 0. Also tests to make sure other properties that look like
+// capability (like capability2) are not read instead.
+TEST(KFDTopology, GFX1250A0IsPrintedAsStrict) {
+  unittest::TempDir Dir("kfd-topology", /*Unique=*/true);
+  addGPUNodeWithCapability(Dir.path(), 0, "120500", /*Capability=*/0xF837A280,
+                           /*Capability2=*/0xFFFFFFFF);
+  std::string Output;
+  EXPECT_EQ(printGPUsByKFDCapturingStdout(Dir.path(), Output), 0);
+  EXPECT_EQ(Output, "gfx1250-strict\n");
+}
+
+// Make sure any other version of gfx1250 is printed as gfx1250.
+TEST(KFDTopology, GFX1250NonA0IsPrintedPlain) {
+  unittest::TempDir Dir("kfd-topology", /*Unique=*/true);
+  addGPUNodeWithCapability(Dir.path(), 0, "120500", /*Capability=*/0xF877A280,
+                           /*Capability2=*/0x00000000);
+  std::string Output;
+  EXPECT_EQ(printGPUsByKFDCapturingStdout(Dir.path(), Output), 0);
+  EXPECT_EQ(Output, "gfx1250\n");
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to