[llvm-branch-commits] [mlir] [MLIR][LLVM] Add function metadata to LLVMFuncOp (PR #203018)

Akimasa Watanuki via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jun 12 09:06:34 PDT 2026


https://github.com/Men-cotton updated https://github.com/llvm/llvm-project/pull/203018

>From db44ba015a82df6384b697eff94e5ed28b49522e Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Mon, 8 Jun 2026 20:51:57 +0900
Subject: [PATCH] [MLIR][LLVM] Add function metadata to LLVMFuncOp

Add a generic LLVM dialect carrier for LLVM IR function metadata on LLVMFuncOp.
Represent attachments as an ordered list so repeated metadata kinds, such as
multiple type metadata attachments, can be preserved while keeping metadata names
language-agnostic.
---
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       | 22 +++++++++++++++++++
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   |  1 +
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 17 ++++++++++++++
 mlir/lib/Target/LLVMIR/ModuleTranslation.cpp  |  3 +++
 mlir/test/Dialect/LLVMIR/invalid.mlir         | 20 +++++++++++++++++
 mlir/test/Dialect/LLVMIR/roundtrip.mlir       | 22 +++++++++++++++++++
 6 files changed, 85 insertions(+)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 831dcecd0fc93..818f05c38264c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1788,6 +1788,28 @@ def LLVM_MDNodeArrayAttr
     : TypedArrayAttrBase<LLVM_MDNodeAttr,
                          "array of #llvm.md_node attributes">;
 
+def LLVM_FunctionMetadataAttr
+    : LLVM_Attr<"FunctionMetadata", "func_metadata"> {
+  let summary = "LLVM function metadata attachment";
+  let description = [{
+    Models one LLVM IR function metadata attachment. LLVM IR allows several
+    attachments with the same metadata kind, so function metadata is represented
+    as an ordered list of these entries instead of a dictionary.
+
+    Example:
+    ```mlir
+    #llvm.func_metadata<"type", <#llvm.md_string<"id">>>
+    ```
+  }];
+  let parameters = (ins "StringAttr":$metadataName, "MDNodeAttr":$node);
+  let assemblyFormat = "`<` $metadataName `,` $node `>`";
+  let genVerifyDecl = 1;
+}
+
+def LLVM_FunctionMetadataArrayAttr
+    : TypedArrayAttrBase<LLVM_FunctionMetadataAttr,
+                         "array of #llvm.func_metadata attributes">;
+
 def LLVM_AnyMDAttr : AnyAttrOf<[
     LLVM_MDStringAttr, LLVM_MDConstantAttr, LLVM_MDValueAttr, LLVM_MDNodeAttr],
     "LLVM metadata attribute (md_string, md_const, md_value, or md_node)">;
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 6fda732baa77b..c528b1ba707f6 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2071,6 +2071,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
     OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint,
     OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size,
     OptionalAttr<I32Attr>:$intel_reqd_sub_group_size,
+    OptionalAttr<LLVM_FunctionMetadataArrayAttr>:$function_metadata,
     OptionalAttr<UWTableKindAttr>:$uwtable_kind,
     OptionalAttr<BoolAttr>:$use_sample_profile
   );
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 2bd5b42720ee2..cf753ceb84a59 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -135,6 +135,23 @@ bool AddressSpaceAttr::isValidPtrIntCast(
   return false;
 }
 
