diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index 55bbf2a02f70..29440ea351f4 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -1810,6 +1810,28 @@ def LLVM_MDNodeArrayAttr : TypedArrayAttrBase; +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; + def LLVM_AnyMDAttr : AnyAttrOf<[ LLVM_MDStringAttr, LLVM_MDConstantAttr, LLVM_MDGlobalValueAttr, LLVM_MDNodeAttr], diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 84f71054994f..e7d17e1ef1f2 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -2077,6 +2077,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [ OptionalAttr:$work_group_size_hint, OptionalAttr:$reqd_work_group_size, OptionalAttr:$intel_reqd_sub_group_size, + OptionalAttr:$function_metadata, OptionalAttr:$uwtable_kind, OptionalAttr:$use_sample_profile ); diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp index 266faeca4553..bb655c749db4 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -135,6 +135,24 @@ bool AddressSpaceAttr::isValidPtrIntCast( return false; } +//===----------------------------------------------------------------------===// +// FunctionMetadataAttr +//===----------------------------------------------------------------------===// + +LogicalResult +FunctionMetadataAttr::verify(function_ref 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 47e63e2aa279..01c96ded535b 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -2063,6 +2063,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 bde7807dadb8..28d6405582fb 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@+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@+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@+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@+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@+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 d1766052964b..7a1c4ee95143 100644 --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -1244,3 +1244,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">>> + ] +}