[llvm-branch-commits] [mlir] [mlir][AMDGPU][NFC] Pre-commit tests for incorrect version checks (PR #220104)

Krzysztof Drewniak via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Sep 9 13:54:43 PDT 2026


https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/220104

>From ded5397152438af886b38b27814c3cec9dd474e2 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 8 Sep 2026 17:17:38 +0000
Subject: [PATCH 1/2] [mlir][ROCDL] Add `rocdl.xnack` and `rocdl.sramecc`
 module attributes

Since 27eeb7370281, the AMDGPU backend takes the xnack
and sramecc target-ID settings from the `amdgpu.xnack` and
`amdgpu.sramecc` module flags instead subtarget features, making the
old usage a hard error.

This commit adds `rocdl.xnack` and `rocdl.sramecc` module attributes
to the discardable attribute list the ROCDL dialect defines in order
to represent these flags and adds translations for them.

Omitting them means to leave these modifiers at
their default "either" state, which isn't the same as setting them to
false.

AI disclosure: Claude wrote this code and I reviewed it and tried to
reword the comments to something better.
---
 .../mlir/Dialect/LLVMIR/ROCDLDialect.td       | 13 +++++++
 mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp   | 10 +++++
 .../ROCDL/ROCDLToLLVMIRTranslation.cpp        | 18 +++++++++
 mlir/test/Dialect/LLVMIR/rocdl.mlir           | 38 +++++++++++++++++++
 .../Target/LLVMIR/rocdl-module-flags.mlir     | 29 ++++++++++++++
 5 files changed, 108 insertions(+)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
index c92cdd49e8200..a05913bb2c15f 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
@@ -125,6 +125,14 @@ def ROCDL_Dialect : Dialect {
     static constexpr ::llvm::StringLiteral getUniformWorkGroupSizeAttrName() {
       return ::llvm::StringLiteral("rocdl.uniform_work_group_size");
     }
+    /// Get the LLVM module flag key `rocdl.xnack` translates to.
+    static constexpr ::llvm::StringLiteral getModuleFlagKeyXnackName() {
+      return ::llvm::StringLiteral("amdgpu.xnack");
+    }
+    /// Get the LLVM module flag key `rocdl.sramecc` translates to.
+    static constexpr ::llvm::StringLiteral getModuleFlagKeySramEccName() {
+      return ::llvm::StringLiteral("amdgpu.sramecc");
+    }
     /// Get the LLVM module flag key for the AMDGPU buffer OOB mode.
     static constexpr ::llvm::StringLiteral
     getModuleFlagKeyBufferOOBModeName() {
@@ -154,6 +162,11 @@ def ROCDL_Dialect : Dialect {
      "::mlir::IntegerAttr":$max_flat_work_group_size,
      "::mlir::IntegerAttr":$waves_per_eu,
      "::mlir::BoolAttr":$unsafe_fp_atomics,
+     // Boolean attributes for explicitly enabling/disabling xnack or sramecc.
+     // Not setting these is a third "default"/"any" state, and not the same as
+     // false.
+     "::mlir::BoolAttr":$xnack,
+     "::mlir::BoolAttr":$sramecc,
      // Correspond to LLVM metadata of the same name
      "::mlir::UnitAttr":$last_use,
      "::mlir::UnitAttr":$no_remote_memory,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
index e5d2bed07d05c..b508475626a88 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
@@ -103,6 +103,16 @@ LogicalResult ROCDLDialect::verifyOperationAttribute(Operation *op,
                              << "' attribute attached to unexpected op";
     }
   }
+  // xnack/sramecc describe the whole code object.
+  if (attr.getName() == xnackAttrName.getName() ||
+      attr.getName() == srameccAttrName.getName()) {
+    if (!LLVM::satisfiesLLVMModule(op))
+      return op->emitError() << "'" << attr.getName().getValue()
+                             << "' is only supported on modules";
+    if (!isa<BoolAttr>(attr.getValue()))
+      return op->emitError()
+             << "'" << attr.getName().getValue() << "' must be a boolean";
+  }
   return success();
 }
 
diff --git a/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp
index 18eb07a9e17df..00e4164a9f4aa 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp
@@ -149,6 +149,24 @@ class ROCDLDialectLLVMIRTranslationInterface
       else
         llvmFunc->removeFnAttr("uniform-work-group-size");
     }
+
+    bool isXnack =
+        dialect->getXnackAttrHelper().getName() == attribute.getName();
+    bool isSramecc =
+        dialect->getSrameccAttrHelper().getName() == attribute.getName();
+    if (isXnack || isSramecc) {
+      auto value = dyn_cast<BoolAttr>(attribute.getValue());
+      if (!value)
+        return op->emitOpError(Twine(attribute.getName()) +
+                               " must be a boolean");
+      StringRef key = isXnack
+                          ? ROCDL::ROCDLDialect::getModuleFlagKeyXnackName()
+                          : ROCDL::ROCDLDialect::getModuleFlagKeySramEccName();
+      moduleTranslation.getLLVMModule()->addModuleFlag(
+          llvm::Module::Error, key,
+          llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvmContext),
+                                 value.getValue()));
+    }
     if (dialect->getUnsafeFpAtomicsAttrHelper().getName() ==
         attribute.getName()) {
       auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
diff --git a/mlir/test/Dialect/LLVMIR/rocdl.mlir b/mlir/test/Dialect/LLVMIR/rocdl.mlir
index 6a6f99ac7d2e7..58e337ae771df 100644
--- a/mlir/test/Dialect/LLVMIR/rocdl.mlir
+++ b/mlir/test/Dialect/LLVMIR/rocdl.mlir
@@ -1856,6 +1856,44 @@ module {
 
 // -----
 
+// CHECK-LABEL: module @module_target_id_settings
+// CHECK-SAME: attributes {rocdl.sramecc = false, rocdl.xnack = true}
+module @module_target_id_settings attributes {
+    rocdl.xnack = true, rocdl.sramecc = false} {
+}
+
+// -----
+
+// CHECK-LABEL: gpu.module @gpu_module_target_id_settings
+// CHECK-SAME: attributes {rocdl.sramecc = true, rocdl.xnack = false}
+gpu.module @gpu_module_target_id_settings attributes {
+    rocdl.xnack = false, rocdl.sramecc = true} {
+}
+
+// -----
+
+// expected-error at below {{'rocdl.xnack' is only supported on modules}}
+llvm.func private @xnack_on_func() attributes {rocdl.xnack = true}
+
+// -----
+
+// expected-error at below {{'rocdl.sramecc' is only supported on modules}}
+llvm.func private @sramecc_on_func() attributes {rocdl.sramecc = true}
+
+// -----
+
+// expected-error at below {{'rocdl.xnack' must be a boolean}}
+module attributes {rocdl.xnack = "on"} {
+}
+
+// -----
+
+// expected-error at below {{'rocdl.sramecc' must be a boolean}}
+module attributes {rocdl.sramecc = 1 : i32} {
+}
+
+// -----
+
 // Just check these don't emit errors.
 gpu.module @module_1 [#rocdl.target<O = 1, chip = "gfx900", abi = "500", link = ["my_device_lib.bc"], flags = {fast, daz, unsafe_math}>] {
 }
diff --git a/mlir/test/Target/LLVMIR/rocdl-module-flags.mlir b/mlir/test/Target/LLVMIR/rocdl-module-flags.mlir
index 8e1db326e7f28..2f67770190b13 100644
--- a/mlir/test/Target/LLVMIR/rocdl-module-flags.mlir
+++ b/mlir/test/Target/LLVMIR/rocdl-module-flags.mlir
@@ -45,3 +45,32 @@ module {
 // CHECK-LABEL: define void @generic_oob_relaxed()
 // CHECK: !llvm.module.flags = !{![[GENERIC_BUFFER_RELAXED:[0-9]+]]
 // CHECK-DAG: ![[GENERIC_BUFFER_RELAXED]] = !{i32 7, !"amdgpu.buffer.oob.mode", i32 1}
+
+// -----
+
+module attributes {rocdl.xnack = true, rocdl.sramecc = false} {
+  llvm.func @xnack_on_sramecc_off() {
+    llvm.return
+  }
+}
+
+// CHECK-LABEL: define void @xnack_on_sramecc_off()
+// CHECK: !llvm.module.flags = !{![[SRAMECC_OFF:[0-9]+]], ![[XNACK_ON:[0-9]+]]
+// CHECK-DAG: ![[SRAMECC_OFF]] = !{i32 1, !"amdgpu.sramecc", i32 0}
+// CHECK-DAG: ![[XNACK_ON]] = !{i32 1, !"amdgpu.xnack", i32 1}
+
+// -----
+
+// An unmentioned setting stays unmentioned: the backend reads that as "either",
+// which is not the same as the feature being disabled.
+
+module attributes {rocdl.xnack = false} {
+  llvm.func @xnack_off_sramecc_any() {
+    llvm.return
+  }
+}
+
+// CHECK-LABEL: define void @xnack_off_sramecc_any()
+// CHECK: !llvm.module.flags = !{![[XNACK_OFF:[0-9]+]]
+// CHECK-DAG: ![[XNACK_OFF]] = !{i32 1, !"amdgpu.xnack", i32 0}
+// CHECK-NOT: amdgpu.sramecc

>From 1d99f657626c38c3cf916ba3c05fb512799069a4 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Thu, 27 Aug 2026 19:48:44 +0000
Subject: [PATCH 2/2] [mlir][AMDGPU][NFC] Pre-commit tests for incorrect
 version checks

There'll be a refactoring from `amdgpu::Chipset` to
`ROCDL::TargetInfo`, thus also moving from chip version checks to
features checks. This commit adds tests for incorrect lowerings that
were allowed by the current code.

- gfx90c is >= gfx90a but stil needs atomic emulation (it doesn't
  have buffer fmax and so on).
- gfx90c is also >= gfx90a but has no barrier back-off, so it needs
  the inline asm workaround around `s_barrier` that it isn't getting
- gfx908 doesn't have a packed fp16 atomic add but we thought it did
- gfx950 is mistakenly allowing xf32 MFMAs
- gfx1200 is allowing permlane_swap instructions that it doesn't have
- gfx11.7 should be allowing OCP FP8 conversions but isn't on the list

This also cleans up some redundant tests with a --check-prefixes

AI disclosure: Claude found these and wrote the tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
 .../8-bit-floats-ocp-gfx1170.mlir             | 28 ++++++++
 .../AMDGPUToROCDL/lds-barrier-gfx90c.mlir     | 15 ++++
 .../Conversion/AMDGPUToROCDL/mfma-gfx950.mlir | 14 ++++
 .../Conversion/AMDGPUToROCDL/permlane.mlir    |  4 ++
 .../AMDGPU/amdgpu-emulate-atomics.mlir        | 69 ++++++++++---------
 5 files changed, 97 insertions(+), 33 deletions(-)
 create mode 100644 mlir/test/Conversion/AMDGPUToROCDL/8-bit-floats-ocp-gfx1170.mlir
 create mode 100644 mlir/test/Conversion/AMDGPUToROCDL/lds-barrier-gfx90c.mlir

diff --git a/mlir/test/Conversion/AMDGPUToROCDL/8-bit-floats-ocp-gfx1170.mlir b/mlir/test/Conversion/AMDGPUToROCDL/8-bit-floats-ocp-gfx1170.mlir
new file mode 100644
index 0000000000000..27692d540e5d4
--- /dev/null
+++ b/mlir/test/Conversion/AMDGPUToROCDL/8-bit-floats-ocp-gfx1170.mlir
@@ -0,0 +1,28 @@
+// RUN: mlir-opt %s --convert-amdgpu-to-rocdl=chipset=gfx1170 --split-input-file --verify-diagnostics
+
+// gfx11.7 has FeatureOCPFP8ConversionInsts, so these conversions are available
+// on it. They are rejected today because the predicate deciding whether a
+// target uses the OCP fp8 formats is written as the version range "gfx9.5+ or
+// gfx12+", which skips over gfx11.7 entirely.
+
+func.func @ext_packed_fp8(%v: vector<4xf8E4M3FN>) -> f32 {
+  // expected-error at below {{failed to legalize operation 'amdgpu.ext_packed_fp8'}}
+  %ret = amdgpu.ext_packed_fp8 %v[0] : vector<4xf8E4M3FN> to f32
+  func.return %ret : f32
+}
+
+// -----
+
+func.func @ext_packed_bf8(%v: vector<4xf8E5M2>) -> f32 {
+  // expected-error at below {{failed to legalize operation 'amdgpu.ext_packed_fp8'}}
+  %ret = amdgpu.ext_packed_fp8 %v[0] : vector<4xf8E5M2> to f32
+  func.return %ret : f32
+}
+
+// -----
+
+func.func @packed_trunc_2xfp8(%v: f32) -> vector<4xf8E4M3FN> {
+  // expected-error at below {{failed to legalize operation 'amdgpu.packed_trunc_2xfp8'}}
+  %ret = amdgpu.packed_trunc_2xfp8 %v, undef into undef[word 0] : f32 to vector<4xf8E4M3FN>
+  func.return %ret : vector<4xf8E4M3FN>
+}
diff --git a/mlir/test/Conversion/AMDGPUToROCDL/lds-barrier-gfx90c.mlir b/mlir/test/Conversion/AMDGPUToROCDL/lds-barrier-gfx90c.mlir
new file mode 100644
index 0000000000000..d1c9919eb0d59
--- /dev/null
+++ b/mlir/test/Conversion/AMDGPUToROCDL/lds-barrier-gfx90c.mlir
@@ -0,0 +1,15 @@
+// RUN: mlir-opt %s -convert-amdgpu-to-rocdl=chipset=gfx90c | FileCheck %s
+
+// gfx90c sorts after gfx90a, so the version comparison guarding the inline asm
+// workaround treats it as having the hardware barrier back-off. It does not:
+// gfx90c is a Renoir-class APU and lacks FeatureBackOffBarrier, so a bare
+// s_barrier lets waits on global memory be introduced around the barrier.
+
+// CHECK-LABEL: func @lds_barrier
+func.func @lds_barrier() {
+  // CHECK: llvm.fence syncscope("workgroup") release
+  // CHECK-NEXT: rocdl.s.barrier
+  // CHECK-NEXT: llvm.fence syncscope("workgroup") acquire
+  amdgpu.lds_barrier
+  func.return
+}
diff --git a/mlir/test/Conversion/AMDGPUToROCDL/mfma-gfx950.mlir b/mlir/test/Conversion/AMDGPUToROCDL/mfma-gfx950.mlir
index ace99fd89625a..d124c33f19144 100644
--- a/mlir/test/Conversion/AMDGPUToROCDL/mfma-gfx950.mlir
+++ b/mlir/test/Conversion/AMDGPUToROCDL/mfma-gfx950.mlir
@@ -96,3 +96,17 @@ func.func @scaled_mfma_to_rocdl(%arg0 : vector<16xf32>,
 
   func.return
 }
+
+// gfx950 does not have the xf32 MFMAs -- FeatureXF32Insts is set on gfx942
+// only -- but it compares greater than gfx942 by ISA version, so the
+// reduced-precision f32 MFMAs are currently selected for it.
+// CHECK-LABEL: func @mfma_reduce_precision_to_rocdl
+func.func @mfma_reduce_precision_to_rocdl(%arg0 : vector<2xf32>,
+                                          %arg1 : vector<16xf32>,
+                                          %arg2 : vector<4xf32>) {
+  // CHECK: rocdl.mfma.f32.32x32x4.xf32
+  amdgpu.mfma 32x32x4 %arg0 * %arg0 + %arg1 reducePrecision : vector<2xf32>, vector<2xf32>, vector<16xf32>
+  // CHECK: rocdl.mfma.f32.16x16x8.xf32
+  amdgpu.mfma 16x16x8 %arg0 * %arg0 + %arg2 reducePrecision : vector<2xf32>, vector<2xf32>, vector<4xf32>
+  func.return
+}
diff --git a/mlir/test/Conversion/AMDGPUToROCDL/permlane.mlir b/mlir/test/Conversion/AMDGPUToROCDL/permlane.mlir
index 660e34a62cc5e..a8643604abb5f 100755
--- a/mlir/test/Conversion/AMDGPUToROCDL/permlane.mlir
+++ b/mlir/test/Conversion/AMDGPUToROCDL/permlane.mlir
@@ -1,4 +1,8 @@
 // RUN: mlir-opt --convert-amdgpu-to-rocdl=chipset=gfx950 --canonicalize %s | FileCheck %s
+// The permlane swaps come from FeaturePermlane16Swap/FeaturePermlane32Swap,
+// which gfx1200 does not have -- but it compares greater than gfx950 by ISA
+// version, so `chipset < kGfx950` lets it through and it lowers identically.
+// RUN: mlir-opt --convert-amdgpu-to-rocdl=chipset=gfx1200 --canonicalize %s | FileCheck %s
 
 // CHECK-LABEL: func @test_permlane16_i32
 // CHECK-SAME: (%[[ARG0:.*]]: i32)
diff --git a/mlir/test/Dialect/AMDGPU/amdgpu-emulate-atomics.mlir b/mlir/test/Dialect/AMDGPU/amdgpu-emulate-atomics.mlir
index 08896158ac7f7..fa883bb96c1a0 100644
--- a/mlir/test/Dialect/AMDGPU/amdgpu-emulate-atomics.mlir
+++ b/mlir/test/Dialect/AMDGPU/amdgpu-emulate-atomics.mlir
@@ -1,9 +1,11 @@
-// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx90a %s | FileCheck %s --check-prefixes=CHECK,GFX90A
+// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx908 %s | FileCheck %s --check-prefixes=CHECK,GFX9CAS,GFX908
+// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx90a %s | FileCheck %s --check-prefixes=CHECK,GFX9CAS,GFX90A
+// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx90c %s | FileCheck %s --check-prefixes=CHECK,GFX9CAS,GFX90C
 // RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx1030 %s | FileCheck %s --check-prefixes=CHECK,GFX10
 // RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx1100 %s | FileCheck %s --check-prefixes=CHECK,GFX11
 // RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx1200 %s | FileCheck %s --check-prefixes=CHECK,GFX12
-// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx942 %s | FileCheck %s --check-prefixes=CHECK,GFX942
-// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx950 %s | FileCheck %s --check-prefixes=CHECK,GFX950
+// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx942 %s | FileCheck %s --check-prefixes=CHECK,GFX9CAS,GFX942
+// RUN: mlir-opt -split-input-file -amdgpu-emulate-atomics=chipset=gfx950 %s | FileCheck %s --check-prefixes=CHECK,GFX9CAS,GFX950
 
 // -----
 
@@ -14,36 +16,16 @@ func.func @atomic_fmax(%val: f32, %buffer: memref<?xf32>, %idx: i32) -> f32 {
 // GFX10: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) {foo} [[val]] -> [[buffer]][[[idx]]]
 // GFX11: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) {foo} [[val]] -> [[buffer]][[[idx]]]
 // GFX12: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) {foo} [[val]] -> [[buffer]][[[idx]]]
-// GFX90A: [[ld:%.+]] = amdgpu.raw_buffer_load boundsCheck(true) {foo} [[buffer]][[[idx]]]
-// GFX90A:  cf.br [[loop:\^.+]]([[ld]] : f32)
-// GFX90A:  [[loop]]([[arg:%.+]]: f32):
-// GFX90A:  [[operated:%.+]] = arith.maximumf [[val]], [[arg]]
-// GFX90A: [[atomicRes:%.+]] = amdgpu.raw_buffer_atomic_cmpswap boundsCheck(true) {foo} [[operated]], [[arg]] -> [[buffer]][[[idx]]]
-// GFX90A:  [[argCast:%.+]] = arith.bitcast [[arg]] : f32 to i32
-// GFX90A:  [[resCast:%.+]] = arith.bitcast [[atomicRes]] : f32 to i32
-// GFX90A:  [[test:%.+]] = arith.cmpi eq, [[resCast]], [[argCast]]
-// GFX90A:  cf.cond_br [[test]], [[post:\^.+]]([[arg]] : f32), [[loop]]([[atomicRes]] : f32)
-// GFX90A:  [[post]]([[old:%.+]]: f32):
-// GFX942: [[ld:%.+]] = amdgpu.raw_buffer_load boundsCheck(true) {foo} [[buffer]][[[idx]]]
-// GFX942:  cf.br [[loop:\^.+]]([[ld]] : f32)
-// GFX942:  [[loop]]([[arg:%.+]]: f32):
-// GFX942:  [[operated:%.+]] = arith.maximumf [[val]], [[arg]]
-// GFX942: [[atomicRes:%.+]] = amdgpu.raw_buffer_atomic_cmpswap boundsCheck(true) {foo} [[operated]], [[arg]] -> [[buffer]][[[idx]]]
-// GFX942:  [[argCast:%.+]] = arith.bitcast [[arg]] : f32 to i32
-// GFX942:  [[resCast:%.+]] = arith.bitcast [[atomicRes]] : f32 to i32
-// GFX942:  [[test:%.+]] = arith.cmpi eq, [[resCast]], [[argCast]]
-// GFX942:  cf.cond_br [[test]], [[post:\^.+]]([[arg]] : f32), [[loop]]([[atomicRes]] : f32)
-// GFX942:  [[post]]([[old:%.+]]: f32):
-// GFX950: [[ld:%.+]] = amdgpu.raw_buffer_load boundsCheck(true) {foo} [[buffer]][[[idx]]]
-// GFX950:  cf.br [[loop:\^.+]]([[ld]] : f32)
-// GFX950:  [[loop]]([[arg:%.+]]: f32):
-// GFX950:  [[operated:%.+]] = arith.maximumf [[val]], [[arg]]
-// GFX950: [[atomicRes:%.+]] = amdgpu.raw_buffer_atomic_cmpswap boundsCheck(true) {foo} [[operated]], [[arg]] -> [[buffer]][[[idx]]]
-// GFX950:  [[argCast:%.+]] = arith.bitcast [[arg]] : f32 to i32
-// GFX950:  [[resCast:%.+]] = arith.bitcast [[atomicRes]] : f32 to i32
-// GFX950:  [[test:%.+]] = arith.cmpi eq, [[resCast]], [[argCast]]
-// GFX950:  cf.cond_br [[test]], [[post:\^.+]]([[arg]] : f32), [[loop]]([[atomicRes]] : f32)
-// GFX950:  [[post]]([[old:%.+]]: f32):
+// GFX9CAS: [[ld:%.+]] = amdgpu.raw_buffer_load boundsCheck(true) {foo} [[buffer]][[[idx]]]
+// GFX9CAS:  cf.br [[loop:\^.+]]([[ld]] : f32)
+// GFX9CAS:  [[loop]]([[arg:%.+]]: f32):
+// GFX9CAS:  [[operated:%.+]] = arith.maximumf [[val]], [[arg]]
+// GFX9CAS: [[atomicRes:%.+]] = amdgpu.raw_buffer_atomic_cmpswap boundsCheck(true) {foo} [[operated]], [[arg]] -> [[buffer]][[[idx]]]
+// GFX9CAS:  [[argCast:%.+]] = arith.bitcast [[arg]] : f32 to i32
+// GFX9CAS:  [[resCast:%.+]] = arith.bitcast [[atomicRes]] : f32 to i32
+// GFX9CAS:  [[test:%.+]] = arith.cmpi eq, [[resCast]], [[argCast]]
+// GFX9CAS:  cf.cond_br [[test]], [[post:\^.+]]([[arg]] : f32), [[loop]]([[atomicRes]] : f32)
+// GFX9CAS:  [[post]]([[old:%.+]]: f32):
 // CHECK-NEXT: gpu.printf "End\0A"
 // CHECK-NEXT: return
   gpu.printf "Begin\n"
@@ -64,6 +46,19 @@ func.func @atomic_fmax_f64(%val: f64, %buffer: memref<?xf64>, %idx: i32) {
 // GFX12: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) [[val]] -> [[buffer]][[[idx]]]
 // GFX942: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) [[val]] -> [[buffer]][[[idx]]]
 // GFX950: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) [[val]] -> [[buffer]][[[idx]]]
+// gfx908 has no f64 buffer fmin/fmax, so it is emulated.
+// GFX908:  [[ld:%.+]] = amdgpu.raw_buffer_load boundsCheck(true) [[buffer]][[[idx]]]
+// GFX908:  cf.br [[loop:\^.+]]([[ld]] : f64)
+// GFX908:  [[loop]]([[arg:%.+]]: f64):
+// GFX908:  [[operated:%.+]] = arith.maximumf [[val]], [[arg]]
+// GFX908: [[atomicRes:%.+]] = amdgpu.raw_buffer_atomic_cmpswap boundsCheck(true) [[operated]], [[arg]] -> [[buffer]][[[idx]]]
+// GFX908:  [[argCast:%.+]] = arith.bitcast [[arg]] : f64 to i64
+// GFX908:  [[resCast:%.+]] = arith.bitcast [[atomicRes]] : f64 to i64
+// GFX908:  [[test:%.+]] = arith.cmpi eq, [[resCast]], [[argCast]]
+// GFX908:  cf.cond_br [[test]], [[post:\^.+]]([[arg]] : f64), [[loop]]([[atomicRes]] : f64)
+// GFX908:  [[post]]([[old:%.+]]: f64):
+// gfx90c has none either, but sorts after gfx90a by ISA version.
+// GFX90C: amdgpu.raw_buffer_atomic_fmax boundsCheck(true) [[val]] -> [[buffer]][[[idx]]]
 // CHECK-NEXT: gpu.printf "End\0A"
   gpu.printf "Begin\n"
   %old = amdgpu.raw_buffer_atomic_fmax boundsCheck(true) %val -> %buffer[%idx] : f64 -> memref<?xf64>, i32
@@ -82,6 +77,8 @@ func.func @atomic_fadd(%val: f32, %buffer: memref<?xf32>, %idx: i32) {
 // GFX12: amdgpu.raw_buffer_atomic_fadd
 // GFX942: amdgpu.raw_buffer_atomic_fadd
 // GFX950: amdgpu.raw_buffer_atomic_fadd
+// GFX908: amdgpu.raw_buffer_atomic_fadd
+// GFX90C: amdgpu.raw_buffer_atomic_fadd
   %old = amdgpu.raw_buffer_atomic_fadd boundsCheck(true) %val -> %buffer[%idx] : f32 -> memref<?xf32>, i32
   func.return
 }
@@ -103,6 +100,8 @@ func.func @atomic_fadd_v2f16(%val: vector<2xf16>, %buffer: memref<?xf16>, %idx:
 // GFX942: amdgpu.raw_buffer_atomic_fadd
 // GFX12:  amdgpu.raw_buffer_atomic_fadd
 // GFX950:  amdgpu.raw_buffer_atomic_fadd
+// GFX908: amdgpu.raw_buffer_atomic_fadd
+// GFX90C: amdgpu.raw_buffer_atomic_fadd
   %old = amdgpu.raw_buffer_atomic_fadd boundsCheck(true) %val -> %buffer[%idx] : vector<2xf16> -> memref<?xf16>, i32
   func.return
 }
@@ -119,6 +118,10 @@ func.func @atomic_fadd_v2bf16(%val: vector<2xbf16>, %buffer: memref<?xbf16>, %id
 // GFX942: amdgpu.raw_buffer_atomic_cmpswap
 // GFX12:  amdgpu.raw_buffer_atomic_fadd
 // GFX950:  amdgpu.raw_buffer_atomic_fadd
+// GFX908: amdgpu.raw_buffer_load
+// GFX908: amdgpu.raw_buffer_atomic_cmpswap
+// GFX90C: amdgpu.raw_buffer_load
+// GFX90C: amdgpu.raw_buffer_atomic_cmpswap
   %old = amdgpu.raw_buffer_atomic_fadd boundsCheck(true) %val -> %buffer[%idx] : vector<2xbf16> -> memref<?xbf16>, i32
   func.return
 }



More information about the llvm-branch-commits mailing list