+//===----------------------------------------------------------------------===//
+// FunctionMetadataAttr
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+FunctionMetadataAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+                             StringAttr metadataName, MDNodeAttr node) {
+  (void)node;
+  StringRef name = metadataName.getValue();
+  if (name.empty())
+    return emitError() << "function_metadata entry name must not be empty";
+  if (name == "dbg" || name == "prof")
+    return emitError() << "reserved function_metadata entry '" << name
+                       << "' must use a dedicated LLVM dialect representation";
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // AliasScopeAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index af9b1ee58d2da..2193b415637a3 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -2045,6 +2045,9 @@ LogicalResult ModuleTranslation::convertFunctionSignatures() {
     llvmFunc->setLinkage(convertLinkageToLLVM(function.getLinkage()));
     llvmFunc->setCallingConv(convertCConvToLLVM(function.getCConv()));
     mapFunction(function.getName(), llvmFunc);
+    if (function.getFunctionMetadataAttr())
+      return function.emitError()
+             << "not yet implemented: translating function_metadata to LLVM IR";
     addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
 
     // Convert function attributes.
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 98180849223a3..f3f917454f15e 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1847,6 +1847,26 @@ llvm.mlir.alias external @y5 : i32 {
 
 // -----
 
+// expected-error at +1{{attribute 'function_metadata' failed to satisfy constraint: array of #llvm.func_metadata attributes}}
+llvm.func @function_metadata_value() attributes {function_metadata = [#llvm.md_string<"int">]}
+
+// -----
+
+// expected-error at +1{{function_metadata entry name must not be empty}}
+llvm.func @empty_function_metadata_name() attributes {function_metadata = [#llvm.func_metadata<"", #llvm.md_node<#llvm.md_string<"x">>>]}
+
+// -----
+
+// expected-error at +1{{reserved function_metadata entry 'dbg' must use a dedicated LLVM dialect representation}}
+llvm.func @reserved_dbg_function_metadata() attributes {function_metadata = [#llvm.func_metadata<"dbg", #llvm.md_node<#llvm.md_string<"x">>>]}
+
+// -----
+
+// expected-error at +1{{reserved function_metadata entry 'prof' must use a dedicated LLVM dialect representation}}
+llvm.func @reserved_prof_function_metadata() attributes {function_metadata = [#llvm.func_metadata<"prof", #llvm.md_node<#llvm.md_string<"function_entry_count">, #llvm.md_const<1 : i64>>>]}
+
+// -----
+
 // expected-error at +1{{attribute 'nodes' failed to satisfy constraint: array of #llvm.md_node attributes}}
 llvm.named_metadata "not_node" [#llvm.md_string<"int">]
 
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 0300a70251113..9cdbdd2d59297 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -1230,3 +1230,25 @@ llvm.named_metadata "foo.kernel" [
     >
   >
 ]
+
+// CHECK-LABEL: llvm.func @generic_function_metadata
+// CHECK-SAME: function_metadata
+// CHECK-SAME: #llvm.func_metadata<"annotation", <#llvm.md_string<"function annotation">>>
+// CHECK-SAME: #llvm.func_metadata<"type", <#llvm.md_const<0 : i64>, #llvm.md_string<"typeid">>>
+llvm.func @generic_function_metadata() attributes {
+  function_metadata = [
+    #llvm.func_metadata<"annotation", #llvm.md_node<#llvm.md_string<"function annotation">>>,
+    #llvm.func_metadata<"type", #llvm.md_node<#llvm.md_const<0 : i64>, #llvm.md_string<"typeid">>>
+  ]
+}
+
+// CHECK-LABEL: llvm.func @repeated_function_metadata
+// CHECK-SAME: function_metadata
+// CHECK-SAME: #llvm.func_metadata<"type", <#llvm.md_const<0 : i64>, #llvm.md_string<"typeid0">>>
+// CHECK-SAME: #llvm.func_metadata<"type", <#llvm.md_const<0 : i64>, #llvm.md_string<"typeid1">>>
+llvm.func @repeated_function_metadata() attributes {
+  function_metadata = [
+    #llvm.func_metadata<"type", #llvm.md_node<#llvm.md_const<0 : i64>, #llvm.md_string<"typeid0">>>,
+    #llvm.func_metadata<"type", #llvm.md_node<#llvm.md_const<0 : i64>, #llvm.md_string<"typeid1">>>
+  ]
+}



More information about the llvm-branch-commits mailing list