[Mlir-commits] [mlir] 4e9ded1 - [MLIR][LLVM] Translate LLVMFuncOp function metadata (#203021)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Aug 20 10:04:22 PDT 2026


Author: Akimasa Watanuki
Date: 2026-08-21T02:04:15+09:00
New Revision: 4e9ded133580fb7ea81cfb607357cd8c04663668

URL: https://github.com/llvm/llvm-project/commit/4e9ded133580fb7ea81cfb607357cd8c04663668
DIFF: https://github.com/llvm/llvm-project/commit/4e9ded133580fb7ea81cfb607357cd8c04663668.diff

LOG: [MLIR][LLVM] Translate LLVMFuncOp function metadata (#203021)

Materialize LLVMFuncOp function_metadata through ModuleTranslation
metadata conversion. Attach function metadata after module-level symbols
are mapped so metadata references to functions, globals, aliases, and
ifuncs can be resolved.

Added: 
    mlir/test/Target/LLVMIR/function-metadata.mlir

Modified: 
    mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
    mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index b23f78ff0f98a..6db1951dbdd35 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -416,6 +416,7 @@ class ModuleTranslation {
                                      llvm::IRBuilderBase &builder,
                                      bool recordInsertions = false);
   LogicalResult convertFunctionSignatures();
+  LogicalResult convertFunctionMetadata();
   LogicalResult convertFunctions();
   LogicalResult convertIFuncs();
   LogicalResult convertComdats();

diff  --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 7c01a475029e2..5bb42575a0955 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1648,6 +1648,36 @@ FailureOr<llvm::Metadata *> ModuleTranslation::convertMetadataAttr(
       });
 }
 
+LogicalResult ModuleTranslation::convertFunctionMetadata() {
+  for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
+    ArrayAttr metadata = function.getFunctionMetadataAttr();
+    if (!metadata)
+      continue;
+
+    llvm::Function *llvmFunc = lookupFunction(function.getName());
+    for (auto entry : metadata.getAsRange<LLVM::FunctionMetadataAttr>()) {
+      StringRef metadataName = entry.getMetadataName().getValue();
+
+      FailureOr<llvm::Metadata *> md =
+          convertMetadataAttr(entry.getNode(), [&]() {
+            return function.emitError()
+                   << "failed to convert function_metadata entry '"
+                   << metadataName << "': ";
+          });
+      if (failed(md))
+        return failure();
+      llvm::MDNode *node = llvm::dyn_cast_if_present<llvm::MDNode>(*md);
+      if (!node) {
+        return function.emitError()
+               << "failed to convert function_metadata entry '" << metadataName
+               << "'";
+      }
+      llvmFunc->addMetadata(metadataName, *node);
+    }
+  }
+  return success();
+}
+
 LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
   // Clear the block, branch value mappings, they are only relevant within one
   // function.
