[MLIR][LLVM] Translate LLVMFuncOp function metadata
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.
This commit is contained in:
parent
396eb66627
commit
1d87038375
2 changed files with 205 additions and 5 deletions
|
|
@ -1635,6 +1635,46 @@ FailureOr<llvm::Metadata *> ModuleTranslation::convertMetadataAttr(
|
|||
});
|
||||
}
|
||||
|
||||
/// Converts generic function metadata from `func` and attaches it to
|
||||
/// `llvmFunc`.
|
||||
static LogicalResult convertFunctionMetadata(ModuleTranslation &translation,
|
||||
LLVMFuncOp func,
|
||||
llvm::Function *llvmFunc) {
|
||||
ArrayAttr metadata = func.getFunctionMetadataAttr();
|
||||
if (!metadata)
|
||||
return success();
|
||||
|
||||
for (auto entry : metadata.getAsRange<LLVM::FunctionMetadataAttr>()) {
|
||||
StringRef metadataName = entry.getMetadataName().getValue();
|
||||
|
||||
FailureOr<llvm::Metadata *> md =
|
||||
translation.convertMetadataAttr(entry.getNode(), [&]() {
|
||||
return func.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 func.emitError() << "failed to convert function_metadata entry '"
|
||||
<< metadataName << "'";
|
||||
}
|
||||
llvmFunc->addMetadata(metadataName, *node);
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
static LogicalResult convertFunctionMetadata(ModuleTranslation &translation,
|
||||
Operation *module) {
|
||||
for (auto function : getModuleBody(module).getOps<LLVMFuncOp>()) {
|
||||
llvm::Function *llvmFunc = translation.lookupFunction(function.getName());
|
||||
if (failed(convertFunctionMetadata(translation, function, llvmFunc)))
|
||||
return failure();
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
|
||||
// Clear the block, branch value mappings, they are only relevant within one
|
||||
// function.
|
||||
|
|
@ -2054,18 +2094,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.
|
||||
|
|
@ -2649,6 +2691,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
|
|||
return nullptr;
|
||||
if (failed(translator.convertIFuncs()))
|
||||
return nullptr;
|
||||
if (failed(convertFunctionMetadata(translator, module)))
|
||||
return nullptr;
|
||||
if (failed(translator.createTBAAMetadata()))
|
||||
return nullptr;
|
||||
if (failed(translator.createIdentMetadata()))
|
||||
|
|
|
|||
156
mlir/test/Target/LLVMIR/function-metadata.mlir
Normal file
156
mlir/test/Target/LLVMIR/function-metadata.mlir
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// 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"}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: define void @uses_later()
|
||||
// CHECK-SAME: !callee ![[LATER_NODE:[0-9]+]]
|
||||
llvm.func @uses_later() attributes {
|
||||
function_metadata = [
|
||||
#llvm.func_metadata<"callee", #llvm.md_node<#llvm.md_string<"later">, #llvm.md_global_value<@later>>>
|
||||
]
|
||||
} {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
llvm.func @later() {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
// CHECK-DAG: ![[LATER_NODE]] = !{!"later", ptr @later}
|
||||
|
||||
// -----
|
||||
|
||||
llvm.mlir.global internal @metadata_global(0 : i32) : i32
|
||||
|
||||
// CHECK-LABEL: define void @uses_global()
|
||||
// CHECK-SAME: !callee ![[GLOBAL_NODE:[0-9]+]]
|
||||
llvm.func @uses_global() attributes {
|
||||
function_metadata = [
|
||||
#llvm.func_metadata<"callee", #llvm.md_node<#llvm.md_global_value<@metadata_global>>>
|
||||
]
|
||||
} {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
// CHECK-DAG: ![[GLOBAL_NODE]] = !{ptr @metadata_global}
|
||||
|
||||
// -----
|
||||
|
||||
llvm.func @metadata_alias_target() {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
llvm.mlir.alias external @metadata_alias : !llvm.func<void ()> {
|
||||
%0 = llvm.mlir.addressof @metadata_alias_target : !llvm.ptr
|
||||
llvm.return %0 : !llvm.ptr
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @uses_alias()
|
||||
// CHECK-SAME: !callee ![[ALIAS_NODE:[0-9]+]]
|
||||
llvm.func @uses_alias() attributes {
|
||||
function_metadata = [
|
||||
#llvm.func_metadata<"callee", #llvm.md_node<#llvm.md_global_value<@metadata_alias>>>
|
||||
]
|
||||
} {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
// CHECK-DAG: ![[ALIAS_NODE]] = !{ptr @metadata_alias}
|
||||
|
||||
// -----
|
||||
|
||||
llvm.mlir.ifunc external @metadata_ifunc : !llvm.func<void ()>, !llvm.ptr @metadata_ifunc_resolver
|
||||
|
||||
llvm.func @metadata_ifunc_resolver() -> !llvm.ptr {
|
||||
%0 = llvm.mlir.addressof @metadata_ifunc_target : !llvm.ptr
|
||||
llvm.return %0 : !llvm.ptr
|
||||
}
|
||||
|
||||
llvm.func @metadata_ifunc_target() {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @uses_ifunc()
|
||||
// CHECK-SAME: !callee ![[IFUNC_NODE:[0-9]+]]
|
||||
llvm.func @uses_ifunc() attributes {
|
||||
function_metadata = [
|
||||
#llvm.func_metadata<"callee", #llvm.md_node<#llvm.md_global_value<@metadata_ifunc>>>
|
||||
]
|
||||
} {
|
||||
llvm.return
|
||||
}
|
||||
|
||||
// CHECK-DAG: ![[IFUNC_NODE]] = !{ptr @metadata_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
|
||||
}
|
||||
Loading…
Reference in a new issue