[clang] [llvm] [mlir] [AMDGPU] Introduce builtin, intrinsic and ROCDL instruction for buffer_inv (PR #228497)
Dan Zimmerman via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 2 09:56:40 PDT 2026
https://github.com/danzimm updated https://github.com/llvm/llvm-project/pull/228497
>From 7633649bf23094e0cb9b2f3159270c521477512d Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Wed, 23 Sep 2026 09:12:41 -0700
Subject: [PATCH 1/7] [AMDGPU] Add buffer_inv subtarget feature
---
llvm/lib/Target/AMDGPU/AMDGPU.td | 8 +++++++-
llvm/unittests/TargetParser/TargetParserTest.cpp | 12 ++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 90a0871ff3669..6b2c4bc27af98 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -510,6 +510,10 @@ defm GFX940Insts : AMDGPUSubtargetFeature<"gfx940-insts",
/*GenPredicate=*/0
>;
+defm BufferInvInst : AMDGPUSubtargetFeature<"buffer-inv-inst",
+ "Has buffer_inv instruction"
+>;
+
defm Permlane16Insts : AMDGPUSubtargetFeature<"permlane16-insts",
"Has v_permlane16_b32/v_permlanex16_b32 instructions"
>;
@@ -2101,6 +2105,7 @@ def FeatureISAVersion9_4_Common : FeatureSet<
FeatureAGPRAlloc,
FeatureTgSplitSupport,
FeatureGFX940Insts,
+ FeatureBufferInvInst,
FeatureRequiresAlignedVGPRs,
FeatureFmaMixInsts,
FeatureDLInsts,
@@ -3357,7 +3362,8 @@ def AMDGPUFrontendVisibleFeatures {
FeatureAtomicFaddRtnInsts, FeatureAtomicFlatPkAdd16Insts, FeatureAtomicGlobalPkAddBF16Inst,
FeatureBF16ConversionInsts,
FeatureBF16PackedInsts, FeatureBF16TransInsts, FeatureBF8ConversionScaleInsts,
- FeatureBVHRayTracingInsts, FeatureBitOp3Insts, FeatureCIInsts,
+ FeatureBVHRayTracingInsts, FeatureBitOp3Insts, FeatureBufferInvInst,
+ FeatureCIInsts,
FeatureClusters, FeatureCubeInsts, FeatureCvtPkNormVOP2Insts,
FeatureCvtSrPkBF16F32Inst, FeatureDLInsts, FeatureDPP,
FeatureDot10Insts, FeatureDot11Insts, FeatureDot12Insts,
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 78a13daac2867..6e0e469f75fd4 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -2877,6 +2877,18 @@ TEST(TargetParserTest, testAMDGPUgetFeatureBitset) {
EXPECT_TRUE(Empty.empty());
}
+TEST(TargetParserTest, testAMDGPUBufferInvInstFeature) {
+ auto Has = [](AMDGPU::GPUKind AK) {
+ return AMDGPU::getFeatureBitset(AK).test(AMDGPU::FEAT_BUFFER_INV_INST);
+ };
+
+ EXPECT_FALSE(Has(AMDGPU::GK_GFX90A));
+ EXPECT_TRUE(Has(AMDGPU::GK_GFX942));
+ EXPECT_TRUE(Has(AMDGPU::GK_GFX950));
+ EXPECT_TRUE(Has(AMDGPU::GK_GFX9_4_GENERIC));
+ EXPECT_FALSE(Has(AMDGPU::GK_GFX1250));
+}
+
TEST(TargetParserTest, testAMDGPUHalfAddressableLDSFeature) {
auto Has = [](AMDGPU::GPUKind AK) {
return AMDGPU::getFeatureBitset(AK).test(
>From cd9af185bd50a5e2d35f3a057117a5b6363b1028 Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Thu, 24 Sep 2026 10:20:47 -0700
Subject: [PATCH 2/7] [AMDGPU] Use BufferInvInst for buffer_inv predicates
---
llvm/lib/Target/AMDGPU/BUFInstructions.td | 8 +++++---
llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s | 10 ++++++++++
2 files changed, 15 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s
diff --git a/llvm/lib/Target/AMDGPU/BUFInstructions.td b/llvm/lib/Target/AMDGPU/BUFInstructions.td
index 057c0f103ce80..2b5d20c6849f7 100644
--- a/llvm/lib/Target/AMDGPU/BUFInstructions.td
+++ b/llvm/lib/Target/AMDGPU/BUFInstructions.td
@@ -1429,7 +1429,7 @@ let SubtargetPredicate = HasAtomicFMinFMaxF64GlobalInsts in {
}
def BUFFER_INV : MUBUF_Invalidate<"buffer_inv"> {
- let SubtargetPredicate = isGFX940Plus;
+ let SubtargetPredicate = HasBufferInvInst;
let has_glc = 1;
let has_sccb = 1;
let InOperandList = (ins CPol_0:$cpol);
@@ -3660,10 +3660,12 @@ let AsmString = BUFFER_WBL2.Mnemonic, // drop flags
defm BUFFER_WBL2 : MUBUF_Real_gfx90a<0x28>;
defm BUFFER_INVL2 : MUBUF_Real_gfx90a<0x29>;
-let SubtargetPredicate = isGFX940Plus in {
+let SubtargetPredicate = isGFX940Plus in
def BUFFER_WBL2_gfx940 : MUBUF_Real_gfx940<0x28, BUFFER_WBL2>;
+
+let SubtargetPredicate = HasBufferInvInst,
+ AssemblerPredicate = HasBufferInvInst in
def BUFFER_INV_gfx940 : MUBUF_Real_gfx940<0x29, BUFFER_INV>;
-}
class MTBUF_Real_Base_vi <bits<4> op, MTBUF_Pseudo ps, int Enc> :
MTBUF_Real<ps>,
diff --git a/llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s b/llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s
new file mode 100644
index 0000000000000..52d7c4e5eed49
--- /dev/null
+++ b/llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -triple=amdgpu9.42 -show-encoding %s | FileCheck --check-prefix=SUPPORTED %s
+// RUN: llvm-mc -triple=amdgpu9.50 -show-encoding %s | FileCheck --check-prefix=SUPPORTED %s
+// RUN: llvm-mc -triple=amdgcn-amd-amdhsa -mcpu=gfx9-4-generic -show-encoding %s | FileCheck --check-prefix=SUPPORTED %s
+// RUN: not llvm-mc -triple=amdgpu9.0a -filetype=null %s 2>&1 | FileCheck --check-prefix=GFX90A %s
+// RUN: not llvm-mc -triple=amdgpu9.42 -mattr=-buffer-inv-inst -filetype=null %s 2>&1 | FileCheck --check-prefix=DISABLED %s
+
+buffer_inv sc0 sc1
+// SUPPORTED: buffer_inv sc0 sc1 ; encoding: [0x00,0xc0,0xa4,0xe0,0x00,0x00,0x00,0x00]
+// GFX90A: error: instruction not supported on this GPU (gfx90a): buffer_inv
+// DISABLED: error: instruction not supported on this GPU (gfx942): buffer_inv
>From 42555ef11329ae4681e0c8e329ce2ddad2e6d2ae Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Thu, 24 Sep 2026 10:21:38 -0700
Subject: [PATCH 3/7] [AMDGPU] Use BufferInvInst in memory legalizer
---
llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
index e818e06e3bb04..10804d65b82b0 100644
--- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp
@@ -1396,7 +1396,7 @@ bool SIGfx6CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
if (canAffectGlobalAddrSpace(AddrSpace)) {
switch (Scope) {
case SIAtomicScope::SYSTEM:
- if (ST.hasGFX940Insts()) {
+ if (ST.hasBufferInvInst()) {
// Ensures that following loads will not see stale remote VMEM data or
// stale local VMEM data with MTYPE NC. Local VMEM data with MTYPE RW
// and CC will never be stale due to the local memory probes.
@@ -1428,7 +1428,7 @@ bool SIGfx6CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
}
[[fallthrough]];
case SIAtomicScope::AGENT:
- if (ST.hasGFX940Insts()) {
+ if (ST.hasBufferInvInst()) {
// Ensures that following loads will not see stale remote date or local
// MTYPE NC global data. Local MTYPE RW and CC memory will never be
// stale due to the memory probes.
@@ -1445,7 +1445,7 @@ bool SIGfx6CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
break;
case SIAtomicScope::WORKGROUP:
if (TgSplitEnabled) {
- if (ST.hasGFX940Insts()) {
+ if (ST.hasBufferInvInst()) {
// In threadgroup split mode the waves of a work-group can be
// executing on different CUs. Therefore need to invalidate the L1
// which is per CU. Otherwise in non-threadgroup split mode all waves
>From f996c6abd726e004adde5d275b42cbbc5caaa29c Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Thu, 24 Sep 2026 14:44:56 -0700
Subject: [PATCH 4/7] [AMDGPU] Remove redundant buffer_inv feature tests
---
llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s | 10 ----------
llvm/unittests/TargetParser/TargetParserTest.cpp | 12 ------------
2 files changed, 22 deletions(-)
delete mode 100644 llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s
diff --git a/llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s b/llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s
deleted file mode 100644
index 52d7c4e5eed49..0000000000000
--- a/llvm/test/MC/AMDGPU/buffer-inv-subtarget-feature.s
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: llvm-mc -triple=amdgpu9.42 -show-encoding %s | FileCheck --check-prefix=SUPPORTED %s
-// RUN: llvm-mc -triple=amdgpu9.50 -show-encoding %s | FileCheck --check-prefix=SUPPORTED %s
-// RUN: llvm-mc -triple=amdgcn-amd-amdhsa -mcpu=gfx9-4-generic -show-encoding %s | FileCheck --check-prefix=SUPPORTED %s
-// RUN: not llvm-mc -triple=amdgpu9.0a -filetype=null %s 2>&1 | FileCheck --check-prefix=GFX90A %s
-// RUN: not llvm-mc -triple=amdgpu9.42 -mattr=-buffer-inv-inst -filetype=null %s 2>&1 | FileCheck --check-prefix=DISABLED %s
-
-buffer_inv sc0 sc1
-// SUPPORTED: buffer_inv sc0 sc1 ; encoding: [0x00,0xc0,0xa4,0xe0,0x00,0x00,0x00,0x00]
-// GFX90A: error: instruction not supported on this GPU (gfx90a): buffer_inv
-// DISABLED: error: instruction not supported on this GPU (gfx942): buffer_inv
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 6e0e469f75fd4..78a13daac2867 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -2877,18 +2877,6 @@ TEST(TargetParserTest, testAMDGPUgetFeatureBitset) {
EXPECT_TRUE(Empty.empty());
}
-TEST(TargetParserTest, testAMDGPUBufferInvInstFeature) {
- auto Has = [](AMDGPU::GPUKind AK) {
- return AMDGPU::getFeatureBitset(AK).test(AMDGPU::FEAT_BUFFER_INV_INST);
- };
-
- EXPECT_FALSE(Has(AMDGPU::GK_GFX90A));
- EXPECT_TRUE(Has(AMDGPU::GK_GFX942));
- EXPECT_TRUE(Has(AMDGPU::GK_GFX950));
- EXPECT_TRUE(Has(AMDGPU::GK_GFX9_4_GENERIC));
- EXPECT_FALSE(Has(AMDGPU::GK_GFX1250));
-}
-
TEST(TargetParserTest, testAMDGPUHalfAddressableLDSFeature) {
auto Has = [](AMDGPU::GPUKind AK) {
return AMDGPU::getFeatureBitset(AK).test(
>From 72149a67c9dc254d13d0bca6b9836094dee1ee41 Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Thu, 24 Sep 2026 14:48:12 -0700
Subject: [PATCH 5/7] [AMDGPU] Inherit predicates for GFX940 buffer
invalidation instructions
---
llvm/lib/Target/AMDGPU/BUFInstructions.td | 4 ----
1 file changed, 4 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/BUFInstructions.td b/llvm/lib/Target/AMDGPU/BUFInstructions.td
index 2b5d20c6849f7..6cb0f77e0dbeb 100644
--- a/llvm/lib/Target/AMDGPU/BUFInstructions.td
+++ b/llvm/lib/Target/AMDGPU/BUFInstructions.td
@@ -3660,11 +3660,7 @@ let AsmString = BUFFER_WBL2.Mnemonic, // drop flags
defm BUFFER_WBL2 : MUBUF_Real_gfx90a<0x28>;
defm BUFFER_INVL2 : MUBUF_Real_gfx90a<0x29>;
-let SubtargetPredicate = isGFX940Plus in
def BUFFER_WBL2_gfx940 : MUBUF_Real_gfx940<0x28, BUFFER_WBL2>;
-
-let SubtargetPredicate = HasBufferInvInst,
- AssemblerPredicate = HasBufferInvInst in
def BUFFER_INV_gfx940 : MUBUF_Real_gfx940<0x29, BUFFER_INV>;
class MTBUF_Real_Base_vi <bits<4> op, MTBUF_Pseudo ps, int Enc> :
>From 958521eae1c1940e14b4ff9453fc1219c424e6d4 Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Tue, 8 Sep 2026 13:55:51 -0700
Subject: [PATCH 6/7] [AMDGPU] Add buffer_inv intrinsic and builtin
---
clang/include/clang/Basic/BuiltinsAMDGPU.td | 1 +
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaAMDGPU.cpp | 13 +++++++
.../builtins-amdgcn-buffer-inv.cl | 35 +++++++++++++++++++
llvm/include/llvm/IR/IntrinsicsAMDGPU.td | 8 +++++
.../AMDGPU/AMDGPURegBankLegalizeRules.cpp | 1 +
llvm/lib/Target/AMDGPU/BUFInstructions.td | 1 +
.../CodeGen/AMDGPU/llvm.amdgcn.buffer.inv.ll | 22 ++++++++++++
.../Verifier/AMDGPU/llvm.amdgcn.buffer.inv.ll | 18 ++++++++++
9 files changed, 102 insertions(+)
create mode 100644 clang/test/CodeGenOpenCL/builtins-amdgcn-buffer-inv.cl
create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.buffer.inv.ll
create mode 100644 llvm/test/Verifier/AMDGPU/llvm.amdgcn.buffer.inv.ll
diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.td b/clang/include/clang/Basic/BuiltinsAMDGPU.td
index c66f8c10a84c7..d9c731f728d43 100644
--- a/clang/include/clang/Basic/BuiltinsAMDGPU.td
+++ b/clang/include/clang/Basic/BuiltinsAMDGPU.td
@@ -157,6 +157,7 @@ def __builtin_amdgcn_sched_group_barrier : AMDGPUBuiltin<"void(_Constant int, _C
def __builtin_amdgcn_iglp_opt : AMDGPUBuiltin<"void(_Constant int)">;
def __builtin_amdgcn_s_dcache_inv : AMDGPUBuiltin<"void()">;
def __builtin_amdgcn_buffer_wbinvl1 : AMDGPUBuiltin<"void()">;
+def __builtin_amdgcn_buffer_inv : AMDGPUBuiltin<"void(_Constant int)", [], "buffer-inv-inst">;
def __builtin_amdgcn_fence : AMDGPUBuiltin<"void(unsigned int, char const *, ...)">;
def __builtin_amdgcn_groupstaticsize : AMDGPUBuiltin<"unsigned int()">;
def __builtin_amdgcn_wavefrontsize : AMDGPUBuiltin<"unsigned int()", [Const]>;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9208aba1445d7..8b5cf452d7e8f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -14346,6 +14346,9 @@ def note_amdgpu_named_barrier_reason_inherited : Note<
// AMDGCN builtins diagnostics
def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">;
def note_amdgcn_load_lds_size_valid_value : Note<"size must be %select{1, 2, or 4|1, 2, 4, 12 or 16}0">;
+def err_amdgcn_buffer_inv_invalid_cpol
+ : Error<"argument to '__builtin_amdgcn_buffer_inv' must be a combination "
+ "of the sc0 (1) and sc1 (16) cache-policy bits">;
def err_invalid_sync_scope
: Error<"unsupported atomic synchronization scope '%0'">;
def err_amdgcn_processor_is_arg_not_literal
diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp
index b1f6fa33649bd..11472b1689f6c 100644
--- a/clang/lib/Sema/SemaAMDGPU.cpp
+++ b/clang/lib/Sema/SemaAMDGPU.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
@@ -168,6 +169,18 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(const TargetInfo &TI,
case AMDGPU::BI__builtin_amdgcn_s_setreg:
return SemaRef.BuiltinConstantArgRange(TheCall, /*ArgNum=*/0, /*Low=*/0,
/*High=*/UINT16_MAX);
+ case AMDGPU::BI__builtin_amdgcn_buffer_inv: {
+ llvm::APSInt CPol;
+ if (SemaRef.BuiltinConstantArg(TheCall, /*ArgNum=*/0, CPol))
+ return true;
+
+ // BUFFER_INV only supports the SC0 (1) and SC1 (16) cache-policy bits.
+ if (!llvm::is_contained({0u, 1u, 16u, 17u}, CPol.getZExtValue()))
+ return Diag(TheCall->getArg(0)->getExprLoc(),
+ diag::err_amdgcn_buffer_inv_invalid_cpol)
+ << TheCall->getArg(0)->getSourceRange();
+ return false;
+ }
case AMDGPU::BI__builtin_amdgcn_s_wait_event: {
llvm::APSInt Result;
if (SemaRef.BuiltinConstantArg(TheCall, 0, Result))
diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-buffer-inv.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-buffer-inv.cl
new file mode 100644
index 0000000000000..257a3649c751a
--- /dev/null
+++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-buffer-inv.cl
@@ -0,0 +1,35 @@
+// REQUIRES: amdgpu-registered-target
+// RUN: %clang_cc1 -cl-std=CL2.0 -triple amdgpu9.4-amd-amdhsa -DTEST_VALID -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -cl-std=CL2.0 -triple amdgpu9.4-amd-amdhsa -DTEST_INVALID -fsyntax-only -verify %s
+// RUN: %clang_cc1 -cl-std=CL2.0 -triple amdgpu9.0a-amd-amdhsa -DTEST_UNSUPPORTED -emit-llvm -o /dev/null -verify %s
+
+#ifdef TEST_VALID
+// CHECK-LABEL: @test_buffer_inv(
+// CHECK: call void @llvm.amdgcn.buffer.inv(i32 0)
+// CHECK: call void @llvm.amdgcn.buffer.inv(i32 1)
+// CHECK: call void @llvm.amdgcn.buffer.inv(i32 16)
+// CHECK: call void @llvm.amdgcn.buffer.inv(i32 17)
+void test_buffer_inv(void) {
+ __builtin_amdgcn_buffer_inv(0);
+ __builtin_amdgcn_buffer_inv(1);
+ __builtin_amdgcn_buffer_inv(16);
+ __builtin_amdgcn_buffer_inv(17);
+}
+#endif
+
+#ifdef TEST_INVALID
+void test_nonconstant(int cpol) {
+ __builtin_amdgcn_buffer_inv(cpol); // expected-error {{argument to '__builtin_amdgcn_buffer_inv' must be a constant integer}}
+}
+
+void test_invalid_policy(void) {
+ // expected-error at +1 {{must be a combination of the sc0 (1) and sc1 (16) cache-policy bits}}
+ __builtin_amdgcn_buffer_inv(2);
+}
+#endif
+
+#ifdef TEST_UNSUPPORTED
+void test_unsupported(void) {
+ __builtin_amdgcn_buffer_inv(0); // expected-error {{'__builtin_amdgcn_buffer_inv' needs target feature buffer-inv-inst}}
+}
+#endif
diff --git a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
index 623e8b7f0647c..c06e094c56d3a 100644
--- a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
+++ b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
@@ -2317,6 +2317,14 @@ def int_amdgcn_buffer_wbinvl1 :
ClangBuiltin<"__builtin_amdgcn_buffer_wbinvl1">,
DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>;
+let TargetFeatures = "buffer-inv-inst" in
+def int_amdgcn_buffer_inv :
+ ClangBuiltin<"__builtin_amdgcn_buffer_inv">,
+ DefaultAttrsIntrinsic<[], [llvm_i32_ty],
+ [ImmArg<ArgIndex<0>>,
+ RangeSet<ArgIndex<0>, [[0, 1], [16, 17]]>,
+ IntrNoMem, IntrHasSideEffects]>;
+
def int_amdgcn_s_dcache_inv :
ClangBuiltin<"__builtin_amdgcn_s_dcache_inv">,
DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
index 237971bb436d4..5775c67179a83 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
@@ -1801,6 +1801,7 @@ RegBankLegalizeRules::RegBankLegalizeRules(const GCNSubtarget &_ST,
// Intrinsics with no register operands.
addRulesForIOpcs({amdgcn_asyncmark,
+ amdgcn_buffer_inv,
amdgcn_endpgm,
amdgcn_iglp_opt,
amdgcn_init_exec,
diff --git a/llvm/lib/Target/AMDGPU/BUFInstructions.td b/llvm/lib/Target/AMDGPU/BUFInstructions.td
index 6cb0f77e0dbeb..b8776084b31ed 100644
--- a/llvm/lib/Target/AMDGPU/BUFInstructions.td
+++ b/llvm/lib/Target/AMDGPU/BUFInstructions.td
@@ -1434,6 +1434,7 @@ def BUFFER_INV : MUBUF_Invalidate<"buffer_inv"> {
let has_sccb = 1;
let InOperandList = (ins CPol_0:$cpol);
let AsmOperands = "$cpol";
+ let Pattern = [(int_amdgcn_buffer_inv timm:$cpol)];
}
def BUFFER_GL0_INV : MUBUF_Invalidate<"buffer_gl0_inv">;
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.buffer.inv.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.buffer.inv.ll
new file mode 100644
index 0000000000000..e4717be9a36dc
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.buffer.inv.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=amdgpu9.4-amd-amdhsa -verify-machineinstrs < %s | FileCheck --check-prefix=GFX94 %s
+; RUN: llc -mtriple=amdgpu9.4-amd-amdhsa -global-isel -global-isel-abort=1 -verify-machineinstrs < %s | FileCheck --check-prefix=GFX94 %s
+; RUN: not llc -mtriple=amdgpu9.0a-amd-amdhsa -filetype=null < %s 2>&1 | FileCheck --check-prefix=GFX90A-ERR %s
+
+; GFX90A-ERR: llvm.amdgcn.buffer.inv requires target feature 'buffer-inv-inst'
+
+declare void @llvm.amdgcn.buffer.inv(i32 immarg)
+
+define amdgpu_kernel void @buffer_inv_cache_policies() {
+; GFX94-LABEL: buffer_inv_cache_policies:
+; GFX94: ; %bb.0:
+; GFX94-NEXT: buffer_inv
+; GFX94-NEXT: buffer_inv sc0
+; GFX94-NEXT: buffer_inv sc1
+; GFX94-NEXT: buffer_inv sc0 sc1
+ call void @llvm.amdgcn.buffer.inv(i32 0)
+ call void @llvm.amdgcn.buffer.inv(i32 1)
+ call void @llvm.amdgcn.buffer.inv(i32 16)
+ call void @llvm.amdgcn.buffer.inv(i32 17)
+ ret void
+}
diff --git a/llvm/test/Verifier/AMDGPU/llvm.amdgcn.buffer.inv.ll b/llvm/test/Verifier/AMDGPU/llvm.amdgcn.buffer.inv.ll
new file mode 100644
index 0000000000000..26d2d8929cd2a
--- /dev/null
+++ b/llvm/test/Verifier/AMDGPU/llvm.amdgcn.buffer.inv.ll
@@ -0,0 +1,18 @@
+; RUN: not llvm-as %s -disable-output 2>&1 | FileCheck %s
+
+declare void @llvm.amdgcn.buffer.inv(i32)
+
+define void @nonconstant(i32 %cpol) {
+ ; CHECK: immarg operand has non-immediate parameter
+ ; CHECK-NEXT: i32 %cpol
+ ; CHECK-NEXT: call void @llvm.amdgcn.buffer.inv(i32 %cpol)
+ call void @llvm.amdgcn.buffer.inv(i32 %cpol)
+ ret void
+}
+
+define void @invalid_cache_policy() {
+ ; CHECK: immarg value 2 for arg 0 out of range set
+ ; CHECK-NEXT: call void @llvm.amdgcn.buffer.inv(i32 2)
+ call void @llvm.amdgcn.buffer.inv(i32 2)
+ ret void
+}
>From 4ce065a47a776dd64ce2f01b4c2e287fc97c8a0c Mon Sep 17 00:00:00 2001
From: Dan Zimmerman <danzimm at meta.com>
Date: Thu, 10 Sep 2026 10:00:43 -0700
Subject: [PATCH 7/7] [MLIR][ROCDL] Expose buffer.inv intrinsic
---
mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td | 4 ++++
mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td | 10 ++++++++++
mlir/include/mlir/Dialect/LLVMIR/ROCDLOps.td | 16 ++++++++++++++++
.../LLVMIR/rocdl-cache-policy-invalid.mlir | 8 ++++++++
mlir/test/Dialect/LLVMIR/rocdl.mlir | 13 +++++++++++++
mlir/test/Target/LLVMIR/rocdl.mlir | 13 +++++++++++++
6 files changed, 64 insertions(+)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
index 075fa75ab5ad8..013c451f4b0a0 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
@@ -93,6 +93,10 @@ def ROCDL_Gfx942CachePolicyAttr
: ROCDL_IntrinsicIntegerEnumAttr<ROCDL_Gfx942CachePolicy,
"gfx942_cache_policy">;
+def ROCDL_BufferInvCachePolicyAttr
+ : ROCDL_IntrinsicIntegerEnumAttr<ROCDL_BufferInvCachePolicy,
+ "buffer_inv_cache_policy">;
+
def ROCDL_Gfx12CachePolicyAttr
: ROCDL_IntrinsicIntegerEnumAttr<ROCDL_Gfx12CachePolicy,
"gfx12_cache_policy">;
diff --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
index fb704ecf4c0de..e6116be1f8d1a 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
@@ -208,6 +208,16 @@ def ROCDL_Gfx942CachePolicy : ROCDL_I32BitEnum<"Gfx942CachePolicy",
let printBitEnumQuoted = 0;
}
+def ROCDL_BufferInvCachePolicy : ROCDL_I32BitEnum<"BufferInvCachePolicy",
+ "buffer invalidate cache policy bits",
+ [
+ ROCDL_Gfx942CachePolicyNone,
+ ROCDL_Gfx942CachePolicySC0,
+ ROCDL_Gfx942CachePolicySC1
+ ]> {
+ let printBitEnumQuoted = 0;
+}
+
def ROCDL_Gfx12CachePolicyNone : I32BitEnumCaseNone<"none">;
def ROCDL_Gfx12CachePolicyNT : I32BitEnumCaseBit<"nt", 0>;
def ROCDL_Gfx12CachePolicyHT : I32BitEnumCaseBit<"ht", 1>;
diff --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLOps.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLOps.td
index 716fd92e810ac..92cc04f91c6ec 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLOps.td
@@ -322,6 +322,22 @@ def ROCDL_SWaitcntOp : ROCDL_ConcreteNonMemIntrOp<"s.waitcnt", [], 0, [0], ["bit
}];
}
+def ROCDL_BufferInvOp :
+ ROCDL_ConcreteNonMemIntrOp<"buffer.inv", [], 0, [0], ["cpol"]>,
+ Arguments<(ins ROCDL_BufferInvCachePolicyAttr:$cpol)> {
+ let summary = "Invalidate vector caches";
+ let description = [{
+ Issues `buffer_inv` with the selected `sc0` and `sc1` cache-policy flags.
+ The flags may be combined; `none` selects neither.
+
+ Example:
+ ```mlir
+ rocdl.buffer.inv sc0|sc1
+ ```
+ }];
+ let assemblyFormat = "enum($cpol) attr-dict";
+}
+
def ROCDL_SSleepOp : ROCDL_ConcreteNonMemIntrOp<"s.sleep", [], 0, [0], ["count"]>,
Arguments<(ins I32Attr:$count)> {
let assemblyFormat = "attr-dict $count";
diff --git a/mlir/test/Dialect/LLVMIR/rocdl-cache-policy-invalid.mlir b/mlir/test/Dialect/LLVMIR/rocdl-cache-policy-invalid.mlir
index 354d1ef661b6e..769feacb5e69f 100644
--- a/mlir/test/Dialect/LLVMIR/rocdl-cache-policy-invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/rocdl-cache-policy-invalid.mlir
@@ -36,3 +36,11 @@ llvm.func @atomic_buffer_rejects_gfx12(%rsrc : vector<4xi32>,
%0 = rocdl.raw.buffer.atomic.smax %vdata, %rsrc, %offset, %soffset, gfx12<nt> : i32
llvm.return
}
+
+// -----
+
+llvm.func @buffer_inv_rejects_unsupported_policy() {
+ // expected-error at +1 {{expected string or keyword containing one of the following enum values for attribute 'cpol'}}
+ rocdl.buffer.inv nt
+ llvm.return
+}
diff --git a/mlir/test/Dialect/LLVMIR/rocdl.mlir b/mlir/test/Dialect/LLVMIR/rocdl.mlir
index 1b5b641936881..dd9bbe46e4486 100644
--- a/mlir/test/Dialect/LLVMIR/rocdl.mlir
+++ b/mlir/test/Dialect/LLVMIR/rocdl.mlir
@@ -1206,6 +1206,19 @@ llvm.func @rocdl.s.waitcnt() {
llvm.return
}
+llvm.func @rocdl.buffer.inv() {
+ // CHECK-LABEL: rocdl.buffer.inv
+ // CHECK-NEXT: rocdl.buffer.inv none
+ // CHECK-NEXT: rocdl.buffer.inv sc0
+ // CHECK-NEXT: rocdl.buffer.inv sc1
+ // CHECK-NEXT: rocdl.buffer.inv sc0|sc1
+ rocdl.buffer.inv none
+ rocdl.buffer.inv sc0
+ rocdl.buffer.inv sc1
+ rocdl.buffer.inv sc0|sc1
+ llvm.return
+}
+
llvm.func @rocdl.s.sleep() {
// CHECK-LABEL: rocdl.s.sleep
// CHECK: rocdl.s.sleep 0
diff --git a/mlir/test/Target/LLVMIR/rocdl.mlir b/mlir/test/Target/LLVMIR/rocdl.mlir
index b4a94cef770fa..ff4dea36024af 100644
--- a/mlir/test/Target/LLVMIR/rocdl.mlir
+++ b/mlir/test/Target/LLVMIR/rocdl.mlir
@@ -240,6 +240,19 @@ llvm.func @rocdl.s.waitcnt() {
llvm.return
}
+llvm.func @rocdl.buffer.inv() {
+ // CHECK-LABEL: rocdl.buffer.inv
+ // CHECK-NEXT: call void @llvm.amdgcn.buffer.inv(i32 0)
+ // CHECK-NEXT: call void @llvm.amdgcn.buffer.inv(i32 1)
+ // CHECK-NEXT: call void @llvm.amdgcn.buffer.inv(i32 16)
+ // CHECK-NEXT: call void @llvm.amdgcn.buffer.inv(i32 17)
+ rocdl.buffer.inv none
+ rocdl.buffer.inv sc0
+ rocdl.buffer.inv sc1
+ rocdl.buffer.inv sc0|sc1
+ llvm.return
+}
+
llvm.func @rocdl.s.sleep() {
// CHECK-LABEL: rocdl.s.sleep
// CHECK-NEXT: call void @llvm.amdgcn.s.sleep(i32 0)
More information about the llvm-commits
mailing list