From 9265f9284c1306d30f5e63efaec805b308fe0457 Mon Sep 17 00:00:00 2001 From: adams381 Date: Mon, 6 Apr 2026 11:26:11 -0500 Subject: [PATCH] [mlir][ABI] Add writable, dead_on_unwind, dead_on_return, nofpclass param attrs to LLVM dialect (#188374) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MLIR LLVM dialect is missing support for several parameter attributes that exist in LLVM IR: `writable`, `dead_on_unwind`, `dead_on_return`, and `nofpclass`. This adds them to the kind-to-name mapping in `AttrKindDetail.h` and the corresponding name accessors in `LLVMDialect.td`. The existing generic conversion infrastructure in `ModuleTranslation` and `ModuleImport` picks them up automatically — `writable` and `dead_on_unwind` round-trip as `UnitAttr`, while `dead_on_return` and `nofpclass` round-trip as `IntegerAttr`. CIR needs these to match classic codegen's ABI output (sret gets `writable dead_on_unwind`, indirect args get `dead_on_return`, fast-math FP args get `nofpclass`). --- .../mlir/Dialect/LLVMIR/LLVMDialect.td | 4 +++ mlir/lib/Target/LLVMIR/AttrKindDetail.h | 7 ++++ .../LLVMIR/Import/function-attributes.ll | 18 ++++++++-- mlir/test/Target/LLVMIR/llvmir.mlir | 35 +++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td index d2d71318a611..01a3c8e9a1bd 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td @@ -62,7 +62,11 @@ def LLVM_Dialect : Dialect { static StringRef getSExtAttrName() { return "llvm.signext"; } static StringRef getStackAlignmentAttrName() { return "llvm.alignstack"; } static StringRef getStructRetAttrName() { return "llvm.sret"; } + static StringRef getWritableAttrName() { return "llvm.writable"; } static StringRef getWriteOnlyAttrName() { return "llvm.writeonly"; } + static StringRef getDeadOnUnwindAttrName() { return "llvm.dead_on_unwind"; } + static StringRef getDeadOnReturnAttrName() { return "llvm.dead_on_return"; } + static StringRef getNoFPClassAttrName() { return "llvm.nofpclass"; } static StringRef getZExtAttrName() { return "llvm.zeroext"; } static StringRef getOpBundleSizesAttrName() { return "op_bundle_sizes"; } static StringRef getOpBundleTagsAttrName() { return "op_bundle_tags"; } diff --git a/mlir/lib/Target/LLVMIR/AttrKindDetail.h b/mlir/lib/Target/LLVMIR/AttrKindDetail.h index 051ed1edc4fd..02b1360a6c77 100644 --- a/mlir/lib/Target/LLVMIR/AttrKindDetail.h +++ b/mlir/lib/Target/LLVMIR/AttrKindDetail.h @@ -56,8 +56,15 @@ getAttrKindToNameMapping() { LLVMDialect::getStackAlignmentAttrName()}, {llvm::Attribute::AttrKind::StructRet, LLVMDialect::getStructRetAttrName()}, + {llvm::Attribute::AttrKind::Writable, LLVMDialect::getWritableAttrName()}, {llvm::Attribute::AttrKind::WriteOnly, LLVMDialect::getWriteOnlyAttrName()}, + {llvm::Attribute::AttrKind::DeadOnUnwind, + LLVMDialect::getDeadOnUnwindAttrName()}, + {llvm::Attribute::AttrKind::DeadOnReturn, + LLVMDialect::getDeadOnReturnAttrName()}, + {llvm::Attribute::AttrKind::NoFPClass, + LLVMDialect::getNoFPClassAttrName()}, {llvm::Attribute::AttrKind::ZExt, LLVMDialect::getZExtAttrName()}}; return kindNamePairs; } diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll index 6d057f4e11f7..5d664519e100 100644 --- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll +++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll @@ -53,7 +53,10 @@ attributes #0 = { readnone } ; CHECK-SAME: !llvm.ptr {llvm.preallocated = f64} ; CHECK-SAME: !llvm.ptr {llvm.returned} ; CHECK-SAME: !llvm.ptr {llvm.alignstack = 32 : i64} -; CHECK-SAME: !llvm.ptr {llvm.writeonly} +; CHECK-SAME: !llvm.ptr {llvm.writable, llvm.writeonly} +; CHECK-SAME: !llvm.ptr {llvm.dead_on_unwind} +; CHECK-SAME: !llvm.ptr {llvm.dead_on_return = 8 : i64} +; CHECK-SAME: f32 {llvm.nofpclass = 519 : i64} ; CHECK-SAME: i64 {llvm.range = #llvm.constant_range} define ptr @func_arg_attrs( ptr byval(i64) %arg0, @@ -73,8 +76,11 @@ define ptr @func_arg_attrs( ptr preallocated(double) %arg16, ptr returned %arg17, ptr alignstack(32) %arg18, - ptr writeonly %arg19, - i64 range(i64 0, 4097) %arg20) { + ptr writable writeonly %arg19, + ptr dead_on_unwind %arg20, + ptr dead_on_return(8) %arg21, + float nofpclass(nan inf) %arg22, + i64 range(i64 0, 4097) %arg23) { ret ptr %arg17 } @@ -134,6 +140,12 @@ declare noundef ptr @func_res_attr_noundef() ; // ----- +; CHECK-LABEL: @func_res_attr_nofpclass +; CHECK-SAME: (f32 {llvm.nofpclass = 519 : i64}) +declare nofpclass(nan inf) float @func_res_attr_nofpclass() + +; // ----- + ; CHECK-LABEL: @func_res_attr_dereferenceable ; CHECK-SAME: !llvm.ptr {llvm.dereferenceable = 42 : i64} declare dereferenceable(42) ptr @func_res_attr_dereferenceable() diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 4ac3776d87c8..6882de8ed446 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1227,6 +1227,41 @@ llvm.func @alignstackattr_decl(!llvm.ptr {llvm.alignstack = 32 : i64}) // CHECK-LABEL: declare void @writeonlyattr_decl(ptr writeonly) llvm.func @writeonlyattr_decl(!llvm.ptr {llvm.writeonly}) +// CHECK-LABEL: define void @writableattr(ptr writable % +llvm.func @writableattr(%arg0: !llvm.ptr {llvm.writable}) { + llvm.return +} + +// CHECK-LABEL: declare void @writableattr_decl(ptr writable) +llvm.func @writableattr_decl(!llvm.ptr {llvm.writable}) + +// CHECK-LABEL: define void @deadonunwindattr(ptr dead_on_unwind % +llvm.func @deadonunwindattr(%arg0: !llvm.ptr {llvm.dead_on_unwind}) { + llvm.return +} + +// CHECK-LABEL: declare void @deadonunwindattr_decl(ptr dead_on_unwind) +llvm.func @deadonunwindattr_decl(!llvm.ptr {llvm.dead_on_unwind}) + +// CHECK-LABEL: define void @deadonreturnattr(ptr dead_on_return(8) % +llvm.func @deadonreturnattr(%arg0: !llvm.ptr {llvm.dead_on_return = 8 : i64}) { + llvm.return +} + +// CHECK-LABEL: declare void @deadonreturnattr_decl(ptr dead_on_return(8)) +llvm.func @deadonreturnattr_decl(!llvm.ptr {llvm.dead_on_return = 8 : i64}) + +// CHECK-LABEL: define void @nofpclassattr(float nofpclass(nan inf) % +llvm.func @nofpclassattr(%arg0: f32 {llvm.nofpclass = 519 : i64}) { + llvm.return +} + +// CHECK-LABEL: declare void @nofpclassattr_decl(float nofpclass(nan inf)) +llvm.func @nofpclassattr_decl(f32 {llvm.nofpclass = 519 : i64}) + +// CHECK-LABEL: declare nofpclass(nan inf) float @nofpclassattr_ret_decl() +llvm.func @nofpclassattr_ret_decl() -> (f32 {llvm.nofpclass = 519 : i64}) + // CHECK-LABEL: declare align 4 ptr @alignattr_ret_decl() llvm.func @alignattr_ret_decl() -> (!llvm.ptr {llvm.align = 4})