https://github.com/aobolensk created 
https://github.com/llvm/llvm-project/pull/233772

Inline asm may hide a barrier, so it must not be moved into divergent control 
flow

depends on https://github.com/llvm/llvm-project/pull/233770

>From 820d1a5af89ee4f64c7b685773ed11db42a85b4d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <[email protected]>
Date: Tue, 20 Oct 2026 11:52:09 +0200
Subject: [PATCH] [CIR] Mark inline asm convergent in GPU code

Inline asm may hide a barrier, so it must not be moved into divergent control 
flow
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td       |  7 +++++--
 clang/lib/CIR/CodeGen/CIRGenAsm.cpp                |  5 ++++-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp            | 11 ++++++++++-
 .../lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp  |  2 +-
 clang/test/CIR/CodeGen/offload-convergent-attr.cu  | 11 +++++++++++
 clang/test/CIR/IR/inline-asm.cir                   | 14 ++++++++++++++
 clang/test/CIR/Lowering/inline-asm.cir             | 12 ++++++++++++
 7 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 6039e1f49a3ee7..b4bcbacf43f4ac 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5854,6 +5854,9 @@ def CIR_InlineAsmOp : CIR_Op<"asm",
     order: output, input and then in/out operands. When several output operands
     are present, the result type may be represented as an anonymous record 
type.
 
