[Mlir-commits] [mlir] [mlir][llvm] Add convergent attribute to llvm.inline_asm. (PR #221990)

Benjamin Chetioui llvmlistbot at llvm.org
Tue Sep 8 06:08:36 PDT 2026


https://github.com/bchetioui created https://github.com/llvm/llvm-project/pull/221990

Expose LLVM's convergent call-site attribute on the LLVM dialect inline_asm op. This allows marking an inline asm block as convergent so that divergence-aware passes do not move it relative to divergent control flow.

>From 5181c058fe565f93f19b4414cb04f6c6207b6fcd Mon Sep 17 00:00:00 2001
From: Benjamin Chetioui <bchetioui at google.com>
Date: Tue, 8 Sep 2026 13:04:43 +0000
Subject: [PATCH] [mlir][llvm] Add convergent attribute to llvm.inline_asm.

Expose LLVM's convergent call-site attribute on the LLVM dialect
inline_asm op. This allows marking an inline asm block as convergent so
that divergence-aware passes do not move it relative to divergent control
flow.
---
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td         |  2 ++
 mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp |  1 +
 mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp     |  1 +
 .../Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp  |  1 +
 mlir/lib/Dialect/X86/Transforms/AVXTranspose.cpp    |  1 +
 .../Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp      |  2 ++
 mlir/lib/Target/LLVMIR/ModuleImport.cpp             |  1 +
 mlir/test/Dialect/LLVMIR/roundtrip.mlir             |  3 +++
 mlir/test/Target/LLVMIR/Import/instructions.ll      | 13 +++++++++++++
 mlir/test/Target/LLVMIR/llvmir.mlir                 |  5 +++++
 10 files changed, 30 insertions(+)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index ceb418ebd2998..9811b93539a9b 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2548,6 +2548,7 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
         UnitAttr:$has_side_effects,
         UnitAttr:$is_align_stack,
         DefaultValuedAttr<TailCallKind, "TailCallKind::None">:$tail_call_kind,
+        UnitAttr:$convergent,
         OptionalAttr<
           DefaultValuedAttr<AsmATTOrIntel, "AsmDialect::AD_ATT">>:$asm_dialect,
         OptionalAttr<ArrayAttr>:$operand_attrs);
@@ -2558,6 +2559,7 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
     (`has_side_effects` $has_side_effects^)?
     (`is_align_stack` $is_align_stack^)?
     (`tail_call_kind` `=` $tail_call_kind^)?
+    (`convergent` $convergent^)?
     (`asm_dialect` `=` $asm_dialect^)?
     (`operand_attrs` `=` $operand_attrs^)?
     attr-dict
diff --git a/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp b/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
index cb7192f651a0d..8aacd032b932a 100644
--- a/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
+++ b/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
@@ -666,6 +666,7 @@ struct LDSBarrierOpLowering : public ConvertOpToLLVMPattern<LDSBarrierOp> {
           /*resultTypes=*/TypeRange(), /*operands=*/ValueRange(),
           /*asm_string=*/asmStr, constraints, /*has_side_effects=*/true,
           /*is_align_stack=*/false, LLVM::TailCallKind::None,
+          /*convergent=*/false,
           /*asm_dialect=*/asmDialectAttr,
           /*operand_attrs=*/ArrayAttr());
     } else if (chipset.majorVersion < 12) {
diff --git a/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp b/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
index 4bc0d3a7a6ebe..7c393e8cf2b66 100644
--- a/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
+++ b/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
@@ -566,6 +566,7 @@ static FailureOr<LLVM::InlineAsmOp> emitMmaSparseSyncOpAsm(
                                    /*has_side_effects=*/true,
                                    /*is_align_stack=*/false,
                                    LLVM::TailCallKind::None,
+                                   /*convergent=*/false,
                                    /*asm_dialect=*/asmDialectAttr,
                                    /*operand_attrs=*/ArrayAttr());
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp b/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp
index a8767611adb64..64cec0eadd2cb 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp
@@ -505,6 +505,7 @@ LLVM::InlineAsmOp PtxBuilder::build() {
       /*constraints=*/registerConstraints.data(),
       /*has_side_effects=*/interfaceOp.hasSideEffect(),
       /*is_align_stack=*/false, LLVM::TailCallKind::None,
+      /*convergent=*/false,
       /*asm_dialect=*/asmDialectAttr,
       /*operand_attrs=*/ArrayAttr());
 }
