[llvm-branch-commits] [mlir] [MLIR][LLVM] Preserve unknown function metadata on import (PR #203022)
Akimasa Watanuki via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jun 12 09:06:39 PDT 2026
https://github.com/Men-cotton updated https://github.com/llvm/llvm-project/pull/203022
>From 07c0f68ed5b40d9fc1790176df8513c0ae5f78db Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Mon, 8 Jun 2026 20:54:24 +0900
Subject: [PATCH] [MLIR][LLVM] Preserve unknown function metadata on import
Import non-debug function metadata without a kind-specific dialect conversion into LLVMFuncOp function_metadata. Preserve repeated metadata kinds through the generic carrier so LLVM IR import and export can round-trip those attachments.
---
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 41 +++++++-
.../Target/LLVMIR/Import/function-metadata.ll | 95 +++++++++++++++++++
2 files changed, 131 insertions(+), 5 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/Import/function-metadata.ll
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index def83537df2f8..c1151b1d02603 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -3283,18 +3283,49 @@ LogicalResult ModuleImport::processFunction(llvm::Function *func) {
// Handle Function attributes.
processFunctionAttributes(func, funcOp);
- // Convert non-debug metadata by using the dialect interface.
+ // Convert non-debug metadata by using the dialect interface. Metadata without
+ // a kind-specific dialect conversion is preserved in the generic function
+ // metadata carrier.
SmallVector<std::pair<unsigned, llvm::MDNode *>> allMetadata;
func->getAllMetadata(allMetadata);
+ SmallVector<StringRef> metadataNames;
+ llvmModule->getMDKindNames(metadataNames);
+ SmallVector<Attribute> functionMetadata;
for (auto &[kind, node] : allMetadata) {
- if (!iface.isConvertibleMetadata(kind))
+ if (kind == llvm::LLVMContext::MD_dbg)
continue;
- if (failed(iface.setMetadataAttrs(builder, kind, node, funcOp, *this))) {
+
+ llvm::MDNode *metadataNode = node;
+ auto emitUnhandledFunctionMetadataWarning = [&]() {
emitWarning(funcOp.getLoc())
- << "unhandled function metadata: " << diagMD(node, llvmModule.get())
- << " on " << diag(*func);
+ << "unhandled function metadata: "
+ << diagMD(metadataNode, llvmModule.get()) << " on " << diag(*func);
+ };
+
+ if (!iface.isConvertibleMetadata(kind)) {
+ auto getNamelessGlobalSymbol =
+ [this](llvm::GlobalVariable *globalVar) -> FlatSymbolRefAttr {
+ return getOrCreateNamelessSymbolName(globalVar);
+ };
+ Attribute nodeAttr = convertMetadataToAttr(context, metadataNode, iface,
+ getNamelessGlobalSymbol);
+ auto mdNodeAttr = dyn_cast_if_present<LLVM::MDNodeAttr>(nodeAttr);
+ if (!mdNodeAttr || kind >= metadataNames.size()) {
+ emitUnhandledFunctionMetadataWarning();
+ continue;
+ }
+
+ functionMetadata.push_back(LLVM::FunctionMetadataAttr::get(
+ context, builder.getStringAttr(metadataNames[kind]), mdNodeAttr));
+ continue;
}
+
+ if (failed(
+ iface.setMetadataAttrs(builder, kind, metadataNode, funcOp, *this)))
+ emitUnhandledFunctionMetadataWarning();
}
+ if (!functionMetadata.empty())
+ funcOp.setFunctionMetadataAttr(builder.getArrayAttr(functionMetadata));
if (func->isDeclaration())
return success();
diff --git a/mlir/test/Target/LLVMIR/Import/function-metadata.ll b/mlir/test/Target/LLVMIR/Import/function-metadata.ll
new file mode 100644
index 0000000000000..15cf1835974a8
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/function-metadata.ll
@@ -0,0 +1,95 @@
+; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+
+; CHECK-LABEL: llvm.func @repeated_type_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">>>
+define void @repeated_type_metadata() !type !0 !type !1 {
+ ret void
+}
+
+!0 = !{i64 0, !"typeid0"}
+!1 = !{i64 0, !"typeid1"}
+
+; // -----
+
+; CHECK-LABEL: llvm.func @declaration_metadata
+; CHECK-SAME: function_metadata
+; CHECK-SAME: #llvm.func_metadata<"annotation", <#llvm.md_string<"declaration annotation">>>
+declare !annotation !0 void @declaration_metadata()
+
+!0 = !{!"declaration annotation"}
+
+; // -----
+
+declare void @callee()
+
+; CHECK-LABEL: llvm.func @function_ref_metadata
+; CHECK-SAME: function_metadata
+; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_value<@callee>>>
+define void @function_ref_metadata() !callees !0 {
+ ret void
+}
+
+!0 = !{ptr @callee}
+
+; // -----
+
+define void @alias_target() {
+ ret void
+}
+ at alias = alias void (), ptr @alias_target
+
+; CHECK-LABEL: llvm.func @alias_ref_metadata
+; CHECK-SAME: function_metadata
+; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_value<@alias>>>
+define void @alias_ref_metadata() !callees !0 {
+ ret void
+}
+
+!0 = !{ptr @alias}
+
+; // -----
+
+ at global = global i32 0
+
+; CHECK-LABEL: llvm.func @global_ref_metadata
+; CHECK-SAME: function_metadata
+; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_value<@global>>>
+define void @global_ref_metadata() !callees !0 {
+ ret void
+}
+
+!0 = !{ptr @global}
+
+; // -----
+
+ at 0 = global i32 0
+
+; CHECK-LABEL: llvm.func @nameless_global_ref_metadata
+; CHECK-SAME: function_metadata
+; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_value<@{{mlir\.llvm\.nameless_global_[0-9]+}}>>>
+define void @nameless_global_ref_metadata() !callees !0 {
+ ret void
+}
+
+!0 = !{ptr @0}
+
+; // -----
+
+ at ifunc = ifunc void (), ptr @ifunc_resolver
+define ptr @ifunc_resolver() {
+ ret ptr @ifunc_target
+}
+define void @ifunc_target() {
+ ret void
+}
+
+; CHECK-LABEL: llvm.func @ifunc_ref_metadata
+; CHECK-SAME: function_metadata
+; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_value<@ifunc>>>
+define void @ifunc_ref_metadata() !callees !0 {
+ ret void
+}
+
+!0 = !{ptr @ifunc}
More information about the llvm-branch-commits
mailing list