[llvm] [AMDGPU] Fix SSID merge in SIMemoryLegalizer to use smallest inclusiv… (PR #208300)

Wooseok Lee via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 10 06:52:47 PDT 2026


https://github.com/wooseoklee updated https://github.com/llvm/llvm-project/pull/208300

>From e0ebcf37830c7e3432ad5b042005faaffeae8aa8 Mon Sep 17 00:00:00 2001
From: wooseoklee <wolee at amd.com>
Date: Wed, 8 Jul 2026 13:17:37 -0500
Subject: [PATCH 1/5] [AMDGPU] Fix SSID merge in SIMemoryLegalizer to use
 smallest inclusive scope

SIMemOpAccess::constructFromMIWithMMO merged multiple MMO sync scopes by
calling isSyncScopeInclusion(A, B) and blindly overwriting SSID with B
when it returned false. This was correct when B strictly subsumes A, but
isSyncScopeInclusion returned false for both "A < B" and "A and B are
incomparable" -- e.g. agent-one-as (one-AS, agent level) vs workgroup
(cross-AS, workgroup level) live on different branches of the two-dimensional
scope lattice and neither subsumes the other. In the incomparable case the
resulting SSID depended on MMO order, silently dropping agent-scope
cache-management requirements.

Fix: replace isSyncScopeInclusion (std::optional<bool>) with
getMergedSyncScopeID (std::optional<SyncScope::ID>) which returns the
smallest scope inclusive of both inputs. The merged level is max(level_A,
level_B); if either input is cross-AS the result is also cross-AS, since
dropping cross-AS ordering would silently lose the ordering guarantee for
address spaces not covered by a one-AS scope.

Add tests in memory-legalizer-multiple-mem-operands-atomics.mir verifying
that a FLAT_ATOMIC_ADD with agent-one-as and workgroup MMOs produces
agent-scope cache ops (BUFFER_WBINVL1_VOL) regardless of MMO order.
---
 .../Target/AMDGPU/AMDGPUMachineModuleInfo.h   | 60 ++++++++++++++-----
 llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp  | 21 +++----
 llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll  |  4 +-
 .../memory-legalizer-invalid-syncscope.ll     |  8 +--
 ...egalizer-multiple-mem-operands-atomics.mir | 46 ++++++++++++++
 5 files changed, 109 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
index bf852bb38376e..b2dd1841f4a55 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
@@ -130,26 +130,58 @@ class AMDGPUMachineModuleInfo final : public MachineModuleInfoELF {
     return ClusterOneAddressSpaceSSID;
   }
 
-  /// In AMDGPU target synchronization scopes are inclusive, meaning a
-  /// larger synchronization scope is inclusive of a smaller synchronization
-  /// scope.
+  /// In AMDGPU, synchronization scopes are inclusive: a larger scope is
+  /// inclusive of a smaller one (e.g. agent includes workgroup).
+  ///
+  /// Returns the merged synchronization scope of \p A and \p B: the smallest
+  /// scope that is inclusive of both. Takes the larger inclusion level and,
+  /// if either scope is cross-address-space, the result is also
+  /// cross-address-space (since a one-AS scope cannot subsume a cross-AS
+  /// scope at the same level).
   ///
-  /// \returns True if synchronization scope \p A is larger than or equal to
-  /// synchronization scope \p B, false if synchronization scope \p A is smaller
-  /// than synchronization scope \p B, or "std::nullopt" if either
-  /// synchronization scope \p A or \p B is not supported by the AMDGPU target.
-  std::optional<bool> isSyncScopeInclusion(SyncScope::ID A,
-                                           SyncScope::ID B) const {
+  /// \returns The merged scope ID, or "std::nullopt" if either scope is not
+  /// supported by the AMDGPU target.
+  std::optional<SyncScope::ID> getMergedSyncScopeID(SyncScope::ID A,
+                                                    SyncScope::ID B) const {
     const auto &AIO = getSyncScopeInclusionOrdering(A);
     const auto &BIO = getSyncScopeInclusionOrdering(B);
     if (!AIO || !BIO)
       return std::nullopt;
 
-    bool IsAOneAddressSpace = isOneAddressSpace(A);
-    bool IsBOneAddressSpace = isOneAddressSpace(B);
-
-    return *AIO >= *BIO &&
-           (IsAOneAddressSpace == IsBOneAddressSpace || !IsAOneAddressSpace);
+    uint8_t Level = std::max(*AIO, *BIO);
+    // If either scope is cross-AS, the result must be cross-AS.
+    if (isOneAddressSpace(A) && isOneAddressSpace(B)) {
+      switch (Level) {
+      case 0:
+        return SyncScope::SingleThread;
+      case 1:
+        return getWavefrontOneAddressSpaceSSID();
+      case 2:
+        return getWorkgroupOneAddressSpaceSSID();
+      case 3:
+        return getClusterOneAddressSpaceSSID();
+      case 4:
+        return getAgentOneAddressSpaceSSID();
+      case 5:
+        return getSystemOneAddressSpaceSSID();
+      }
+    } else {
+      switch (Level) {
+      case 0:
+        return SyncScope::SingleThread;
+      case 1:
+        return getWavefrontSSID();
+      case 2:
+        return getWorkgroupSSID();
+      case 3:
+        return getClusterSSID();
+      case 4:
+        return getAgentSSID();
+      case 5:
+        return SyncScope::System;
+      }
+    }
+    return std::nullopt;
   }
 };
 
diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index 409fcc7f8d980..b90ceffdf5582 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -851,7 +851,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
     const MachineBasicBlock::iterator &MI) const {
   assert(MI->getNumMemOperands() > 0);
 
-  SyncScope::ID SSID = SyncScope::SingleThread;
+  std::optional<SyncScope::ID> MergedSSID;
   AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
   AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
   SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
@@ -867,19 +867,19 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
     IsVolatile |= MMO->isVolatile();
     IsLastUse |= MMO->getFlags() & MOLastUse;
     IsCooperative |= MMO->getFlags() & MOCooperative;
-    InstrAddrSpace |=
-      toSIAtomicAddrSpace(MMO->getPointerInfo().getAddrSpace());
+    InstrAddrSpace |= toSIAtomicAddrSpace(MMO->getPointerInfo().getAddrSpace());
     AtomicOrdering OpOrdering = MMO->getSuccessOrdering();
     if (OpOrdering != AtomicOrdering::NotAtomic) {
-      const auto &IsSyncScopeInclusion =
-          MMI->isSyncScopeInclusion(SSID, MMO->getSyncScopeID());
-      if (!IsSyncScopeInclusion) {
-        reportUnsupported(MI,
-          "Unsupported non-inclusive atomic synchronization scope");
+      // Merge the accumulated scope with the new one to get the smallest scope
+      // inclusive of both.
+      SyncScope::ID CurSSID = MergedSSID.value_or(MMO->getSyncScopeID());
+      const auto &Merged =
+          MMI->getMergedSyncScopeID(CurSSID, MMO->getSyncScopeID());
+      if (!Merged) {
+        reportUnsupported(MI, "Unsupported atomic synchronization scope");
         return std::nullopt;
       }
-
-      SSID = *IsSyncScopeInclusion ? SSID : MMO->getSyncScopeID();
+      MergedSSID = *Merged;
       Ordering = getMergedAtomicOrdering(Ordering, OpOrdering);
       assert(MMO->getFailureOrdering() != AtomicOrdering::Release &&
              MMO->getFailureOrdering() != AtomicOrdering::AcquireRelease);
@@ -887,6 +887,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
           getMergedAtomicOrdering(FailureOrdering, MMO->getFailureOrdering());
     }
   }
+  SyncScope::ID SSID = MergedSSID.value_or(SyncScope::SingleThread);
 
   // FIXME: The MMO of buffer atomic instructions does not always have an atomic
   // ordering. We only need to handle VBUFFER atomics on GFX12+ so we can fix it
diff --git a/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll b/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
index ce4522f4b4ad7..d64366a2b3f9b 100644
--- a/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
+++ b/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
@@ -1,8 +1,8 @@
 ; RUN: not llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx942 -filetype=null < %s 2>&1 | FileCheck %s
 ; RUN: not llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx942 -filetype=null < %s 2>&1 | FileCheck %s
 
-; CHECK: error: {{.*}}: in function av_load_bad_scope {{.*}}: Unsupported non-inclusive atomic synchronization scope
-; CHECK: error: {{.*}}: in function av_store_bad_scope {{.*}}: Unsupported non-inclusive atomic synchronization scope
+; CHECK: error: {{.*}}: in function av_load_bad_scope {{.*}}: Unsupported atomic synchronization scope
+; CHECK: error: {{.*}}: in function av_store_bad_scope {{.*}}: Unsupported atomic synchronization scope
 
 define <4 x i32> @av_load_bad_scope(ptr addrspace(1) %p) {
   %v = call <4 x i32> @llvm.amdgcn.av.load.b128.p1(ptr addrspace(1) %p, metadata !0)
diff --git a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
index 1a2058cbe39e4..e820bac9e5ae5 100644
--- a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
+++ b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
@@ -11,7 +11,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_load void (ptr, ptr): Unsupported non-inclusive atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_load void (ptr, ptr): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_load(
     ptr %in, ptr %out) {
 entry:
@@ -20,7 +20,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_store void (i32, ptr): Unsupported non-inclusive atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_store void (i32, ptr): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_store(
     i32 %in, ptr %out) {
 entry:
@@ -28,7 +28,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_cmpxchg void (ptr, i32, i32): Unsupported non-inclusive atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_cmpxchg void (ptr, i32, i32): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_cmpxchg(
     ptr %out, i32 %in, i32 %old) {
 entry:
@@ -37,7 +37,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_rmw void (ptr, i32): Unsupported non-inclusive atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_rmw void (ptr, i32): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_rmw(
     ptr %out, i32 %in) {
 entry:
diff --git a/llvm/test/CodeGen/AMDGPU/memory-legalizer-multiple-mem-operands-atomics.mir b/llvm/test/CodeGen/AMDGPU/memory-legalizer-multiple-mem-operands-atomics.mir
index 3941da208f825..1496f2533d88b 100644
--- a/llvm/test/CodeGen/AMDGPU/memory-legalizer-multiple-mem-operands-atomics.mir
+++ b/llvm/test/CodeGen/AMDGPU/memory-legalizer-multiple-mem-operands-atomics.mir
@@ -111,3 +111,49 @@ body:             |
     S_ENDPGM 0
 
 ...
+---
+# Test that multi-MMO atomics with incomparable sync scopes (agent-one-as and
+# workgroup) produce agent-scope cache ops regardless of MMO order. The merged
+# scope of agent-one-as and workgroup is agent (cross-AS). Before the fix, the
+# result was MMO-order dependent.
+name: merge_agent_one_as_and_workgroup
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $sgpr3
+    ; GCN-LABEL: name: merge_agent_one_as_and_workgroup
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $sgpr3
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: renamable $vgpr0_vgpr1 = COPY $sgpr0_sgpr1
+    ; GCN-NEXT: renamable $vgpr2 = COPY $sgpr2
+    ; GCN-NEXT: S_WAITCNT_soft .Vmcnt_0_Lgkmcnt_0
+    ; GCN-NEXT: FLAT_ATOMIC_ADD $vgpr0_vgpr1, $vgpr2, 0, 0, implicit $exec, implicit $flat_scr :: (load store syncscope("agent-one-as") seq_cst (s32) on `ptr addrspace(1) poison`, addrspace 1), (load store syncscope("workgroup") seq_cst (s32) on `ptr addrspace(1) poison`, addrspace 1)
+    ; GCN-NEXT: S_WAITCNT_soft .Vmcnt_0
+    ; GCN-NEXT: BUFFER_WBINVL1_VOL implicit $exec
+    ; GCN-NEXT: S_ENDPGM 0
+    renamable $vgpr0_vgpr1 = COPY $sgpr0_sgpr1
+    renamable $vgpr2 = COPY $sgpr2
+    FLAT_ATOMIC_ADD $vgpr0_vgpr1, $vgpr2, 0, 0, implicit $exec, implicit $flat_scr :: (load store syncscope("agent-one-as") seq_cst (s32) on `ptr addrspace(1) poison`), (load store syncscope("workgroup") seq_cst (s32) on `ptr addrspace(1) poison`)
+    S_ENDPGM 0
+...
+---
+name: merge_agent_one_as_and_workgroup_reversed
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $sgpr0, $sgpr1, $sgpr2, $sgpr3
+    ; GCN-LABEL: name: merge_agent_one_as_and_workgroup_reversed
+    ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2, $sgpr3
+    ; GCN-NEXT: {{  $}}
+    ; GCN-NEXT: renamable $vgpr0_vgpr1 = COPY $sgpr0_sgpr1
+    ; GCN-NEXT: renamable $vgpr2 = COPY $sgpr2
+    ; GCN-NEXT: S_WAITCNT_soft .Vmcnt_0_Lgkmcnt_0
+    ; GCN-NEXT: FLAT_ATOMIC_ADD $vgpr0_vgpr1, $vgpr2, 0, 0, implicit $exec, implicit $flat_scr :: (load store syncscope("workgroup") seq_cst (s32) on `ptr addrspace(1) poison`, addrspace 1), (load store syncscope("agent-one-as") seq_cst (s32) on `ptr addrspace(1) poison`, addrspace 1)
+    ; GCN-NEXT: S_WAITCNT_soft .Vmcnt_0
+    ; GCN-NEXT: BUFFER_WBINVL1_VOL implicit $exec
+    ; GCN-NEXT: S_ENDPGM 0
+    renamable $vgpr0_vgpr1 = COPY $sgpr0_sgpr1
+    renamable $vgpr2 = COPY $sgpr2
+    FLAT_ATOMIC_ADD $vgpr0_vgpr1, $vgpr2, 0, 0, implicit $exec, implicit $flat_scr :: (load store syncscope("workgroup") seq_cst (s32) on `ptr addrspace(1) poison`), (load store syncscope("agent-one-as") seq_cst (s32) on `ptr addrspace(1) poison`)
+    S_ENDPGM 0
+...

>From 5e81400fed414c7d702f91f6d64354b8b353f7d9 Mon Sep 17 00:00:00 2001
From: wooseoklee <wolee at amd.com>
Date: Thu, 9 Jul 2026 09:02:33 -0500
Subject: [PATCH 2/5] Address the issue from the reviwer.

---
 .../Target/AMDGPU/AMDGPUMachineModuleInfo.h   | 113 ++++++------------
 1 file changed, 36 insertions(+), 77 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
index b2dd1841f4a55..5062fd8f0e2e2 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
@@ -47,47 +47,6 @@ class AMDGPUMachineModuleInfo final : public MachineModuleInfoELF {
   /// Cluster synchronization scope ID (single address space).
   SyncScope::ID ClusterOneAddressSpaceSSID;
 
-  /// In AMDGPU target synchronization scopes are inclusive, meaning a
-  /// larger synchronization scope is inclusive of a smaller synchronization
-  /// scope.
-  ///
-  /// \returns \p SSID's inclusion ordering, or "std::nullopt" if \p SSID is not
-  /// supported by the AMDGPU target.
-  std::optional<uint8_t>
-  getSyncScopeInclusionOrdering(SyncScope::ID SSID) const {
-    if (SSID == SyncScope::SingleThread ||
-        SSID == getSingleThreadOneAddressSpaceSSID())
-      return 0;
-    else if (SSID == getWavefrontSSID() ||
-             SSID == getWavefrontOneAddressSpaceSSID())
-      return 1;
-    else if (SSID == getWorkgroupSSID() ||
-             SSID == getWorkgroupOneAddressSpaceSSID())
-      return 2;
-    else if (SSID == getClusterSSID() ||
-             SSID == getClusterOneAddressSpaceSSID())
-      return 3;
-    else if (SSID == getAgentSSID() ||
-             SSID == getAgentOneAddressSpaceSSID())
-      return 4;
-    else if (SSID == SyncScope::System ||
-             SSID == getSystemOneAddressSpaceSSID())
-      return 5;
-
-    return std::nullopt;
-  }
-
-  /// \returns True if \p SSID is restricted to single address space, false
-  /// otherwise
-  bool isOneAddressSpace(SyncScope::ID SSID) const {
-    return SSID == getClusterOneAddressSpaceSSID() ||
-           SSID == getSingleThreadOneAddressSpaceSSID() ||
-           SSID == getWavefrontOneAddressSpaceSSID() ||
-           SSID == getWorkgroupOneAddressSpaceSSID() ||
-           SSID == getAgentOneAddressSpaceSSID() ||
-           SSID == getSystemOneAddressSpaceSSID();
-  }
-
 public:
   AMDGPUMachineModuleInfo(const MachineModuleInfo &MMI);
 
@@ -143,45 +102,45 @@ class AMDGPUMachineModuleInfo final : public MachineModuleInfoELF {
   /// supported by the AMDGPU target.
   std::optional<SyncScope::ID> getMergedSyncScopeID(SyncScope::ID A,
                                                     SyncScope::ID B) const {
-    const auto &AIO = getSyncScopeInclusionOrdering(A);
-    const auto &BIO = getSyncScopeInclusionOrdering(B);
-    if (!AIO || !BIO)
+    // Ordered from smallest to largest scope. Level is the index.
+    // Cross-AS and one-AS scopes share the same inclusion ordering level.
+    // Level | Cross-AS scope   | One-AS scope
+    // ------+------------------+----------------------
+    //   0   | singlethread     | singlethread-one-as
+    //   1   | wavefront        | wavefront-one-as
+    //   2   | workgroup        | workgroup-one-as
+    //   3   | cluster          | cluster-one-as
+    //   4   | agent            | agent-one-as
+    //   5   | system           | one-as
+    const SyncScope::ID CrossAS[] = {
+        SyncScope::SingleThread, getWavefrontSSID(), getWorkgroupSSID(),
+        getClusterSSID(),        getAgentSSID(),     SyncScope::System};
+    const SyncScope::ID OneAS[] = {
+        getSingleThreadOneAddressSpaceSSID(), getWavefrontOneAddressSpaceSSID(),
+        getWorkgroupOneAddressSpaceSSID(),    getClusterOneAddressSpaceSSID(),
+        getAgentOneAddressSpaceSSID(),        getSystemOneAddressSpaceSSID()};
+
+    // Returns {level, isOneAS} for a given scope, or nullopt if unsupported.
+    auto GetLevelAndOneAS =
+        [&](SyncScope::ID SSID)
+        -> std::optional<std::pair<unsigned, bool>> {
+      for (unsigned I = 0; I < std::size(CrossAS); ++I) {
+        if (CrossAS[I] == SSID)
+          return std::make_pair(I, false);
+        if (OneAS[I] == SSID)
+          return std::make_pair(I, true);
+      }
+      return std::nullopt;
+    };
+
+    auto AI = GetLevelAndOneAS(A);
+    auto BI = GetLevelAndOneAS(B);
+    if (!AI || !BI)
       return std::nullopt;
 
-    uint8_t Level = std::max(*AIO, *BIO);
+    unsigned Level = std::max(AI->first, BI->first);
     // If either scope is cross-AS, the result must be cross-AS.
-    if (isOneAddressSpace(A) && isOneAddressSpace(B)) {
-      switch (Level) {
-      case 0:
-        return SyncScope::SingleThread;
-      case 1:
-        return getWavefrontOneAddressSpaceSSID();
-      case 2:
-        return getWorkgroupOneAddressSpaceSSID();
-      case 3:
-        return getClusterOneAddressSpaceSSID();
-      case 4:
-        return getAgentOneAddressSpaceSSID();
-      case 5:
-        return getSystemOneAddressSpaceSSID();
-      }
-    } else {
-      switch (Level) {
-      case 0:
-        return SyncScope::SingleThread;
-      case 1:
-        return getWavefrontSSID();
-      case 2:
-        return getWorkgroupSSID();
-      case 3:
-        return getClusterSSID();
-      case 4:
-        return getAgentSSID();
-      case 5:
-        return SyncScope::System;
-      }
-    }
-    return std::nullopt;
+    return (AI->second && BI->second) ? OneAS[Level] : CrossAS[Level];
   }
 };
 

>From 3af06ec874e49378ae972af4106d91bb1c8b18bd Mon Sep 17 00:00:00 2001
From: wooseoklee <wolee at amd.com>
Date: Thu, 9 Jul 2026 09:07:08 -0500
Subject: [PATCH 3/5] Format fix

---
 llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
index 5062fd8f0e2e2..eb77f11ad6ebd 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
@@ -122,8 +122,7 @@ class AMDGPUMachineModuleInfo final : public MachineModuleInfoELF {
 
     // Returns {level, isOneAS} for a given scope, or nullopt if unsupported.
     auto GetLevelAndOneAS =
-        [&](SyncScope::ID SSID)
-        -> std::optional<std::pair<unsigned, bool>> {
+        [&](SyncScope::ID SSID) -> std::optional<std::pair<unsigned, bool>> {
       for (unsigned I = 0; I < std::size(CrossAS); ++I) {
         if (CrossAS[I] == SSID)
           return std::make_pair(I, false);

>From 876394bd0cba1c36a8b7f4c0d4af6c310e70328d Mon Sep 17 00:00:00 2001
From: wooseoklee <wolee at amd.com>
Date: Thu, 9 Jul 2026 15:48:15 -0500
Subject: [PATCH 4/5] Update error messages to start with lower case letters

---
 llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp           | 10 +++++-----
 llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll           |  4 ++--
 .../AMDGPU/memory-legalizer-invalid-addrspace.mir      |  8 ++++----
 .../AMDGPU/memory-legalizer-invalid-syncscope.ll       | 10 +++++-----
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index b90ceffdf5582..00757653082cc 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -876,7 +876,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
       const auto &Merged =
           MMI->getMergedSyncScopeID(CurSSID, MMO->getSyncScopeID());
       if (!Merged) {
-        reportUnsupported(MI, "Unsupported atomic synchronization scope");
+        reportUnsupported(MI, "unsupported atomic synchronization scope");
         return std::nullopt;
       }
       MergedSSID = *Merged;
@@ -902,7 +902,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
   if (Ordering != AtomicOrdering::NotAtomic) {
     auto ScopeOrNone = toSIAtomicScope(SSID, InstrAddrSpace);
     if (!ScopeOrNone) {
-      reportUnsupported(MI, "Unsupported atomic synchronization scope");
+      reportUnsupported(MI, "unsupported atomic synchronization scope");
       return std::nullopt;
     }
     std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
@@ -910,7 +910,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
     if ((OrderingAddrSpace == SIAtomicAddrSpace::NONE) ||
         ((OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) != OrderingAddrSpace) ||
         ((InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) == SIAtomicAddrSpace::NONE)) {
-      reportUnsupported(MI, "Unsupported atomic address space");
+      reportUnsupported(MI, "unsupported atomic address space");
       return std::nullopt;
     }
   }
@@ -961,7 +961,7 @@ SIMemOpAccess::getAtomicFenceInfo(const MachineBasicBlock::iterator &MI) const {
   SyncScope::ID SSID = static_cast<SyncScope::ID>(MI->getOperand(1).getImm());
   auto ScopeOrNone = toSIAtomicScope(SSID, SIAtomicAddrSpace::ATOMIC);
   if (!ScopeOrNone) {
-    reportUnsupported(MI, "Unsupported atomic synchronization scope");
+    reportUnsupported(MI, "unsupported atomic synchronization scope");
     return std::nullopt;
   }
 
@@ -976,7 +976,7 @@ SIMemOpAccess::getAtomicFenceInfo(const MachineBasicBlock::iterator &MI) const {
     // can refine the AS ordered by the fence.
     // If that changes, we need to review the semantics of that function
     // in case it needs to preserve certain address spaces.
-    reportUnsupported(MI, "Unsupported atomic address space");
+    reportUnsupported(MI, "unsupported atomic address space");
     return std::nullopt;
   }
 
diff --git a/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll b/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
index d64366a2b3f9b..9bb18a0e01213 100644
--- a/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
+++ b/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
@@ -1,8 +1,8 @@
 ; RUN: not llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx942 -filetype=null < %s 2>&1 | FileCheck %s
 ; RUN: not llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx942 -filetype=null < %s 2>&1 | FileCheck %s
 
-; CHECK: error: {{.*}}: in function av_load_bad_scope {{.*}}: Unsupported atomic synchronization scope
-; CHECK: error: {{.*}}: in function av_store_bad_scope {{.*}}: Unsupported atomic synchronization scope
+; CHECK: error: {{.*}}: in function av_load_bad_scope {{.*}}: unsupported atomic synchronization scope
+; CHECK: error: {{.*}}: in function av_store_bad_scope {{.*}}: unsupported atomic synchronization scope
 
 define <4 x i32> @av_load_bad_scope(ptr addrspace(1) %p) {
   %v = call <4 x i32> @llvm.amdgcn.av.load.b128.p1(ptr addrspace(1) %p, metadata !0)
diff --git a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir
index 0251284696591..0765761737e51 100644
--- a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir
+++ b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir
@@ -2,7 +2,7 @@
 
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_load void (): Unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_load void (): unsupported atomic address space
 
 name:            invalid_load
 body:             |
@@ -20,7 +20,7 @@ body:             |
 ...
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_store void (): Unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_store void (): unsupported atomic address space
 
 name:            invalid_store
 body:             |
@@ -36,7 +36,7 @@ body:             |
 ...
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_cmpxchg void (): Unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_cmpxchg void (): unsupported atomic address space
 
 name:            invalid_cmpxchg
 body:             |
@@ -53,7 +53,7 @@ body:             |
 ...
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_rmw void (): Unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_rmw void (): unsupported atomic address space
 
 name:            invalid_rmw
 body:             |
diff --git a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
index e820bac9e5ae5..3e41328bc3b2a 100644
--- a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
+++ b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
@@ -4,14 +4,14 @@
 ; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 < %s 2>&1 | FileCheck %s
 ; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 < %s 2>&1 | FileCheck %s
 
-; CHECK: error: <unknown>:0:0: in function invalid_fence void (): Unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_fence void (): unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_fence() {
 entry:
   fence syncscope("invalid") seq_cst
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_load void (ptr, ptr): Unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_load void (ptr, ptr): unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_load(
     ptr %in, ptr %out) {
 entry:
@@ -20,7 +20,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_store void (i32, ptr): Unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_store void (i32, ptr): unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_store(
     i32 %in, ptr %out) {
 entry:
@@ -28,7 +28,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_cmpxchg void (ptr, i32, i32): Unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_cmpxchg void (ptr, i32, i32): unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_cmpxchg(
     ptr %out, i32 %in, i32 %old) {
 entry:
@@ -37,7 +37,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_rmw void (ptr, i32): Unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_rmw void (ptr, i32): unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_rmw(
     ptr %out, i32 %in) {
 entry:

>From 227048529f8188629078707f168608fa44264e43 Mon Sep 17 00:00:00 2001
From: wooseoklee <wolee at amd.com>
Date: Fri, 10 Jul 2026 08:52:29 -0500
Subject: [PATCH 5/5] Address the review. Revert NFC change

---
 llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h       |  6 +++---
 llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp           | 10 +++++-----
 llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll           |  4 ++--
 .../AMDGPU/memory-legalizer-invalid-addrspace.mir      |  8 ++++----
 .../AMDGPU/memory-legalizer-invalid-syncscope.ll       | 10 +++++-----
 5 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
index eb77f11ad6ebd..6aee1bba71335 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMachineModuleInfo.h
@@ -123,10 +123,10 @@ class AMDGPUMachineModuleInfo final : public MachineModuleInfoELF {
     // Returns {level, isOneAS} for a given scope, or nullopt if unsupported.
     auto GetLevelAndOneAS =
         [&](SyncScope::ID SSID) -> std::optional<std::pair<unsigned, bool>> {
-      for (unsigned I = 0; I < std::size(CrossAS); ++I) {
-        if (CrossAS[I] == SSID)
+      for (auto [I, Cross, One] : llvm::enumerate(CrossAS, OneAS)) {
+        if (Cross == SSID)
           return std::make_pair(I, false);
-        if (OneAS[I] == SSID)
+        if (One == SSID)
           return std::make_pair(I, true);
       }
       return std::nullopt;
diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index 00757653082cc..b90ceffdf5582 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -876,7 +876,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
       const auto &Merged =
           MMI->getMergedSyncScopeID(CurSSID, MMO->getSyncScopeID());
       if (!Merged) {
-        reportUnsupported(MI, "unsupported atomic synchronization scope");
+        reportUnsupported(MI, "Unsupported atomic synchronization scope");
         return std::nullopt;
       }
       MergedSSID = *Merged;
@@ -902,7 +902,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
   if (Ordering != AtomicOrdering::NotAtomic) {
     auto ScopeOrNone = toSIAtomicScope(SSID, InstrAddrSpace);
     if (!ScopeOrNone) {
-      reportUnsupported(MI, "unsupported atomic synchronization scope");
+      reportUnsupported(MI, "Unsupported atomic synchronization scope");
       return std::nullopt;
     }
     std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
@@ -910,7 +910,7 @@ std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
     if ((OrderingAddrSpace == SIAtomicAddrSpace::NONE) ||
         ((OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) != OrderingAddrSpace) ||
         ((InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) == SIAtomicAddrSpace::NONE)) {
-      reportUnsupported(MI, "unsupported atomic address space");
+      reportUnsupported(MI, "Unsupported atomic address space");
       return std::nullopt;
     }
   }
@@ -961,7 +961,7 @@ SIMemOpAccess::getAtomicFenceInfo(const MachineBasicBlock::iterator &MI) const {
   SyncScope::ID SSID = static_cast<SyncScope::ID>(MI->getOperand(1).getImm());
   auto ScopeOrNone = toSIAtomicScope(SSID, SIAtomicAddrSpace::ATOMIC);
   if (!ScopeOrNone) {
-    reportUnsupported(MI, "unsupported atomic synchronization scope");
+    reportUnsupported(MI, "Unsupported atomic synchronization scope");
     return std::nullopt;
   }
 
@@ -976,7 +976,7 @@ SIMemOpAccess::getAtomicFenceInfo(const MachineBasicBlock::iterator &MI) const {
     // can refine the AS ordered by the fence.
     // If that changes, we need to review the semantics of that function
     // in case it needs to preserve certain address spaces.
-    reportUnsupported(MI, "unsupported atomic address space");
+    reportUnsupported(MI, "Unsupported atomic address space");
     return std::nullopt;
   }
 
diff --git a/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll b/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
index 9bb18a0e01213..d64366a2b3f9b 100644
--- a/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
+++ b/llvm/test/CodeGen/AMDGPU/av-invalid-scope.ll
@@ -1,8 +1,8 @@
 ; RUN: not llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx942 -filetype=null < %s 2>&1 | FileCheck %s
 ; RUN: not llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx942 -filetype=null < %s 2>&1 | FileCheck %s
 
-; CHECK: error: {{.*}}: in function av_load_bad_scope {{.*}}: unsupported atomic synchronization scope
-; CHECK: error: {{.*}}: in function av_store_bad_scope {{.*}}: unsupported atomic synchronization scope
+; CHECK: error: {{.*}}: in function av_load_bad_scope {{.*}}: Unsupported atomic synchronization scope
+; CHECK: error: {{.*}}: in function av_store_bad_scope {{.*}}: Unsupported atomic synchronization scope
 
 define <4 x i32> @av_load_bad_scope(ptr addrspace(1) %p) {
   %v = call <4 x i32> @llvm.amdgcn.av.load.b128.p1(ptr addrspace(1) %p, metadata !0)
diff --git a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir
index 0765761737e51..0251284696591 100644
--- a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir
+++ b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-addrspace.mir
@@ -2,7 +2,7 @@
 
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_load void (): unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_load void (): Unsupported atomic address space
 
 name:            invalid_load
 body:             |
@@ -20,7 +20,7 @@ body:             |
 ...
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_store void (): unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_store void (): Unsupported atomic address space
 
 name:            invalid_store
 body:             |
@@ -36,7 +36,7 @@ body:             |
 ...
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_cmpxchg void (): unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_cmpxchg void (): Unsupported atomic address space
 
 name:            invalid_cmpxchg
 body:             |
@@ -53,7 +53,7 @@ body:             |
 ...
 ---
 
-# GCN: error: <unknown>:0:0: in function invalid_rmw void (): unsupported atomic address space
+# GCN: error: <unknown>:0:0: in function invalid_rmw void (): Unsupported atomic address space
 
 name:            invalid_rmw
 body:             |
diff --git a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
index 3e41328bc3b2a..e820bac9e5ae5 100644
--- a/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
+++ b/llvm/test/CodeGen/AMDGPU/memory-legalizer-invalid-syncscope.ll
@@ -4,14 +4,14 @@
 ; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 < %s 2>&1 | FileCheck %s
 ; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 < %s 2>&1 | FileCheck %s
 
-; CHECK: error: <unknown>:0:0: in function invalid_fence void (): unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_fence void (): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_fence() {
 entry:
   fence syncscope("invalid") seq_cst
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_load void (ptr, ptr): unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_load void (ptr, ptr): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_load(
     ptr %in, ptr %out) {
 entry:
@@ -20,7 +20,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_store void (i32, ptr): unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_store void (i32, ptr): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_store(
     i32 %in, ptr %out) {
 entry:
@@ -28,7 +28,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_cmpxchg void (ptr, i32, i32): unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_cmpxchg void (ptr, i32, i32): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_cmpxchg(
     ptr %out, i32 %in, i32 %old) {
 entry:
@@ -37,7 +37,7 @@ entry:
   ret void
 }
 
-; CHECK: error: <unknown>:0:0: in function invalid_rmw void (ptr, i32): unsupported atomic synchronization scope
+; CHECK: error: <unknown>:0:0: in function invalid_rmw void (ptr, i32): Unsupported atomic synchronization scope
 define amdgpu_kernel void @invalid_rmw(
     ptr %out, i32 %in) {
 entry:



More information about the llvm-commits mailing list