diff --git a/mlir/lib/Dialect/X86/Transforms/AVXTranspose.cpp b/mlir/lib/Dialect/X86/Transforms/AVXTranspose.cpp
index bd649a555461f..089de23f3a8ed 100644
--- a/mlir/lib/Dialect/X86/Transforms/AVXTranspose.cpp
+++ b/mlir/lib/Dialect/X86/Transforms/AVXTranspose.cpp
@@ -41,6 +41,7 @@ Value mlir::x86::avx2::inline_asm::mm256BlendPsAsm(ImplicitLocOpBuilder &b,
       b, v1.getType(), /*operands=*/asmVals, /*asm_string=*/asmStr,
       /*constraints=*/asmCstr, /*has_side_effects=*/false,
       /*is_align_stack=*/false, LLVM::TailCallKind::None,
+      /*convergent=*/false,
       /*asm_dialect=*/asmDialectAttr,
       /*operand_attrs=*/ArrayAttr());
   return asmOp.getResult(0);
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 497b24c94811c..0c715da6ba954 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -607,6 +607,8 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
         moduleTranslation.lookupValues(inlineAsmOp.getOperands()));
     inst->setTailCallKind(convertTailCallKindToLLVM(
         inlineAsmOp.getTailCallKindAttr().getTailCallKind()));
+    if (inlineAsmOp.getConvergent())
+      inst->addFnAttr(llvm::Attribute::Convergent);
     if (auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
       llvm::AttributeList attrList;
       for (const auto &it : llvm::enumerate(*maybeOperandAttrs)) {
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index bc4ca805b9d7b..00fb013f08d5e 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2551,6 +2551,7 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
                    builder.getStringAttr(asmI->getConstraintString()),
                    asmI->hasSideEffects(), asmI->isAlignStack(),
                    convertTailCallKindFromLLVM(callInst->getTailCallKind()),
+                   callInst->hasFnAttr(llvm::Attribute::Convergent),
                    AsmDialectAttr::get(
                        mlirModule.getContext(),
                        convertAsmDialectFromLLVM(asmI->getDialect())),
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 42581ca2e3d92..a17ee35808ed9 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -721,6 +721,9 @@ llvm.func @useInlineAsm(%arg0: i32) {
   // CHECK-NEXT:  llvm.inline_asm "foo", "=r,=r,r" {{.*}} : (i32) -> !llvm.struct<(i8, i8)>
   %5 = llvm.inline_asm "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
 
+  // CHECK-NEXT:  llvm.inline_asm convergent {{.*}} (i32) -> i8
+  %6 = llvm.inline_asm convergent "bswap $0", "=r,r" %arg0 : (i32) -> i8
+
   llvm.return
 }
 
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 4116bed6f3489..6665262a035dd 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -555,6 +555,19 @@ define i32 @inlineasm(i32 %arg1) {
 
 ; // -----
 
+; CHECK-LABEL: @inlineasm_convergent
+; CHECK-SAME:  %[[ARG1:[a-zA-Z0-9]+]]
+define i32 @inlineasm_convergent(i32 %arg1) {
+  ; CHECK:  %[[RES:.+]] = llvm.inline_asm convergent asm_dialect = att "bswap $0", "=r,r" %[[ARG1]] : (i32) -> i32
+  %1 = call i32 asm "bswap $0", "=r,r"(i32 %arg1) #0
+  ; CHECK: return %[[RES]]
+  ret i32 %1
+}
+
+attributes #0 = { convergent }
+
+; // -----
+
 ; CHECK-LABEL: @inlineasm2
 define void @inlineasm2() {
   %p = alloca ptr, align 8
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 9f99bf83dae95..84d892876d36a 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2209,9 +2209,14 @@ llvm.func @useInlineAsm(%arg0: i32, %arg1 : !llvm.ptr) {
   // CHECK-NEXT:  notail call { i8, i8 } asm "foo", "=r,=r,r"(i32 {{.*}})
   %8 = llvm.inline_asm tail_call_kind = <notail> "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
 
+  // CHECK-NEXT:  call i8 asm "foo", "=r,r"(i32 {{.*}}) #[[$CONVERGENT:.*]]
+  %9 = llvm.inline_asm convergent "foo", "=r,r" %arg0 : (i32) -> i8
+
   llvm.return
 }
 
+// CHECK: attributes #[[$CONVERGENT]] = { convergent }
+
 // -----
 
 // CHECK: @useInlineAsm2(ptr %[[A0:.*]], i64 %[[A1:.*]], ptr %[[A2:.*]], i64 %[[A3:.*]]) {



More information about the Mlir-commits mailing list