-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[MLIR][LLVM] Add CG Profile module flags support #137115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MLIR][LLVM] Add CG Profile module flags support #137115
Conversation
@llvm/pr-subscribers-mlir @llvm/pr-subscribers-mlir-llvm Author: Bruno Cardoso Lopes (bcardosolopes) ChangesDialect 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. Full diff: https://github.com/llvm/llvm-project/pull/137115.diff 8 Files Affected:
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@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@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:]]}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, LGTM modulo some nits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM % some additional nits.
mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
Outdated
Show resolved
Hide resolved
All comments addressed, thanks folks! |
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.
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.
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.
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.
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.