@@ -2067,18 +2097,20 @@ ModuleTranslation::convertParameterAttrs(Location loc,
 
 LogicalResult ModuleTranslation::convertFunctionSignatures() {
   // Declare all functions first because there may be function calls that form a
-  // call graph with cycles, or global initializers that reference functions.
+  // call graph with cycles, global initializers that reference functions, or
+  // metadata that references functions declared later in the module.
   for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
     llvm::FunctionCallee llvmFuncCst = llvmModule->getOrInsertFunction(
         function.getName(),
         cast<llvm::FunctionType>(convertType(function.getFunctionType())));
     llvm::Function *llvmFunc = cast<llvm::Function>(llvmFuncCst.getCallee());
+    mapFunction(function.getName(), llvmFunc);
+  }
+
+  for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
+    llvm::Function *llvmFunc = lookupFunction(function.getName());
     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.
@@ -2662,6 +2694,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
     return nullptr;
   if (failed(translator.convertIFuncs()))
     return nullptr;
+  if (failed(translator.convertFunctionMetadata()))
+    return nullptr;
   if (failed(translator.createTBAAMetadata()))
     return nullptr;
   if (failed(translator.createIdentMetadata()))

diff  --git a/mlir/test/Target/LLVMIR/function-metadata.mlir b/mlir/test/Target/LLVMIR/function-metadata.mlir
new file mode 100644
index 0000000000000..91ce21ce75e13
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/function-metadata.mlir
@@ -0,0 +1,104 @@
+// RUN: mlir-translate -verify-diagnostics -split-input-file -mlir-to-llvmir %s | FileCheck %s
+
+// CHECK-LABEL: define void @function_metadata()
+// CHECK-SAME: !type ![[TYPE:[0-9]+]]
+// CHECK-SAME: !annotation ![[ANNOTATION:[0-9]+]]
+llvm.func @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">
+    >>
+  ]
+} {
+  llvm.return
+}
+
+// CHECK-DAG: ![[ANNOTATION]] = !{!"function annotation"}
+// CHECK-DAG: ![[TYPE]] = !{i64 0, !"typeid"}
+
+// -----
+
+// CHECK-LABEL: declare !annotation
+// CHECK-SAME: ![[DECL_ANNOTATION:[0-9]+]] void @declaration_metadata()
+llvm.func @declaration_metadata() attributes {
+  function_metadata = [
+    #llvm.func_metadata<"annotation", #llvm.md_node<
+      #llvm.md_string<"declaration annotation">
+    >>
+  ]
+}
+
+// CHECK-DAG: ![[DECL_ANNOTATION]] = !{!"declaration annotation"}
+
+// -----
+
+// Function metadata is converted after functions and ifuncs are mapped, so
+// references to symbols declared later in the module can be resolved.
+// CHECK-LABEL: define void @uses_later_symbols()
+// CHECK-SAME: !refs ![[LATER_NODE:[0-9]+]]
+llvm.func @uses_later_symbols() attributes {
+  function_metadata = [
+    #llvm.func_metadata<"refs", #llvm.md_node<
+      #llvm.md_global_value<@later_function>,
+      #llvm.md_global_value<@later_ifunc>
+    >>
+  ]
+} {
+  llvm.return
+}
+
+llvm.func @later_function() {
+  llvm.return
+}
+
+llvm.mlir.ifunc external @later_ifunc : !llvm.func<void ()>, !llvm.ptr @later_ifunc_resolver
+
+llvm.func @later_ifunc_resolver() -> !llvm.ptr {
+  %0 = llvm.mlir.addressof @later_function : !llvm.ptr
+  llvm.return %0 : !llvm.ptr
+}
+
+// CHECK-DAG: ![[LATER_NODE]] = !{ptr @later_function, ptr @later_ifunc}
+
+// -----
+
+// CHECK-LABEL: define void @repeated_kind_metadata()
+// CHECK-SAME: !type ![[TYPE0:[0-9]+]]
+// CHECK-SAME: !type ![[TYPE1:[0-9]+]]
+llvm.func @repeated_kind_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">>>
+  ]
+} {
+  llvm.return
+}
+
+// CHECK-DAG: ![[TYPE0]] = !{i64 0, !"typeid0"}
+// CHECK-DAG: ![[TYPE1]] = !{i64 0, !"typeid1"}
+
+// -----
+
+// expected-error @below{{failed to convert function_metadata entry 'callee': could not resolve metadata reference '@missing'}}
+llvm.func @missing_function_metadata_ref() attributes {
+  function_metadata = [
+    #llvm.func_metadata<"callee", #llvm.md_node<#llvm.md_global_value<@missing>>>
+  ]
+} {
+  llvm.return
+}
+
+// -----
+
+// expected-error @below{{failed to convert function_metadata entry 'bad': expected integer attribute in metadata constant}}
+llvm.func @malformed_function_metadata() attributes {
+  function_metadata = [
+    #llvm.func_metadata<"bad", #llvm.md_node<#llvm.md_const<"not an integer">>>
+  ]
+} {
+  llvm.return
+}


        


More information about the Mlir-commits mailing list