[Mlir-commits] [mlir] 2d1fb73 - [mlir][LLVM][ROCDL] Add buffer oob mode module flags, flag interfaces (#202729)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Jun 12 09:19:44 PDT 2026


Author: Krzysztof Drewniak
Date: 2026-06-12T09:19:39-07:00
New Revision: 2d1fb738d6f9eb109a2f1e0405397565f25fece4

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

LOG: [mlir][LLVM][ROCDL] Add buffer oob mode module flags, flag interfaces (#202729)

Now that the out-of-bounds mode for buffer accesses will be controlled
by a module flag and is no longer a function of the subtarget triple (as
of #160922) and since `ptr addrpace(7)` lowering will start respecting
this mode soon, add MLIR-level support for setting this flag.

After a few iterations, I think adding this module flag to
`llvm.module.flags` but adding interfaces for module flag attributes (so
that those wishing to set this flag don't need to know it has `max`
combining semantics or look up the enum values) is a
minimally-disruptive way to get a more ergonomic wrapper around this
functionality.

AI note: AI generated the code hehe, I reviewed it. The documentation
update to ModuleFlagsOp is mine.

(The LLVM PR that would want people to start explicitly setting
`relaxed` is #134329)

Co-authored-by: Codex <codex at openai.com>

Added: 
    mlir/test/Target/LLVMIR/rocdl-module-flags.mlir

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
    mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
    mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
    mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
    mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
    mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
    mlir/test/Dialect/GPU/module-to-binary-rocdl.mlir
    mlir/test/Dialect/LLVMIR/invalid.mlir
    mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
    mlir/test/Dialect/LLVMIR/rocdl.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 56f3afba6a030..9474afb897119 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1585,14 +1585,16 @@ def LLVM_DereferenceableAttr : LLVM_Attr<"Dereferenceable", "dereferenceable"> {
 //===----------------------------------------------------------------------===//
 
 def ModuleFlagAttr
-    : LLVM_Attr<"ModuleFlag", "mlir.module_flag"> {
+    : LLVM_Attr<"ModuleFlag", "mlir.module_flag",
+                [DeclareAttrInterfaceMethods<LLVM_ModuleFlagAttrInterface>]> {
   let summary = "LLVM module flag metadata";
   let description = [{
     Represents a single entry of llvm.module.flags metadata
     (llvm::Module::ModuleFlagEntry in LLVM). The first element is a behavior
     flag described by `ModFlagBehaviorAttr`, the second is a string ID
     and third is the value of the flag. Supported keys and values include:
-      - Arbitrary `key`s holding integer constants or strings.
+      - Arbitrary `key`s holding integer constants, integer-like dialect
+        attributes, strings, or non-empty string arrays.
       - Domain specific keys (e.g "CG Profile"), holding lists of supported
         module flag values (e.g. `llvm.cgprofile_entry`).
 

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
index e10d7f7df3450..19dced51e976f 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
@@ -100,6 +100,11 @@ bool isValidLoadStoreImpl(Type type, ptr::AtomicOrdering ordering,
                           std::optional<int64_t> alignment,
                           const ::mlir::DataLayout *dataLayout,
                           function_ref<InFlightDiagnostic()> emitError);
+
+/// Verifies that a module flag value can be exported to LLVM IR.
+LogicalResult
+verifyModuleFlagValue(StringAttr key, Attribute value,
+                      function_ref<InFlightDiagnostic()> emitError);
 } // namespace detail
 } // namespace LLVM
 } // namespace mlir

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
index 8c6d4fcefa903..c59b38c416956 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
@@ -582,6 +582,42 @@ def LLVM_IntrinsicIntegerAttrInterface :
   ];
 }
 
+def LLVM_ModuleFlagAttrInterface :
+    AttrInterface<"ModuleFlagAttrInterface"> {
+  let description = [{
+    An interface for attributes that represent LLVM module flag metadata entries.
+
+    Implementing attributes provide the module flag merge behavior, metadata key,
+    and metadata value. This lets target dialects define richer, target-specific
+    module flag attributes while still sharing `llvm.module_flags` as the common
+    operation container. Values returned by this interface must use a shape that
+    can be exported to LLVM IR: integer attributes (exported as i32 constants),
+    string attributes, attributes implementing `IntrinsicIntegerAttrInterface`,
+    supported array values, or `ModuleFlagProfileSummaryAttr`.
+  }];
+  let cppNamespace = "::mlir::LLVM";
+  let methods = [
+    InterfaceMethod<
+      /*description=*/"Returns the module flag merge behavior.",
+      /*retTy=*/"::mlir::LLVM::ModFlagBehavior",
+      /*methodName=*/"getModuleFlagBehavior",
+      /*args=*/(ins)
+    >,
+    InterfaceMethod<
+      /*description=*/"Returns the module flag metadata key.",
+      /*retTy=*/"::mlir::StringAttr",
+      /*methodName=*/"getModuleFlagKey",
+      /*args=*/(ins)
+    >,
+    InterfaceMethod<
+      /*description=*/"Returns the module flag metadata value.",
+      /*retTy=*/"::mlir::Attribute",
+      /*methodName=*/"getModuleFlagValue",
+      /*args=*/(ins)
+    >
+  ];
+}
+
 def LLVM_TargetAttrInterface
   : AttrInterface<"TargetAttrInterface", [DLTIQueryInterface]> {
   let description = [{

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 85b768f2f6755..9d112e5ea227e 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2643,8 +2643,10 @@ def LLVM_ModuleFlagsOp
   let summary = "Information about module properties";
   let description = [{
     Represents the equivalent in MLIR for LLVM's `llvm.module.flags` metadata,
-    which requires a list of metadata triplets. Each triplet entry is described
-    by a `ModuleFlagAttr`.
+    which requires a list of metadata triplets (combining kind, name, value),
+    either specified directly by a `ModuleFlagAttr` or defined by an attribute
+    implementing `ModuleFlagAttrInterface` (which is used to wrap the details
+    of metadata combining, provided other verifications, etc.)
 
     Example:
     ```mlir

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
index c3a66e2e92256..4f84513d23576 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLAttrs.td
@@ -11,6 +11,7 @@
 
 include "mlir/Dialect/LLVMIR/ROCDLDialect.td"
 include "mlir/Dialect/LLVMIR/ROCDLEnums.td"
+include "mlir/Dialect/LLVMIR/LLVMInterfaces.td"
 include "mlir/IR/EnumAttr.td"
 
 //===----------------------------------------------------------------------===//
@@ -26,6 +27,39 @@ class ROCDL_IntrinsicIntegerEnumAttr<EnumInfo enumInfo, string name>
     : EnumAttr<ROCDL_Dialect, enumInfo, name,
                [LLVM_IntrinsicIntegerAttrInterface]>;
 
+def ROCDL_BufferOOBModeAttr :
+    ROCDL_IntrinsicIntegerEnumAttr<ROCDL_BufferOOBMode, "buffer_oob_mode"> {
+  let summary = "ROCDL buffer out-of-bounds mode";
+  let description = [{
+    Specifies the AMDGPU buffer out-of-bounds mode encoded in
+    `amdgpu.buffer.oob.mode` or `amdgpu.tbuffer.oob.mode` LLVM module flags.
+  }];
+  let assemblyFormat = "`<` $value `>`";
+}
+
+class ROCDL_BufferOOBModeModuleFlagAttrBase<string attrName, string mnemonic>
+    : ROCDL_Attr<attrName, mnemonic,
+                 [DeclareAttrInterfaceMethods<LLVM_ModuleFlagAttrInterface>]> {
+  let summary = "ROCDL buffer/tbuffer out-of-bounds mode LLVM module flag";
+  let description = [{
+    Specifies an AMDGPU buffer or tbuffer out-of-bounds mode LLVM module flag.
+    The attribute supplies the required `max` merge behavior and AMDGPU module
+    flag key. Prefer these typed attributes over hand-written generic
+    `#llvm.mlir.module_flag` triples for AMDGPU OOB mode keys when MLIR-side
+    behavior and enum validation are required.
+  }];
+  let parameters = (ins EnumParameter<ROCDL_BufferOOBMode>:$value);
+  let assemblyFormat = "`<` $value `>`";
+}
+
+def ROCDL_BufferOOBModeModuleFlagAttr :
+    ROCDL_BufferOOBModeModuleFlagAttrBase<"BufferOOBModeModuleFlag",
+                                          "buffer_oob_mode_flag">;
+
+def ROCDL_TBufferOOBModeModuleFlagAttr :
+    ROCDL_BufferOOBModeModuleFlagAttrBase<"TBufferOOBModeModuleFlag",
+                                          "tbuffer_oob_mode_flag">;
+
 def ROCDL_MFMAPermBAttr
     : ROCDL_IntrinsicIntegerEnumAttr<ROCDL_MFMAPermB, "mfma_perm_b">;
 

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
index 6b3f073a4a994..0807cf8cf04a4 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
@@ -124,7 +124,16 @@ def ROCDL_Dialect : Dialect {
     static constexpr ::llvm::StringLiteral getUniformWorkGroupSizeAttrName() {
       return ::llvm::StringLiteral("rocdl.uniform_work_group_size");
     }
-
+    /// Get the LLVM module flag key for the AMDGPU buffer OOB mode.
+    static constexpr ::llvm::StringLiteral
+    getModuleFlagKeyBufferOOBModeName() {
+      return ::llvm::StringLiteral("amdgpu.buffer.oob.mode");
+    }
+    /// Get the LLVM module flag key for the AMDGPU tbuffer OOB mode.
+    static constexpr ::llvm::StringLiteral
+    getModuleFlagKeyTBufferOOBModeName() {
+      return ::llvm::StringLiteral("amdgpu.tbuffer.oob.mode");
+    }
     /// The address space value that represents global memory.
     static constexpr unsigned kGlobalMemoryAddressSpace = 1;
     /// The address space value that represents shared memory.

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
index e0d1773b59b7b..fb704ecf4c0de 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLEnums.td
@@ -32,6 +32,21 @@ class ROCDL_I32BitEnum<string name, string summary,
   let cppNamespace = "::mlir::ROCDL";
 }
 
+//===----------------------------------------------------------------------===//
+// Buffer out-of-bounds mode enum.
+//===----------------------------------------------------------------------===//
+
+// Keep these values in sync with OOBFlagValue in AMDGPUTargetMachine.cpp and
+// the LLVM IR verifier's AMDGPU module flag checks.
+def ROCDL_BufferOOBModeAny : I32EnumCase<"Any", 0, "any">;
+def ROCDL_BufferOOBModeRelaxed : I32EnumCase<"Relaxed", 1, "relaxed">;
+def ROCDL_BufferOOBModeStrict : I32EnumCase<"Strict", 2, "strict">;
+
+def ROCDL_BufferOOBMode :
+    ROCDL_I32Enum<"BufferOOBMode", "ROCDL buffer out-of-bounds mode",
+                  [ROCDL_BufferOOBModeAny, ROCDL_BufferOOBModeRelaxed,
+                   ROCDL_BufferOOBModeStrict]>;
+
 def ROCDL_MFMAPermB : ROCDL_I32Enum<"MFMAPermB",
     "permutations of the lanes storing B in an MFMA",
     [

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 2bd5b42720ee2..266faeca4553b 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -544,10 +544,9 @@ FailureOr<::mlir::Attribute> TargetAttr::query(DataLayoutEntryKey key) {
 // ModuleFlagAttr
 //===----------------------------------------------------------------------===//
 
-LogicalResult
-ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
-                       LLVM::ModFlagBehavior flagBehavior, StringAttr key,
-                       Attribute value) {
+LogicalResult LLVM::detail::verifyModuleFlagValue(
+    StringAttr key, Attribute value,
+    function_ref<InFlightDiagnostic()> emitError) {
   if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {
     auto arrayAttr = dyn_cast<ArrayAttr>(value);
     if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute attr) {
@@ -565,7 +564,7 @@ ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
     return success();
   }
 
-  if (isa<IntegerAttr, StringAttr>(value))
+  if (isa<IntegerAttr, StringAttr, IntrinsicIntegerAttrInterface>(value))
     return success();
 
   // Allow non-empty ArrayAttr of StringAttrs to represent MDTuples of
@@ -578,7 +577,24 @@ ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
         llvm::all_of(arrayAttr, [](Attribute a) { return isa<StringAttr>(a); }))
       return success();
 
-  return emitError() << "only integer, string, and string-array values are "
-                        "currently supported for unknown key '"
-                     << key << "'";
+  return emitError()
+         << "only integer, integer-like dialect attributes, string, "
+            "and string-array values are currently supported for "
+            "unknown key '"
+         << key << "'";
 }
+
+LogicalResult
+ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+                       LLVM::ModFlagBehavior flagBehavior, StringAttr key,
+                       Attribute value) {
+  return LLVM::detail::verifyModuleFlagValue(key, value, emitError);
+}
+
+ModFlagBehavior ModuleFlagAttr::getModuleFlagBehavior() const {
+  return getBehavior();
+}
+
+StringAttr ModuleFlagAttr::getModuleFlagKey() const { return getKey(); }
+
+Attribute ModuleFlagAttr::getModuleFlagValue() const { return getValue(); }

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index ac6cf03e057dc..3111d5bed3a64 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -25,6 +25,7 @@
 #include "mlir/Transforms/InliningUtils.h"
 
 #include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/Support/Error.h"
@@ -4171,9 +4172,23 @@ LogicalResult ModuleFlagsOp::verify() {
   if (Operation *parentOp = (*this)->getParentOp();
       parentOp && !satisfiesLLVMModule(parentOp))
     return emitOpError("must appear at the module level");
-  for (Attribute flag : getFlags())
-    if (!isa<ModuleFlagAttr>(flag))
+
+  llvm::DenseSet<StringAttr> seenNonRequireKeys;
+  for (Attribute flag : getFlags()) {
+    auto moduleFlag = dyn_cast<ModuleFlagAttrInterface>(flag);
+    if (!moduleFlag)
       return emitOpError("expected a module flag attribute");
+    if (failed(LLVM::detail::verifyModuleFlagValue(
+            moduleFlag.getModuleFlagKey(), moduleFlag.getModuleFlagValue(),
+            [&] { return emitOpError(); })))
+      return failure();
+    if (moduleFlag.getModuleFlagBehavior() == ModFlagBehavior::Require)
+      continue;
+    StringAttr key = moduleFlag.getModuleFlagKey();
+    if (!seenNonRequireKeys.insert(key).second)
+      return emitOpError("expected module flag key '")
+             << key.getValue() << "' to be unique for non-require flags";
+  }
   return success();
 }
 

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
index 6e69a07856300..686b62f1dd80e 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/ROCDLDialect.cpp
@@ -25,6 +25,7 @@
 #include "mlir/IR/Operation.h"
 #include "mlir/Transforms/InliningUtils.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -66,6 +67,34 @@ void ROCDLDialect::initialize() {
   declarePromisedInterface<gpu::TargetAttrInterface, ROCDLTargetAttr>();
 }
 
+LLVM::ModFlagBehavior
+BufferOOBModeModuleFlagAttr::getModuleFlagBehavior() const {
+  return LLVM::ModFlagBehavior::Max;
+}
+
+StringAttr BufferOOBModeModuleFlagAttr::getModuleFlagKey() const {
+  return StringAttr::get(getContext(),
+                         ROCDLDialect::getModuleFlagKeyBufferOOBModeName());
+}
+
+Attribute BufferOOBModeModuleFlagAttr::getModuleFlagValue() const {
+  return BufferOOBModeAttr::get(getContext(), getValue());
+}
+
+LLVM::ModFlagBehavior
+TBufferOOBModeModuleFlagAttr::getModuleFlagBehavior() const {
+  return LLVM::ModFlagBehavior::Max;
+}
+
+StringAttr TBufferOOBModeModuleFlagAttr::getModuleFlagKey() const {
+  return StringAttr::get(getContext(),
+                         ROCDLDialect::getModuleFlagKeyTBufferOOBModeName());
+}
+
+Attribute TBufferOOBModeModuleFlagAttr::getModuleFlagValue() const {
+  return BufferOOBModeAttr::get(getContext(), getValue());
+}
+
 LogicalResult ROCDLDialect::verifyOperationAttribute(Operation *op,
                                                      NamedAttribute attr) {
   // Kernel function attribute should be attached to functions.

diff  --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 5474689c9b0b5..7cd8c3c77c15f 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -382,34 +382,40 @@ static llvm::Metadata *convertModuleFlagProfileSummaryAttr(
 static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
                                  LLVM::ModuleTranslation &moduleTranslation) {
   llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
-  for (auto flagAttr : flags.getAsRange<ModuleFlagAttr>()) {
+  auto convertIntegerAttr = [&](IntegerAttr intAttr) -> llvm::Metadata * {
+    return llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+        llvm::Type::getInt32Ty(builder.getContext()), intAttr.getInt()));
+  };
+  for (auto flagAttr : flags.getAsRange<ModuleFlagAttrInterface>()) {
     llvm::Metadata *valueMetadata =
-        llvm::TypeSwitch<Attribute, llvm::Metadata *>(flagAttr.getValue())
+        llvm::TypeSwitch<Attribute, llvm::Metadata *>(
+            flagAttr.getModuleFlagValue())
             .Case([&](StringAttr strAttr) {
               return llvm::MDString::get(builder.getContext(),
                                          strAttr.getValue());
             })
             .Case([&](IntegerAttr intAttr) {
-              return llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
-                  llvm::Type::getInt32Ty(builder.getContext()),
-                  intAttr.getInt()));
+              return convertIntegerAttr(intAttr);
+            })
+            .Case([&](IntrinsicIntegerAttrInterface intAttr) {
+              return convertIntegerAttr(intAttr.getIntegerAttr());
             })
             .Case([&](ArrayAttr arrayAttr) {
-              return convertModuleFlagValue(flagAttr.getKey().getValue(),
-                                            arrayAttr, builder,
-                                            moduleTranslation);
+              return convertModuleFlagValue(
+                  flagAttr.getModuleFlagKey().getValue(), arrayAttr, builder,
+                  moduleTranslation);
             })
             .Case([&](ModuleFlagProfileSummaryAttr summaryAttr) {
               return convertModuleFlagProfileSummaryAttr(
-                  flagAttr.getKey().getValue(), summaryAttr, builder,
+                  flagAttr.getModuleFlagKey().getValue(), summaryAttr, builder,
                   moduleTranslation);
             })
             .Default([](auto) { return nullptr; });
 
     assert(valueMetadata && "expected valid metadata");
     llvmModule->addModuleFlag(
-        convertModFlagBehaviorToLLVM(flagAttr.getBehavior()),
-        flagAttr.getKey().getValue(), valueMetadata);
+        convertModFlagBehaviorToLLVM(flagAttr.getModuleFlagBehavior()),
+        flagAttr.getModuleFlagKey().getValue(), valueMetadata);
   }
 }
 

diff  --git a/mlir/test/Dialect/GPU/module-to-binary-rocdl.mlir b/mlir/test/Dialect/GPU/module-to-binary-rocdl.mlir
index 939dbdd4382e7..7c3223d4b9970 100644
--- a/mlir/test/Dialect/GPU/module-to-binary-rocdl.mlir
+++ b/mlir/test/Dialect/GPU/module-to-binary-rocdl.mlir
@@ -4,8 +4,11 @@
 
 module attributes {gpu.container_module} {
   // CHECK-LABEL:gpu.binary @kernel_module1
-  // CHECK:[#gpu.object<#rocdl.target<chip = "gfx90a">, offload = "{{.*}}">]
+  // CHECK:[#gpu.object<#rocdl.target<chip = "gfx90a">, offload = "{{.*}}amdgpu.buffer.oob.mode{{.*}}">]
   gpu.module @kernel_module1 [#rocdl.target<chip = "gfx90a">] {
+    llvm.module_flags [
+      #rocdl.buffer_oob_mode_flag<relaxed>
+    ]
     llvm.func @kernel(%arg0: i32, %arg1: !llvm.ptr,
         %arg2: !llvm.ptr, %arg3: i64, %arg4: i64,
         %arg5: i64) attributes {gpu.kernel} {

diff  --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index e80094df1eed2..a0377cdfc14ff 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1850,12 +1850,21 @@ llvm.mlir.alias external @y5 : i32 {
 module {
   llvm.func @foo()
 
-  // expected-error at below {{only integer, string, and string-array values are currently supported for unknown key '"yolo"'}}
+  // expected-error at below {{only integer, integer-like dialect attributes, string, and string-array values are currently supported for unknown key '"yolo"'}}
   llvm.module_flags [#llvm.mlir.module_flag<error, "yolo", @foo>]
 }
 
 // -----
 
+module {
+  // expected-error at below {{expected module flag key 'amdgpu.buffer.oob.mode' to be unique for non-require flags}}
+  llvm.module_flags [#rocdl.buffer_oob_mode_flag<any>,
+                     #llvm.mlir.module_flag<max, "amdgpu.buffer.oob.mode",
+                                            #rocdl.buffer_oob_mode<strict>>]
+}
+
+// -----
+
 module {
   // expected-error at below {{'CG Profile' key expects an array of '#llvm.cgprofile_entry'}}
   llvm.module_flags [#llvm.mlir.module_flag<append, "CG Profile", [

diff  --git a/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
index 85abd57df53c8..aa1f99a76ce5d 100644
--- a/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
@@ -46,3 +46,14 @@ module {
 // CHECK-SAME:        <cut_off = 10000, min_count = 86427, num_counts = 1>,
 // CHECK-SAME:        <cut_off = 100000, min_count = 86427, num_counts = 1>
 // CHECK-SAME: >>]
+
+// -----
+
+module {
+  llvm.module_flags [#llvm.mlir.module_flag<require, "shared-require", 0 : i32>,
+                     #llvm.mlir.module_flag<require, "shared-require", 1 : i32>]
+}
+
+// CHECK: llvm.module_flags [
+// CHECK-SAME: #llvm.mlir.module_flag<require, "shared-require", 0 : i32>,
+// CHECK-SAME: #llvm.mlir.module_flag<require, "shared-require", 1 : i32>]

diff  --git a/mlir/test/Dialect/LLVMIR/rocdl.mlir b/mlir/test/Dialect/LLVMIR/rocdl.mlir
index 603913750a32c..dd0b00faf7f1f 100644
--- a/mlir/test/Dialect/LLVMIR/rocdl.mlir
+++ b/mlir/test/Dialect/LLVMIR/rocdl.mlir
@@ -1,5 +1,30 @@
 // RUN: mlir-opt %s -split-input-file -verify-diagnostics | FileCheck %s
 
+// CHECK-LABEL: module {
+// CHECK: llvm.module_flags [
+// CHECK-SAME: #rocdl.buffer_oob_mode_flag<any>,
+// CHECK-SAME: #rocdl.tbuffer_oob_mode_flag<strict>
+module {
+  llvm.module_flags [
+    #rocdl.buffer_oob_mode_flag<any>,
+    #rocdl.tbuffer_oob_mode_flag<strict>
+  ]
+}
+
+// -----
+
+// CHECK-LABEL: module {
+// CHECK: llvm.module_flags [
+// CHECK-SAME: #llvm.mlir.module_flag<max, "amdgpu.buffer.oob.mode", #rocdl.buffer_oob_mode<relaxed>>
+module {
+  llvm.module_flags [
+    #llvm.mlir.module_flag<max, "amdgpu.buffer.oob.mode",
+                           #rocdl.buffer_oob_mode<relaxed>>
+  ]
+}
+
+// -----
+
 func.func @rocdl_special_regs() -> i32 {
   // CHECK-LABEL: rocdl_special_regs
   // CHECK: rocdl.workitem.id.x : i32
@@ -1803,6 +1828,23 @@ func.func private @expected_llvm_func() attributes { rocdl.kernel }
 
 // -----
 
+gpu.module @module_oob_modes {
+  llvm.module_flags [
+    #rocdl.buffer_oob_mode_flag<relaxed>,
+    #rocdl.tbuffer_oob_mode_flag<strict>
+  ]
+}
+
+// -----
+
+module {
+  // expected-error at +2 {{expected one of [any, relaxed, strict] for ROCDL buffer out-of-bounds mode}}
+  // expected-error at +1 {{failed to parse ROCDL_BufferOOBModeModuleFlagAttr parameter 'value'}}
+  llvm.module_flags [#rocdl.buffer_oob_mode_flag<invalid>]
+}
+
+// -----
+
 // 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
new file mode 100644
index 0000000000000..8e1db326e7f28
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/rocdl-module-flags.mlir
@@ -0,0 +1,47 @@
+// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
+
+module {
+  llvm.module_flags [
+    #rocdl.buffer_oob_mode_flag<any>,
+    #rocdl.tbuffer_oob_mode_flag<relaxed>
+  ]
+  llvm.func @oob_any_relaxed() {
+    llvm.return
+  }
+}
+
+// CHECK-LABEL: define void @oob_any_relaxed()
+// CHECK: !llvm.module.flags = !{![[BUFFER_ANY:[0-9]+]], ![[TBUFFER_RELAXED:[0-9]+]]
+// CHECK-DAG: ![[BUFFER_ANY]] = !{i32 7, !"amdgpu.buffer.oob.mode", i32 0}
+// CHECK-DAG: ![[TBUFFER_RELAXED]] = !{i32 7, !"amdgpu.tbuffer.oob.mode", i32 1}
+
+// -----
+
+module {
+  llvm.module_flags [
+    #rocdl.buffer_oob_mode_flag<strict>
+  ]
+  llvm.func @oob_strict() {
+    llvm.return
+  }
+}
+
+// CHECK-LABEL: define void @oob_strict()
+// CHECK: !llvm.module.flags = !{![[BUFFER_STRICT:[0-9]+]]
+// CHECK-DAG: ![[BUFFER_STRICT]] = !{i32 7, !"amdgpu.buffer.oob.mode", i32 2}
+
+// -----
+
+module {
+  llvm.module_flags [
+    #llvm.mlir.module_flag<max, "amdgpu.buffer.oob.mode",
+                           #rocdl.buffer_oob_mode<relaxed>>
+  ]
+  llvm.func @generic_oob_relaxed() {
+    llvm.return
+  }
+}
+
+// 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}


        


More information about the Mlir-commits mailing list