[llvm-branch-commits] [mlir] [mlir][LLVM] Add ignore_denormal_mode UnitAttr to LLVM::AtomicRMWOp (PR #217588)

Christian Sigg via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Sep 16 00:08:37 PDT 2026


https://github.com/chsigg updated https://github.com/llvm/llvm-project/pull/217588

>From 5df073e2b6acaf18633df284d0419bb582578915 Mon Sep 17 00:00:00 2001
From: Christian Sigg <csigg at google.com>
Date: Wed, 19 Aug 2026 14:51:10 +0200
Subject: [PATCH] [mlir][LLVM] Add ignore_denormal_mode UnitAttr to
 LLVM::AtomicRMWOp

---
 .../include/mlir/Dialect/LLVMIR/LLVMOpBase.td |  7 +++++
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   | 27 +++++++++++++++----
 .../mlir/Dialect/LLVMIR/ROCDLDialect.td       |  3 +--
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    | 15 ++++++-----
 .../ROCDL/ROCDLToLLVMIRTranslation.cpp        |  6 -----
 mlir/test/Dialect/LLVMIR/invalid.mlir         |  8 ++++++
 mlir/test/Dialect/LLVMIR/roundtrip.mlir       |  4 +++
 .../test/Target/LLVMIR/Import/instructions.ll |  4 +++
 mlir/test/Target/LLVMIR/llvmir.mlir           |  2 ++
 mlir/test/Target/LLVMIR/rocdl.mlir            |  2 --
 10 files changed, 56 insertions(+), 22 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
index 34fb1c6b3153c..34a47274a7fdf 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
@@ -216,6 +216,13 @@ class LLVM_MemOpPatterns {
   code setVolatileCode = [{
     inst->setVolatile($volatile_);
   }];
+  code setIgnoreDenormalModeCode = [{
+    if ($ignore_denormal_mode) {
+      llvm::MDNode *metadata = llvm::MDNode::get(inst->getContext(), {});
+      inst->setMetadata(llvm::LLVMContext::MD_atomic_ignore_denormal_mode,
+                        metadata);
+    }
+  }];
   code setSyncScopeCode = [{
     if ($syncscope.has_value()) {
       llvm::LLVMContext &llvmContext = builder.getContext();
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index b769e3fd0e6f1..2e7ddb98947d2 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2422,12 +2422,14 @@ def LLVM_AtomicRMWOp : LLVM_MemAccessOpBase<"atomicrmw", [
               LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering,
               OptionalAttr<StrAttr>:$syncscope,
               OptionalAttr<I64Attr>:$alignment,
-              UnitAttr:$volatile_);
+              UnitAttr:$volatile_,
+              UnitAttr:$ignore_denormal_mode);
   // Append the aliasing related attributes defined in LLVM_MemAccessOpBase.
   let arguments = !con(args, aliasAttrs);
   let results = (outs LLVM_AtomicRMWType:$res);
   let assemblyFormat = [{
-    (`volatile` $volatile_^)? $bin_op $ptr `,` $val
+    (`volatile` $volatile_^)? (`ignore_denormal_mode` $ignore_denormal_mode^)?
+    $bin_op $ptr `,` $val
     (`syncscope` `(` $syncscope^ `)`)? $ordering
     prop-dict
     attr-dict `:`
@@ -2440,6 +2442,7 @@ def LLVM_AtomicRMWOp : LLVM_MemAccessOpBase<"atomicrmw", [
         convertAtomicOrderingToLLVM($ordering));
     $res = inst;
   }] # setVolatileCode
+     # setIgnoreDenormalModeCode
      # setSyncScopeCode
      # setAlignmentCode
      # setAccessGroupsMetadataCode
@@ -2450,16 +2453,30 @@ def LLVM_AtomicRMWOp : LLVM_MemAccessOpBase<"atomicrmw", [
     $res = LLVM::AtomicRMWOp::create($_builder, $_location,
         convertAtomicBinOpFromLLVM(atomicInst->getOperation()), $ptr, $val,
         convertAtomicOrderingFromLLVM(atomicInst->getOrdering()),
-        getLLVMSyncScope(atomicInst), alignment, atomicInst->isVolatile());
+        getLLVMSyncScope(atomicInst), alignment, atomicInst->isVolatile(),
+        atomicInst->hasMetadata(llvm::LLVMContext::MD_atomic_ignore_denormal_mode));
   }];
-  list<int> llvmArgIndices = [-1, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1];
+  list<int> llvmArgIndices = [-1, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
   let builders = [
     OpBuilder<(ins "LLVM::AtomicBinOp":$binOp, "Value":$ptr, "Value":$val,
       "LLVM::AtomicOrdering":$ordering,
       CArg<"StringRef", "StringRef()">:$syncscope,
-      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile
+      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
+      CArg<"bool", "false">:$ignoreDenormalMode
     )>
   ];
+  let extraClassDeclaration = [{
+    bool isFloatingPointOperation() {
+      return getBinOp() == AtomicBinOp::fadd ||
+             getBinOp() == AtomicBinOp::fsub ||
+             getBinOp() == AtomicBinOp::fmin ||
+             getBinOp() == AtomicBinOp::fmax ||
+             getBinOp() == AtomicBinOp::fminimum ||
+             getBinOp() == AtomicBinOp::fmaximum ||
+             getBinOp() == AtomicBinOp::fminimumnum ||
+             getBinOp() == AtomicBinOp::fmaximumnum;
+    }
+  }];
   let hasVerifier = 1;
 }
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
index a05913bb2c15f..0a41d0b6da6d4 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.td
@@ -170,8 +170,7 @@ def ROCDL_Dialect : Dialect {
      // Correspond to LLVM metadata of the same name
      "::mlir::UnitAttr":$last_use,
      "::mlir::UnitAttr":$no_remote_memory,
-     "::mlir::UnitAttr":$no_fine_grained_memory,
-     "::mlir::UnitAttr":$ignore_denormal_mode
+     "::mlir::UnitAttr":$no_fine_grained_memory
   );
 
   let useDefaultAttributePrinterParser = 1;
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 114800058f7e6..581cc956aecce 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3786,22 +3786,19 @@ OpFoldResult LLVM::ConstantOp::fold(FoldAdaptor) { return getValue(); }
 void AtomicRMWOp::build(OpBuilder &builder, OperationState &state,
                         AtomicBinOp binOp, Value ptr, Value val,
                         AtomicOrdering ordering, StringRef syncscope,
-                        unsigned alignment, bool isVolatile) {
+                        unsigned alignment, bool isVolatile,
+                        bool ignoreDenormalMode) {
   build(builder, state, val.getType(), binOp, ptr, val, ordering,
         !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
         alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
+        ignoreDenormalMode,
         /*access_groups=*/nullptr,
         /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
 }
 
 LogicalResult AtomicRMWOp::verify() {
   auto valType = getVal().getType();
-  if (getBinOp() == AtomicBinOp::fadd || getBinOp() == AtomicBinOp::fsub ||
-      getBinOp() == AtomicBinOp::fmin || getBinOp() == AtomicBinOp::fmax ||
-      getBinOp() == AtomicBinOp::fminimum ||
-      getBinOp() == AtomicBinOp::fmaximum ||
-      getBinOp() == AtomicBinOp::fminimumnum ||
-      getBinOp() == AtomicBinOp::fmaximumnum) {
+  if (isFloatingPointOperation()) {
     if (isCompatibleVectorType(valType)) {
       if (isScalableVectorType(valType))
         return emitOpError("expected LLVM IR fixed vector type");
@@ -3824,6 +3821,10 @@ LogicalResult AtomicRMWOp::verify() {
       return emitOpError("expected LLVM IR integer type");
   }
 
+  if (getIgnoreDenormalMode() && !isFloatingPointOperation())
+    return emitOpError(
+        "expected floating-point operation with 'ignore_denormal_mode'");
+
   if (static_cast<unsigned>(getOrdering()) <
       static_cast<unsigned>(AtomicOrdering::monotonic))
     return emitOpError() << "expected at least '"
diff --git a/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp
index 895d81dffa27b..ad57551a5ae0e 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.cpp
@@ -257,12 +257,6 @@ class ROCDLDialectLLVMIRTranslationInterface
         i->setMetadata("amdgpu.no.fine.grained.memory",
                        llvm::MDNode::get(llvmContext, {}));
     }
-    if (dialect->getIgnoreDenormalModeAttrHelper().getName() ==
-        attribute.getName()) {
-      for (llvm::Instruction *i : instructions)
-        i->setMetadata(llvm::LLVMContext::MD_atomic_ignore_denormal_mode,
-                       llvm::MDNode::get(llvmContext, {}));
-    }
 
     return success();
   }
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index c2d59c1564a42..27671e9e984b9 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -887,6 +887,14 @@ func.func @atomicrmw_expected_int(%f32_ptr : !llvm.ptr, %f32 : f32) {
 
 // -----
 
+func.func @atomicrmw_expected_float_ignore_denormal_mode(%i32_ptr : !llvm.ptr, %i32 : i32) {
+  // expected-error at +1 {{expected floating-point operation with 'ignore_denormal_mode'}}
+  %0 = llvm.atomicrmw ignore_denormal_mode add %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  llvm.return
+}
+
+// -----
+
 func.func @cmpxchg_mismatched_value_operands(%ptr : !llvm.ptr, %i32 : i32, %i64 : i64) {
   // expected-error at +1 {{op failed to verify that operand #1 and operand #2 have the same type}}
   %0 = "llvm.cmpxchg"(%ptr, %i32, %i64) <{success_ordering=2,failure_ordering=2}> : (!llvm.ptr, i32, i64) -> !llvm.struct<(i32, i1)>
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index f33cce1b8928e..def1927847a79 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -569,6 +569,10 @@ func.func @atomicrmw(%ptr : !llvm.ptr, %f32 : f32, %f16_vec : vector<2xf16>) {
   %2 = llvm.atomicrmw fmin %ptr, %f16_vec monotonic : !llvm.ptr, vector<2xf16>
   // CHECK: llvm.atomicrmw fminimumnum %{{.*}}, %{{.*}} monotonic : !llvm.ptr, f32
   %3 = llvm.atomicrmw fminimumnum %ptr, %f32 monotonic : !llvm.ptr, f32
+  // CHECK: llvm.atomicrmw ignore_denormal_mode fadd %{{.*}}, %{{.*}} monotonic : !llvm.ptr, f32
+  %4 = llvm.atomicrmw ignore_denormal_mode fadd %ptr, %f32 monotonic : !llvm.ptr, f32
+  // CHECK: llvm.atomicrmw volatile ignore_denormal_mode fsub %{{.*}}, %{{.*}} syncscope("singlethread") monotonic <alignment = 16> : !llvm.ptr, f32
+  %5 = llvm.atomicrmw volatile ignore_denormal_mode fsub %ptr, %f32 syncscope("singlethread") monotonic <alignment = 16> : !llvm.ptr, f32
   llvm.return
 }
 
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 28ab4bc44a40a..e6caf655aa667 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -485,9 +485,13 @@ define void @atomic_rmw(ptr %ptr1, i32 %val1, ptr %ptr2, float %val2) {
   ; CHECK-SAME:  syncscope("singlethread")
   ; CHECK-SAME:  alignment = 8
   %22 = atomicrmw volatile udec_wrap ptr %ptr1, i32 %val1 syncscope("singlethread") acquire, align 8
+  ; CHECK:  llvm.atomicrmw ignore_denormal_mode fadd %[[PTR2]], %[[VAL2]] acquire
+  %23 = atomicrmw fadd ptr %ptr2, float %val2 acquire, !atomic.ignore.denormal.mode !0
   ret void
 }
 
+!0 = !{}
+
 ; // -----
 
 ; CHECK-LABEL: @atomic_cmpxchg
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index d9bc379ade0a4..0214eebb98f0f 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -1669,6 +1669,8 @@ llvm.func @atomicrmw(
   // CHECK-SAME:  syncscope("singlethread")
   // CHECK-SAME:  align 8
   %27 = llvm.atomicrmw volatile udec_wrap %i32_ptr, %i32 syncscope("singlethread") monotonic <alignment = 8> : !llvm.ptr, i32
+  // CHECK: atomicrmw fadd ptr %{{.*}}, float %{{.*}} monotonic, align 4, !atomic.ignore.denormal.mode !{{[0-9]+}}
+  %28 = llvm.atomicrmw ignore_denormal_mode fadd %f32_ptr, %f32 monotonic : !llvm.ptr, f32
   llvm.return
 }
 
diff --git a/mlir/test/Target/LLVMIR/rocdl.mlir b/mlir/test/Target/LLVMIR/rocdl.mlir
index b4a94cef770fa..84d224e0fb8e0 100644
--- a/mlir/test/Target/LLVMIR/rocdl.mlir
+++ b/mlir/test/Target/LLVMIR/rocdl.mlir
@@ -1962,11 +1962,9 @@ llvm.func @rocdl_4_bit_floats(
 llvm.func @rocdl_atomic_attrs(%ptr: !llvm.ptr<1>, %data: f32) {
   // CHECK-LABEL: @rocdl_atomic_attrs
   // CHECK: atomicrmw
-  // CHECK-SAME: !atomic.ignore.denormal.mode
   // CHECK-SAME: !amdgpu.no.fine.grained.memory
   // CHECK-SAME: !amdgpu.no.remote.memory
   llvm.atomicrmw fadd %ptr, %data monotonic {
-    rocdl.ignore_denormal_mode,
     rocdl.no_fine_grained_memory,
     rocdl.no_remote_memory} : !llvm.ptr<1>, f32
   llvm.return



More information about the llvm-branch-commits mailing list