[MLIR][LLVM] Preserve unknown function metadata on import

Import representable 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 the supported generic metadata subset.

Warn and drop attachments outside that subset while continuing to import the
function.
This commit is contained in:
mencotton 2026-06-08 20:54:24 +09:00
parent 1d87038375
commit 82d818b02a
2 changed files with 146 additions and 5 deletions

View file

@ -3292,18 +3292,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();

View file

@ -0,0 +1,110 @@
; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
; RUN: mlir-translate -import-llvm -split-input-file %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN
; 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_global_value<@callee>>>
define void @function_ref_metadata() !callees !0 {
ret void
}
!0 = !{ptr @callee}
; // -----
define void @alias_target() {
ret void
}
@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_global_value<@alias>>>
define void @alias_ref_metadata() !callees !0 {
ret void
}
!0 = !{ptr @alias}
; // -----
@global = global i32 0
; CHECK-LABEL: llvm.func @global_ref_metadata
; CHECK-SAME: function_metadata
; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_global_value<@global>>>
define void @global_ref_metadata() !callees !0 {
ret void
}
!0 = !{ptr @global}
; // -----
@0 = global i32 0
; CHECK-LABEL: llvm.func @nameless_global_ref_metadata
; CHECK-SAME: function_metadata
; CHECK-SAME: #llvm.func_metadata<"callees", <#llvm.md_global_value<@{{mlir\.llvm\.nameless_global_[0-9]+}}>>>
define void @nameless_global_ref_metadata() !callees !0 {
ret void
}
!0 = !{ptr @0}
; // -----
@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_global_value<@ifunc>>>
define void @ifunc_ref_metadata() !callees !0 {
ret void
}
!0 = !{ptr @ifunc}
; // -----
; WARN: warning: unhandled function metadata:
; WARN-SAME: !{{[0-9]+}} = distinct !{!"identity"}
; WARN-SAME: on define void @distinct_metadata()
; CHECK-LABEL: llvm.func @distinct_metadata()
; CHECK-NOT: function_metadata
; CHECK: llvm.return
define void @distinct_metadata() !annotation !0 {
ret void
}
!0 = distinct !{!"identity"}