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