+    The `convergent` attribute marks asm that may contain convergent
+    operations, so it must not be moved across divergent control flow.
+
     Example:
     ```C++
     __asm__("foo" : : : );
@@ -5896,13 +5899,13 @@ def CIR_InlineAsmOp : CIR_Op<"asm",
   let arguments =
       (ins VariadicOfVariadic<AnyType, "operands_segments">:$asm_operands,
           StrAttr:$asm_string, StrAttr:$constraints, UnitAttr:$side_effects,
-          CIR_AsmFlavorAttr:$asm_flavor, ArrayAttr:$operand_attrs,
+          UnitAttr:$convergent, CIR_AsmFlavorAttr:$asm_flavor, 
ArrayAttr:$operand_attrs,
           DenseI32ArrayAttr:$operands_segments);
 
   let builders = [OpBuilder<(ins
       "llvm::ArrayRef<mlir::ValueRange>":$asmOperands,
       "llvm::StringRef":$asmString, "llvm::StringRef":$constraints,
-      "bool":$sideEffects, "AsmFlavor":$asmFlavor,
+      "bool":$sideEffects, "bool":$convergent, "AsmFlavor":$asmFlavor,
       "llvm::ArrayRef<mlir::Attribute>":$operandAttrs)>];
 
   let hasCustomAssemblyFormat = 1;
diff --git a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp 
b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp
index 31b5ff07ecf641..e3ef61969e60ae 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp
@@ -542,11 +542,14 @@ mlir::LogicalResult CIRGenFunction::emitAsmStmt(const 
AsmStmt &s) {
         cir::RecordType::getAllDataKinds(resultRegTypes));
 
   bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0;
+  // Asm may contain an intrinsically convergent op such as a barrier.
+  bool isConvergent = getLangOpts().assumeFunctionsAreConvergent();
 
   std::vector<mlir::Value> regResults;
   cir::InlineAsmOp ia = cir::InlineAsmOp::create(
       builder, getLoc(s.getAsmLoc()), resultType, operands, asmString,
-      constraints, hasSideEffect, inferFlavor(cgm, s), mlir::ArrayAttr());
+      constraints, hasSideEffect, isConvergent, inferFlavor(cgm, s),
+      mlir::ArrayAttr());
 
   if (isGCCAsmGoto) {
     assert(!cir::MissingFeatures::asmGoto());
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 4dfbfbb195ca46..4554829bdc1949 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -4889,6 +4889,8 @@ void cir::InlineAsmOp::print(OpAsmPrinter &p) {
   p << ')';
   if (getSideEffects())
     p << " side_effects";
+  if (getConvergent())
+    p << " convergent";
 
   p.printOptionalAttrDict(
       getOperation()->getDiscardableAttrDictionary().getValue());
@@ -4900,7 +4902,8 @@ void cir::InlineAsmOp::print(OpAsmPrinter &p) {
 void cir::InlineAsmOp::build(OpBuilder &odsBuilder, OperationState &odsState,
                              ArrayRef<ValueRange> asmOperands,
                              StringRef asmString, StringRef constraints,
-                             bool sideEffects, cir::AsmFlavor asmFlavor,
+                             bool sideEffects, bool convergent,
+                             cir::AsmFlavor asmFlavor,
                              ArrayRef<Attribute> operandAttrs) {
   // Set up the operands_segments for VariadicOfVariadic
   SmallVector<int32_t> segments;
@@ -4920,6 +4923,9 @@ void cir::InlineAsmOp::build(OpBuilder &odsBuilder, 
OperationState &odsState,
   if (sideEffects)
     odsState.addAttribute("side_effects", odsBuilder.getUnitAttr());
 
+  if (convergent)
+    odsState.addAttribute("convergent", odsBuilder.getUnitAttr());
+
   odsState.addAttribute("operand_attrs", 
odsBuilder.getArrayAttr(operandAttrs));
 }
 
@@ -5031,6 +5037,9 @@ ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser,
   if (parser.parseOptionalKeyword("side_effects").succeeded())
     result.attributes.set("side_effects", UnitAttr::get(ctxt));
 
+  if (parser.parseOptionalKeyword("convergent").succeeded())
+    result.attributes.set("convergent", UnitAttr::get(ctxt));
+
   if (parser.parseOptionalAttrDict(result.attributes).failed())
     return mlir::failure();
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 40e6a5624366cc..e225559248bdfb 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -6128,7 +6128,7 @@ mlir::LogicalResult 
CIRToLLVMInlineAsmOpLowering::matchAndRewrite(
       /*tail_call_kind*/
       mlir::LLVM::TailCallKindAttr::get(
           getContext(), mlir::LLVM::tailcallkind::TailCallKind::None),
-      /*convergent=*/mlir::UnitAttr(),
+      op.getConvergentAttr(),
       mlir::LLVM::AsmDialectAttr::get(getContext(), llDialect),
       rewriter.getArrayAttr(opAttrs));
 
diff --git a/clang/test/CIR/CodeGen/offload-convergent-attr.cu 
b/clang/test/CIR/CodeGen/offload-convergent-attr.cu
index 1112ca36143265..16bbc2f4ead55b 100644
--- a/clang/test/CIR/CodeGen/offload-convergent-attr.cu
+++ b/clang/test/CIR/CodeGen/offload-convergent-attr.cu
@@ -33,6 +33,15 @@ void caller() {
   // CIR: cir.return
   // LLVM: call void{{.*}}@no_conv() #[[NO_CONV_CALL_ATTR:.*]]
 }
+
+// CIR: cir.func{{.*}}@inline_asm
+__attribute__((device))
+void inline_asm() {
+  asm volatile("");
+  // CIR: cir.asm(
+  // CIR: side_effects convergent
+  // LLVM: call void asm sideeffect "", "{{.*}}"() #[[ASM_ATTR:[0-9]+]]
+}
 }
 
 // LLVM: attributes #[[NORMAL_ATTR]] 
@@ -43,3 +52,5 @@ void caller() {
 // LLVM-SAME: convergent
 // LLVM: attributes #[[NO_CONV_CALL_ATTR]] 
 // LLVM-NOT: convergent
+// LLVM: attributes #[[ASM_ATTR]]
+// LLVM-SAME: convergent
diff --git a/clang/test/CIR/IR/inline-asm.cir b/clang/test/CIR/IR/inline-asm.cir
index 5134df5f4b5eb0..fc59c5b9ac4eaf 100644
--- a/clang/test/CIR/IR/inline-asm.cir
+++ b/clang/test/CIR/IR/inline-asm.cir
@@ -123,4 +123,18 @@ cir.func @f8() -> !s32i {
     {"movl $$7, $0" "=r,~{dirflag},~{fpsr},~{flags}"}) side_effects {test.attr 
= 7 : i32} -> !s32i
   cir.return %0 : !s32i
 }
+
+cir.func @f9() {
+  // CHECK: cir.asm(x86_att,
+  // CHECK:   out = [],
+  // CHECK:   in = [],
+  // CHECK:   in_out = [],
+  // CHECK:   {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects convergent
+  cir.asm(x86_att,
+    out = [],
+    in = [],
+    in_out = [],
+    {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects convergent
+  cir.return
+}
 }
diff --git a/clang/test/CIR/Lowering/inline-asm.cir 
b/clang/test/CIR/Lowering/inline-asm.cir
index b510f23595ae6b..9a5bd8b16f54b2 100644
--- a/clang/test/CIR/Lowering/inline-asm.cir
+++ b/clang/test/CIR/Lowering/inline-asm.cir
@@ -83,4 +83,16 @@ cir.func @f7(%arg0: !u32i) -> !u32i {
    %3 = cir.load align(4) %0 : !cir.ptr<!u32i>, !u32i
    cir.return %3 : !u32i
 }
+
+cir.func @f8() {
+  // CHECK: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() 
#[[CONV:[0-9]+]]
+  cir.asm(x86_att,
+    out = [],
+    in = [],
+    in_out = [],
+    {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects convergent
+  cir.return
 }
+}
+
+// CHECK: attributes #[[CONV]] = { convergent }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to