https://github.com/krzysz00 created https://github.com/llvm/llvm-project/pull/220104
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) <[email protected]> --- <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub> >From b4354fbc56f885abae604ae7510b7ef6cbee96b7 Mon Sep 17 00:00:00 2001 From: Krzysztof Drewniak <[email protected]> Date: Thu, 27 Aug 2026 19:48:44 +0000 Subject: [PATCH] [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) <[email protected]> --- .../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@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@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@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 } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
