[Mlir-commits] [mlir] [MLIR][LLVM] Add CG Profile module flags support (PR #137115)
Bruno Cardoso Lopes
llvmlistbot at llvm.org
Wed Apr 23 21:23:24 PDT 2025
https://github.com/bcardosolopes created https://github.com/llvm/llvm-project/pull/137115
Dialect only accept arbitrary module flag values in face of simple types like int and string. Whenever metadata is a bit more complex use specific attributes to map functionality. This PR adds an attribute to represent "CG Profile" entries, verifiers, import / translate support.
>From 4a00d2a8deab67c07f7e0eb61e9e639662a0e724 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Wed, 23 Apr 2025 18:12:24 -0700
Subject: [PATCH] [MLIR][LLVM] Add CG Profile module flags support
---
.../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 39 +++++++++++++++---
mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp | 20 ++++++++--
.../LLVMIR/LLVMToLLVMIRTranslation.cpp | 30 ++++++++++++++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 40 ++++++++++++++++++-
mlir/test/Dialect/LLVMIR/invalid.mlir | 16 ++++++++
.../test/Dialect/LLVMIR/module-roundtrip.mlir | 14 ++++++-
.../test/Target/LLVMIR/Import/module-flags.ll | 19 +++++++++
mlir/test/Target/LLVMIR/llvmir.mlir | 21 ++++++++++
8 files changed, 186 insertions(+), 13 deletions(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index f53f95ee9ba49..cfa6ebf3e6775 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1322,7 +1322,7 @@ def LLVM_DereferenceableAttr : LLVM_Attr<"Dereferenceable", "dereferenceable"> {
}
//===----------------------------------------------------------------------===//
-// ModuleFlagAttr
+// ModuleFlagAttr & related
//===----------------------------------------------------------------------===//
def ModuleFlagAttr
@@ -1332,14 +1332,22 @@ def ModuleFlagAttr
Represents a single entry of llvm.module.flags metadata
(llvm::Module::ModuleFlagEntry in LLVM). The first element is a behavior
flag described by `ModFlagBehaviorAttr`, the second is a string ID
- and third is the value of the flag. Current supported types of values:
- - Integer constants
- - Strings
+ and third is the value of the flag. Supported keys and values include:
+ - Arbitrary `key`s holding integer constants or strings.
+ - Domain specific keys (e.g "CG Profile"), holding lists of supported
+ module flag values (e.g. `llvm.cgprofile_entry`).
Example:
```mlir
- #llvm.mlir.module_flag<error, "wchar_size", 4>
- #llvm.mlir.module_flag<error, "probe-stack", "inline-asm">
+ llvm.module_flags [
+ #llvm.mlir.module_flag<error, "wchar_size", 4>,
+ #llvm.mlir.module_flag<error, "probe-stack", "inline-asm">,
+ #llvm.mlir.module_flag<append, "CG Profile", [
+ #llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
+ #llvm.cgprofile_entry<from = @from, to = @from, count = 222>,
+ #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
+ ]
+ >]
```
}];
let parameters = (ins "ModFlagBehavior":$behavior,
@@ -1349,6 +1357,25 @@ def ModuleFlagAttr
let genVerifyDecl = 1;
}
+def ModuleFlagCGProfileEntryAttr
+ : LLVM_Attr<"ModuleFlagCGProfileEntry", "cgprofile_entry"> {
+ let summary = "CG profile module flag entry";
+ let description = [{
+ Describes a single entry for a CG profile module flag. Example:
+ ```mlir
+ llvm.module_flags [
+ #llvm.mlir.module_flag<append, "CG Profile",
+ [#llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
+ ...
+ ]>]
+ ```
+ }];
+ let parameters = (ins "FlatSymbolRefAttr":$from,
+ "FlatSymbolRefAttr":$to,
+ "uint64_t":$count);
+ let assemblyFormat = "`<` struct(params) `>`";
+}
+
//===----------------------------------------------------------------------===//
// LLVM_DependentLibrariesAttr
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index f3ebb8a565ea4..353108e95c8e2 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -380,8 +380,20 @@ LogicalResult
ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
LLVM::ModFlagBehavior flagBehavior, StringAttr key,
Attribute value) {
- if (!isa<IntegerAttr, StringAttr>(value))
- return emitError()
- << "only integer and string values are currently supported";
- return success();
+ if (key == "CG Profile") {
+ auto arrayAttr = dyn_cast<ArrayAttr>(value);
+ if ((!arrayAttr) || (!llvm::all_of(arrayAttr, [](Attribute v) {
+ return isa<ModuleFlagCGProfileEntryAttr>(v);
+ })))
+ return emitError()
+ << "'CG Profile' key expects an array of '#llvm.cgprofile_entry'";
+ return success();
+ }
+
+ if (isa<IntegerAttr, StringAttr>(value))
+ return success();
+
+ return emitError() << "only integer and string values are currently "
+ "supported for unknown key '"
+ << key << "'";
}
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index e816a3e218452..634d052e0d221 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -271,6 +271,31 @@ static void convertLinkerOptionsOp(ArrayAttr options,
linkerMDNode->addOperand(listMDNode);
}
+static llvm::Metadata *
+convertModuleFlagValue(StringRef key, ArrayAttr arrayAttr,
+ llvm::IRBuilderBase &builder,
+ LLVM::ModuleTranslation &moduleTranslation) {
+ llvm::LLVMContext &context = builder.getContext();
+ llvm::MDBuilder mdb(context);
+ SmallVector<llvm::Metadata *> nodes;
+
+ if (key == "CG Profile") {
+ for (auto entry : arrayAttr.getAsRange<ModuleFlagCGProfileEntryAttr>()) {
+ llvm::Function *fromFn =
+ moduleTranslation.lookupFunction(entry.getFrom().getValue());
+ llvm::Function *toFn =
+ moduleTranslation.lookupFunction(entry.getTo().getValue());
+ llvm::Metadata *vals[] = {
+ llvm::ValueAsMetadata::get(fromFn), llvm::ValueAsMetadata::get(toFn),
+ mdb.createConstant(llvm::ConstantInt::get(
+ llvm::Type::getInt64Ty(context), entry.getCount()))};
+ nodes.push_back(llvm::MDNode::get(context, vals));
+ }
+ return llvm::MDTuple::getDistinct(context, nodes);
+ }
+ return nullptr;
+}
+
static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
@@ -286,6 +311,11 @@ static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
llvm::Type::getInt32Ty(builder.getContext()),
intAttr.getInt()));
})
+ .Case<ArrayAttr>([&](auto arrayAttr) {
+ return convertModuleFlagValue(flagAttr.getKey().getValue(),
+ arrayAttr, builder,
+ moduleTranslation);
+ })
.Default([](auto) { return nullptr; });
assert(valueMetadata && "expected valid metadata");
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 3f80002c15ebb..5171e19d80d9b 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -519,6 +519,39 @@ void ModuleImport::addDebugIntrinsic(llvm::CallInst *intrinsic) {
debugIntrinsics.insert(intrinsic);
}
+static Attribute convertCGProfileModuleFlagValue(ModuleOp mlirModule,
+ llvm::MDTuple *mdTuple) {
+ auto getFunctionSymbol = [&](const llvm::MDOperand &funcMDO) {
+ auto *f = cast<llvm::ValueAsMetadata>(funcMDO);
+ auto *llvmFn = cast<llvm::Function>(f->getValue()->stripPointerCasts());
+ return FlatSymbolRefAttr::get(mlirModule->getContext(), llvmFn->getName());
+ };
+
+ // Each tuple element becomes one ModuleFlagCGProfileEntryAttr.
+ SmallVector<Attribute> cgProfile;
+ for (unsigned i = 0; i < mdTuple->getNumOperands(); i++) {
+ const llvm::MDOperand &mdo = mdTuple->getOperand(i);
+ auto *cgEntry = dyn_cast_or_null<llvm::MDNode>(mdo);
+ llvm::Constant *llvmConstant =
+ cast<llvm::ConstantAsMetadata>(cgEntry->getOperand(2))->getValue();
+ uint64_t count = cast<llvm::ConstantInt>(llvmConstant)->getZExtValue();
+ cgProfile.push_back(ModuleFlagCGProfileEntryAttr::get(
+ mlirModule->getContext(), getFunctionSymbol(cgEntry->getOperand(0)),
+ getFunctionSymbol(cgEntry->getOperand(1)), count));
+ }
+ return ArrayAttr::get(mlirModule->getContext(), cgProfile);
+}
+
+// Invoke specific handlers for each known module flag value, returns nullptr if
+// the key is unknown or unimplemented.
+static Attribute convertModuleFlagValueFromMDTuple(ModuleOp mlirModule,
+ StringRef key,
+ llvm::MDTuple *mdTuple) {
+ if (key == "CG Profile")
+ return convertCGProfileModuleFlagValue(mlirModule, mdTuple);
+ return nullptr;
+}
+
LogicalResult ModuleImport::convertModuleFlagsMetadata() {
SmallVector<llvm::Module::ModuleFlagEntry> llvmModuleFlags;
llvmModule->getModuleFlagsMetadata(llvmModuleFlags);
@@ -530,7 +563,12 @@ LogicalResult ModuleImport::convertModuleFlagsMetadata() {
valAttr = builder.getI32IntegerAttr(constInt->getZExtValue());
} else if (auto *mdString = dyn_cast<llvm::MDString>(val)) {
valAttr = builder.getStringAttr(mdString->getString());
- } else {
+ } else if (auto *mdTuple = dyn_cast<llvm::MDTuple>(val)) {
+ valAttr = convertModuleFlagValueFromMDTuple(mlirModule, key->getString(),
+ mdTuple);
+ }
+
+ if (!valAttr) {
emitWarning(mlirModule.getLoc())
<< "unsupported module flag value: " << diagMD(val, llvmModule.get());
continue;
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index a3cd9572933ae..e8902c4ccd5af 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1784,6 +1784,22 @@ module {
// -----
+module {
+ // expected-error at below {{'CG Profile' key expects an array of '#llvm.cgprofile_entry'}}
+ llvm.module_flags [#llvm.mlir.module_flag<append, "CG Profile", [
+ "yo"
+ ]>]
+}
+
+// -----
+
+module {
+ // expected-error at below {{'CG Profile' key expects an array of '#llvm.cgprofile_entry'}}
+ llvm.module_flags [#llvm.mlir.module_flag<append, "CG Profile", 3 : i64>]
+}
+
+// -----
+
llvm.func @t0() -> !llvm.ptr {
%0 = llvm.blockaddress <function = @t0, tag = <id = 1>> : !llvm.ptr
llvm.blocktag <id = 1>
diff --git a/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
index a94514da9818f..508f560ff69f0 100644
--- a/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
@@ -6,7 +6,12 @@ module {
#llvm.mlir.module_flag<max, "PIE Level", 2 : i32>,
#llvm.mlir.module_flag<max, "uwtable", 2 : i32>,
#llvm.mlir.module_flag<max, "frame-pointer", 1 : i32>,
- #llvm.mlir.module_flag<override, "probe-stack", "inline-asm">]
+ #llvm.mlir.module_flag<override, "probe-stack", "inline-asm">,
+ #llvm.mlir.module_flag<append, "CG Profile", [
+ #llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
+ #llvm.cgprofile_entry<from = @from, to = @from, count = 222>,
+ #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
+ ]>]
}
// CHECK: llvm.module_flags [
@@ -15,4 +20,9 @@ module {
// CHECK-SAME: #llvm.mlir.module_flag<max, "PIE Level", 2 : i32>,
// CHECK-SAME: #llvm.mlir.module_flag<max, "uwtable", 2 : i32>,
// CHECK-SAME: #llvm.mlir.module_flag<max, "frame-pointer", 1 : i32>,
-// CHECK-SAME: #llvm.mlir.module_flag<override, "probe-stack", "inline-asm">]
+// CHECK-SAME: #llvm.mlir.module_flag<override, "probe-stack", "inline-asm">,
+// CHECK-SAME: #llvm.mlir.module_flag<append, "CG Profile", [
+// CHECK-SAME: #llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
+// CHECK-SAME: #llvm.cgprofile_entry<from = @from, to = @from, count = 222>,
+// CHECK-SAME: #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
+// CHECK-SAME: ]>]
diff --git a/mlir/test/Target/LLVMIR/Import/module-flags.ll b/mlir/test/Target/LLVMIR/Import/module-flags.ll
index e6bb2c0ffb32d..31ab8afb7ed83 100644
--- a/mlir/test/Target/LLVMIR/Import/module-flags.ll
+++ b/mlir/test/Target/LLVMIR/Import/module-flags.ll
@@ -25,3 +25,22 @@
!12 = !{ i32 2, !"qux", i32 42 }
!13 = !{ i32 3, !"qux", !{ !"foo", i32 1 }}
!llvm.module.flags = !{ !10, !11, !12, !13 }
+
+; // -----
+
+declare void @from(i32)
+declare void @to()
+
+!llvm.module.flags = !{!20}
+
+!20 = !{i32 5, !"CG Profile", !21}
+!21 = distinct !{!22, !23, !24}
+!22 = !{ptr @from, ptr @to, i64 222}
+!23 = !{ptr @from, ptr @from, i64 222}
+!24 = !{ptr @to, ptr @from, i64 222}
+
+; CHECK: llvm.module_flags [#llvm.mlir.module_flag<append, "CG Profile", [
+; CHECK-SAME: #llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
+; CHECK-SAME: #llvm.cgprofile_entry<from = @from, to = @from, count = 222>,
+; CHECK-SAME: #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
+; CHECK-SAME: ]>]
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 74fa327809864..0675531eadbb7 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2838,6 +2838,27 @@ module {
// -----
+module {
+ llvm.module_flags [#llvm.mlir.module_flag<append, "CG Profile", [
+ #llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
+ #llvm.cgprofile_entry<from = @from, to = @from, count = 222>,
+ #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
+ ]>]
+ llvm.func @from(i32)
+ llvm.func @to()
+}
+
+// CHECK: !llvm.module.flags = !{![[#CGPROF:]], ![[#DBG:]]}
+
+// CHECK: ![[#CGPROF]] = !{i32 5, !"CG Profile", ![[#LIST:]]}
+// CHECK: ![[#LIST]] = distinct !{![[#ENTRY_A:]], ![[#ENTRY_B:]], ![[#ENTRY_C:]]}
+// CHECK: ![[#ENTRY_A]] = !{ptr @from, ptr @to, i64 222}
+// CHECK: ![[#ENTRY_B]] = !{ptr @from, ptr @from, i64 222}
+// CHECK: ![[#ENTRY_C]] = !{ptr @to, ptr @from, i64 222}
+// CHECK: ![[#DBG]] = !{i32 2, !"Debug Info Version", i32 3}
+
+// -----
+
module attributes {llvm.dependent_libraries = ["foo", "bar"]} {}
// CHECK: !llvm.dependent-libraries = !{![[#LIBFOO:]], ![[#LIBBAR:]]}
More information about the Mlir-commits
mailing list