[Mlir-commits] [mlir] 28934fe - [MLIR][LLVM] Add ProfileSummary module flag support (#138070)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon May 5 13:54:29 PDT 2025
Author: Bruno Cardoso Lopes
Date: 2025-05-05T13:54:25-07:00
New Revision: 28934fe4cf95512537a61d0f75a7155724050cdb
URL: https://github.com/llvm/llvm-project/commit/28934fe4cf95512537a61d0f75a7155724050cdb
DIFF: https://github.com/llvm/llvm-project/commit/28934fe4cf95512537a61d0f75a7155724050cdb.diff
LOG: [MLIR][LLVM] Add ProfileSummary module flag support (#138070)
Add one more of these module flags.
Unlike "CG Profile", LLVM proper does not verify the content of the
metadata, but returns a nullptr in case it's ill-formed (it's up to the
user to take action). This prompted me to implement warning checks,
preventing the importer to consume broken data.
Added:
Modified:
mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
mlir/lib/Target/LLVMIR/ModuleImport.cpp
mlir/test/Dialect/LLVMIR/invalid.mlir
mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
mlir/test/Target/LLVMIR/Import/import-failure.ll
mlir/test/Target/LLVMIR/Import/module-flags.ll
mlir/test/Target/LLVMIR/llvmir.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 7d6d38ecad897..ade2b64c108ff 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1378,6 +1378,54 @@ def ModuleFlagCGProfileEntryAttr
let assemblyFormat = "`<` struct(params) `>`";
}
+def ModuleFlagProfileSummaryDetailedAttr
+ : LLVM_Attr<"ModuleFlagProfileSummaryDetailed", "profile_summary_detailed"> {
+ let summary = "ProfileSummary detailed information";
+ let description = [{
+ Contains detailed information pertinent to "ProfileSummary" attribute.
+ A `#llvm.profile_summary` may contain several of it.
+ ```mlir
+ llvm.module_flags [ ...
+ detailed_summary =
+ <cut_off = 10000, min_count = 86427, num_counts = 1>,
+ <cut_off = 100000, min_count = 86427, num_counts = 1>
+ ```
+ }];
+ let parameters = (ins "uint32_t":$cut_off,
+ "uint64_t":$min_count,
+ "uint32_t":$num_counts);
+ let assemblyFormat = "`<` struct(params) `>`";
+}
+
+def ModuleFlagProfileSummaryAttr
+ : LLVM_Attr<"ModuleFlagProfileSummary", "profile_summary"> {
+ let summary = "ProfileSummary module flag";
+ let description = [{
+ Describes ProfileSummary gathered data in a module. Example:
+ ```mlir
+ llvm.module_flags [#llvm.mlir.module_flag<error, "ProfileSummary",
+ #llvm.profile_summary<format = InstrProf, total_count = 263646, max_count = 86427,
+ max_internal_count = 86427, max_function_count = 4691,
+ num_counts = 3712, num_functions = 796,
+ is_partial_profile = 0,
+ partial_profile_ratio = 0.000000e+00 : f64,
+ detailed_summary =
+ <cut_off = 10000, min_count = 86427, num_counts = 1>,
+ <cut_off = 100000, min_count = 86427, num_counts = 1>
+ >>]
+ ```
+ }];
+ let parameters = (ins "ProfileSummaryFormatKind":$format,
+ "uint64_t":$total_count, "uint64_t":$max_count,
+ "uint64_t":$max_internal_count, "uint64_t":$max_function_count,
+ "uint64_t":$num_counts, "uint64_t":$num_functions,
+ OptionalParameter<"std::optional<uint64_t>">:$is_partial_profile,
+ OptionalParameter<"FloatAttr">:$partial_profile_ratio,
+ ArrayRefParameter<"ModuleFlagProfileSummaryDetailedAttr">:$detailed_summary);
+
+ let assemblyFormat = "`<` struct(params) `>`";
+}
+
//===----------------------------------------------------------------------===//
// LLVM_DependentLibrariesAttr
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
index 9f9d075a3eebf..b5ea8fc5da500 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
@@ -92,6 +92,9 @@ def LLVM_Dialect : Dialect {
static StringRef getModuleFlagKeyCGProfileName() {
return "CG Profile";
}
+ static StringRef getModuleFlagKeyProfileSummaryName() {
+ return "ProfileSummary";
+ }
/// Returns `true` if the given type is compatible with the LLVM dialect.
static bool isCompatibleType(Type);
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
index 596f562911f8f..b1799a9bccc17 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
@@ -826,7 +826,7 @@ def FPExceptionBehaviorAttr : LLVM_EnumAttr<
}
//===----------------------------------------------------------------------===//
-// Module Flag Behavior
+// Module Flags
//===----------------------------------------------------------------------===//
// These values must match llvm::Module::ModFlagBehavior ones.
@@ -858,6 +858,21 @@ def ModFlagBehaviorAttr : LLVM_EnumAttr<
let cppNamespace = "::mlir::LLVM";
}
+def LLVM_ProfileSummaryFormatSampleProfile : I64EnumAttrCase<"SampleProfile",
+ 0>;
+def LLVM_ProfileSummaryFormatInstrProf : I64EnumAttrCase<"InstrProf", 1>;
+def LLVM_ProfileSummaryFormatCSInstrProf : I64EnumAttrCase<"CSInstrProf", 2>;
+
+def LLVM_ProfileSummaryFormatKind : I64EnumAttr<
+ "ProfileSummaryFormatKind",
+ "LLVM ProfileSummary format kinds", [
+ LLVM_ProfileSummaryFormatSampleProfile,
+ LLVM_ProfileSummaryFormatInstrProf,
+ LLVM_ProfileSummaryFormatCSInstrProf,
+ ]> {
+ let cppNamespace = "::mlir::LLVM";
+}
+
//===----------------------------------------------------------------------===//
// UWTableKind
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 7dccd9d29ecbd..915954a7f5f51 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -390,6 +390,13 @@ ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return success();
}
+ if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName()) {
+ if (!isa<ModuleFlagProfileSummaryAttr>(value))
+ return emitError() << "'ProfileSummary' key expects a "
+ "'#llvm.profile_summary' attribute";
+ return success();
+ }
+
if (isa<IntegerAttr, StringAttr>(value))
return success();
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 35dcde2a33d41..4ea313019f34d 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -303,6 +303,69 @@ convertModuleFlagValue(StringRef key, ArrayAttr arrayAttr,
return nullptr;
}
+static llvm::Metadata *convertModuleFlagProfileSummaryAttr(
+ StringRef key, ModuleFlagProfileSummaryAttr summaryAttr,
+ llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation) {
+ llvm::LLVMContext &context = builder.getContext();
+ llvm::MDBuilder mdb(context);
+ SmallVector<llvm::Metadata *> summaryNodes;
+
+ auto getIntTuple = [&](StringRef key, uint64_t val) -> llvm::MDTuple * {
+ SmallVector<llvm::Metadata *> tupleNodes{
+ mdb.createString(key), mdb.createConstant(llvm::ConstantInt::get(
+ llvm::Type::getInt64Ty(context), val))};
+ return llvm::MDTuple::get(context, tupleNodes);
+ };
+
+ SmallVector<llvm::Metadata *> fmtNode{
+ mdb.createString("ProfileFormat"),
+ mdb.createString(
+ stringifyProfileSummaryFormatKind(summaryAttr.getFormat()))};
+
+ SmallVector<llvm::Metadata *> vals = {
+ llvm::MDTuple::get(context, fmtNode),
+ getIntTuple("TotalCount", summaryAttr.getTotalCount()),
+ getIntTuple("MaxCount", summaryAttr.getMaxCount()),
+ getIntTuple("MaxInternalCount", summaryAttr.getMaxInternalCount()),
+ getIntTuple("MaxFunctionCount", summaryAttr.getMaxFunctionCount()),
+ getIntTuple("NumCounts", summaryAttr.getNumCounts()),
+ getIntTuple("NumFunctions", summaryAttr.getNumFunctions()),
+ };
+
+ if (summaryAttr.getIsPartialProfile())
+ vals.push_back(
+ getIntTuple("IsPartialProfile", *summaryAttr.getIsPartialProfile()));
+
+ if (summaryAttr.getPartialProfileRatio()) {
+ SmallVector<llvm::Metadata *> tupleNodes{
+ mdb.createString("PartialProfileRatio"),
+ mdb.createConstant(llvm::ConstantFP::get(
+ llvm::Type::getDoubleTy(context),
+ summaryAttr.getPartialProfileRatio().getValue()))};
+ vals.push_back(llvm::MDTuple::get(context, tupleNodes));
+ }
+
+ SmallVector<llvm::Metadata *> detailedEntries;
+ llvm::Type *llvmInt64Type = llvm::Type::getInt64Ty(context);
+ for (ModuleFlagProfileSummaryDetailedAttr detailedEntry :
+ summaryAttr.getDetailedSummary()) {
+ SmallVector<llvm::Metadata *> tupleNodes{
+ mdb.createConstant(
+ llvm::ConstantInt::get(llvmInt64Type, detailedEntry.getCutOff())),
+ mdb.createConstant(
+ llvm::ConstantInt::get(llvmInt64Type, detailedEntry.getMinCount())),
+ mdb.createConstant(llvm::ConstantInt::get(
+ llvmInt64Type, detailedEntry.getNumCounts()))};
+ detailedEntries.push_back(llvm::MDTuple::get(context, tupleNodes));
+ }
+ SmallVector<llvm::Metadata *> detailedSummary{
+ mdb.createString("DetailedSummary"),
+ llvm::MDTuple::get(context, detailedEntries)};
+ vals.push_back(llvm::MDTuple::get(context, detailedSummary));
+
+ return llvm::MDNode::get(context, vals);
+}
+
static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
@@ -323,6 +386,11 @@ static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
arrayAttr, builder,
moduleTranslation);
})
+ .Case([&](ModuleFlagProfileSummaryAttr summaryAttr) {
+ return convertModuleFlagProfileSummaryAttr(
+ flagAttr.getKey().getValue(), summaryAttr, 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 0b77a3d23d392..6f56a17ecd4e3 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -41,6 +41,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Operator.h"
#include "llvm/Support/ModRef.h"
+#include <optional>
using namespace mlir;
using namespace mlir::LLVM;
@@ -554,13 +555,284 @@ static Attribute convertCGProfileModuleFlagValue(ModuleOp mlirModule,
return ArrayAttr::get(mlirModule->getContext(), cgProfile);
}
+/// Extract a two element `MDTuple` from a `MDOperand`. Emit a warning in case
+/// something else is found.
+static llvm::MDTuple *getTwoElementMDTuple(ModuleOp mlirModule,
+ const llvm::Module *llvmModule,
+ const llvm::MDOperand &md) {
+ auto *tupleEntry = dyn_cast_or_null<llvm::MDTuple>(md);
+ if (!tupleEntry || tupleEntry->getNumOperands() != 2)
+ emitWarning(mlirModule.getLoc())
+ << "expected 2-element tuple metadata: " << diagMD(md, llvmModule);
+ return tupleEntry;
+}
+
+/// Extract a constant metadata value from a two element tuple (<key, value>).
+/// Return nullptr if requirements are not met. A warning is emitted if the
+/// `matchKey` is
diff erent from the tuple's key.
+static llvm::ConstantAsMetadata *getConstantMDFromKeyValueTuple(
+ ModuleOp mlirModule, const llvm::Module *llvmModule,
+ const llvm::MDOperand &md, StringRef matchKey, bool optional = false) {
+ llvm::MDTuple *tupleEntry = getTwoElementMDTuple(mlirModule, llvmModule, md);
+ if (!tupleEntry)
+ return nullptr;
+ auto *keyMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(0));
+ if (!keyMD || keyMD->getString() != matchKey) {
+ if (!optional)
+ emitWarning(mlirModule.getLoc())
+ << "expected '" << matchKey << "' key, but found: "
+ << diagMD(tupleEntry->getOperand(0), llvmModule);
+ return nullptr;
+ }
+
+ return dyn_cast<llvm::ConstantAsMetadata>(tupleEntry->getOperand(1));
+}
+
+/// Extract an integer value from a two element tuple (<key, value>).
+/// Fail if requirements are not met. A warning is emitted if the
+/// found value isn't a LLVM constant integer.
+static FailureOr<uint64_t>
+convertInt64FromKeyValueTuple(ModuleOp mlirModule,
+ const llvm::Module *llvmModule,
+ const llvm::MDOperand &md, StringRef matchKey) {
+ llvm::ConstantAsMetadata *valMD =
+ getConstantMDFromKeyValueTuple(mlirModule, llvmModule, md, matchKey);
+ if (!valMD)
+ return failure();
+
+ if (auto *cstInt = dyn_cast<llvm::ConstantInt>(valMD->getValue()))
+ return cstInt->getZExtValue();
+
+ emitWarning(mlirModule.getLoc())
+ << "expected integer metadata value for key '" << matchKey
+ << "': " << diagMD(md, llvmModule);
+ return failure();
+}
+
+static std::optional<ProfileSummaryFormatKind>
+convertProfileSummaryFormat(ModuleOp mlirModule, const llvm::Module *llvmModule,
+ const llvm::MDOperand &formatMD) {
+ auto *tupleEntry = getTwoElementMDTuple(mlirModule, llvmModule, formatMD);
+ if (!tupleEntry)
+ return std::nullopt;
+
+ llvm::MDString *keyMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(0));
+ if (!keyMD || keyMD->getString() != "ProfileFormat") {
+ emitWarning(mlirModule.getLoc())
+ << "expected 'ProfileFormat' key: "
+ << diagMD(tupleEntry->getOperand(0), llvmModule);
+ return std::nullopt;
+ }
+
+ llvm::MDString *valMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(1));
+ std::optional<ProfileSummaryFormatKind> fmtKind =
+ symbolizeProfileSummaryFormatKind(valMD->getString());
+ if (!fmtKind) {
+ emitWarning(mlirModule.getLoc())
+ << "expected 'SampleProfile', 'InstrProf' or 'CSInstrProf' values, "
+ "but found: "
+ << diagMD(valMD, llvmModule);
+ return std::nullopt;
+ }
+
+ return fmtKind;
+}
+
+static FailureOr<SmallVector<ModuleFlagProfileSummaryDetailedAttr>>
+convertProfileSummaryDetailed(ModuleOp mlirModule,
+ const llvm::Module *llvmModule,
+ const llvm::MDOperand &summaryMD) {
+ auto *tupleEntry = getTwoElementMDTuple(mlirModule, llvmModule, summaryMD);
+ if (!tupleEntry)
+ return failure();
+
+ llvm::MDString *keyMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(0));
+ if (!keyMD || keyMD->getString() != "DetailedSummary") {
+ emitWarning(mlirModule.getLoc())
+ << "expected 'DetailedSummary' key: "
+ << diagMD(tupleEntry->getOperand(0), llvmModule);
+ return failure();
+ }
+
+ llvm::MDTuple *entriesMD = dyn_cast<llvm::MDTuple>(tupleEntry->getOperand(1));
+ if (!entriesMD) {
+ emitWarning(mlirModule.getLoc())
+ << "expected tuple value for 'DetailedSummary' key: "
+ << diagMD(tupleEntry->getOperand(1), llvmModule);
+ return failure();
+ }
+
+ SmallVector<ModuleFlagProfileSummaryDetailedAttr> detailedSummary;
+ for (auto &&entry : entriesMD->operands()) {
+ llvm::MDTuple *entryMD = dyn_cast<llvm::MDTuple>(entry);
+ if (!entryMD || entryMD->getNumOperands() != 3) {
+ emitWarning(mlirModule.getLoc())
+ << "'DetailedSummary' entry expects 3 operands: "
+ << diagMD(entry, llvmModule);
+ return failure();
+ }
+
+ auto *op0 = dyn_cast<llvm::ConstantAsMetadata>(entryMD->getOperand(0));
+ auto *op1 = dyn_cast<llvm::ConstantAsMetadata>(entryMD->getOperand(1));
+ auto *op2 = dyn_cast<llvm::ConstantAsMetadata>(entryMD->getOperand(2));
+ if (!op0 || !op1 || !op2) {
+ emitWarning(mlirModule.getLoc())
+ << "expected only integer entries in 'DetailedSummary': "
+ << diagMD(entry, llvmModule);
+ return failure();
+ }
+
+ auto detaildSummaryEntry = ModuleFlagProfileSummaryDetailedAttr::get(
+ mlirModule->getContext(),
+ cast<llvm::ConstantInt>(op0->getValue())->getZExtValue(),
+ cast<llvm::ConstantInt>(op1->getValue())->getZExtValue(),
+ cast<llvm::ConstantInt>(op2->getValue())->getZExtValue());
+ detailedSummary.push_back(detaildSummaryEntry);
+ }
+ return detailedSummary;
+}
+
+static Attribute
+convertProfileSummaryModuleFlagValue(ModuleOp mlirModule,
+ const llvm::Module *llvmModule,
+ llvm::MDTuple *mdTuple) {
+ unsigned profileNumEntries = mdTuple->getNumOperands();
+ if (profileNumEntries < 8) {
+ emitWarning(mlirModule.getLoc())
+ << "expected at 8 entries in 'ProfileSummary': "
+ << diagMD(mdTuple, llvmModule);
+ return nullptr;
+ }
+
+ unsigned summayIdx = 0;
+ auto checkOptionalPosition = [&](const llvm::MDOperand &md,
+ StringRef matchKey) -> LogicalResult {
+ // Make sure we won't step over the bound of the array of summary entries.
+ // Since (non-optional) DetailedSummary always comes last, the next entry in
+ // the tuple operand array must exist.
+ if (summayIdx + 1 >= profileNumEntries) {
+ emitWarning(mlirModule.getLoc())
+ << "the last summary entry is '" << matchKey
+ << "', expected 'DetailedSummary': " << diagMD(md, llvmModule);
+ return failure();
+ }
+
+ return success();
+ };
+
+ auto getOptIntValue =
+ [&](const llvm::MDOperand &md,
+ StringRef matchKey) -> FailureOr<std::optional<uint64_t>> {
+ if (!getConstantMDFromKeyValueTuple(mlirModule, llvmModule, md, matchKey,
+ /*optional=*/true))
+ return FailureOr<std::optional<uint64_t>>(std::nullopt);
+ if (checkOptionalPosition(md, matchKey).failed())
+ return failure();
+ FailureOr<uint64_t> val =
+ convertInt64FromKeyValueTuple(mlirModule, llvmModule, md, matchKey);
+ if (failed(val))
+ return failure();
+ return val;
+ };
+
+ auto getOptDoubleValue = [&](const llvm::MDOperand &md,
+ StringRef matchKey) -> FailureOr<FloatAttr> {
+ auto *valMD = getConstantMDFromKeyValueTuple(mlirModule, llvmModule, md,
+ matchKey, /*optional=*/true);
+ if (!valMD)
+ return FloatAttr{};
+ if (auto *cstFP = dyn_cast<llvm::ConstantFP>(valMD->getValue())) {
+ if (checkOptionalPosition(md, matchKey).failed())
+ return failure();
+ return FloatAttr::get(Float64Type::get(mlirModule.getContext()),
+ cstFP->getValueAPF());
+ }
+ emitWarning(mlirModule.getLoc())
+ << "expected double metadata value for key '" << matchKey
+ << "': " << diagMD(md, llvmModule);
+ return failure();
+ };
+
+ // Build ModuleFlagProfileSummaryAttr by sequentially fetching elements in
+ // a fixed order: format, total count, etc.
+ SmallVector<Attribute> profileSummary;
+ std::optional<ProfileSummaryFormatKind> format = convertProfileSummaryFormat(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++));
+ if (!format.has_value())
+ return nullptr;
+
+ FailureOr<uint64_t> totalCount = convertInt64FromKeyValueTuple(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "TotalCount");
+ if (failed(totalCount))
+ return nullptr;
+
+ FailureOr<uint64_t> maxCount = convertInt64FromKeyValueTuple(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "MaxCount");
+ if (failed(maxCount))
+ return nullptr;
+
+ FailureOr<uint64_t> maxInternalCount = convertInt64FromKeyValueTuple(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++),
+ "MaxInternalCount");
+ if (failed(maxInternalCount))
+ return nullptr;
+
+ FailureOr<uint64_t> maxFunctionCount = convertInt64FromKeyValueTuple(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++),
+ "MaxFunctionCount");
+ if (failed(maxFunctionCount))
+ return nullptr;
+
+ FailureOr<uint64_t> numCounts = convertInt64FromKeyValueTuple(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "NumCounts");
+ if (failed(numCounts))
+ return nullptr;
+
+ FailureOr<uint64_t> numFunctions = convertInt64FromKeyValueTuple(
+ mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "NumFunctions");
+ if (failed(numFunctions))
+ return nullptr;
+
+ // Handle optional keys.
+ FailureOr<std::optional<uint64_t>> isPartialProfile =
+ getOptIntValue(mdTuple->getOperand(summayIdx), "IsPartialProfile");
+ if (failed(isPartialProfile))
+ return nullptr;
+ if (isPartialProfile->has_value())
+ summayIdx++;
+
+ FailureOr<FloatAttr> partialProfileRatio =
+ getOptDoubleValue(mdTuple->getOperand(summayIdx), "PartialProfileRatio");
+ if (failed(partialProfileRatio))
+ return nullptr;
+ if (*partialProfileRatio)
+ summayIdx++;
+
+ // Handle detailed summary.
+ FailureOr<SmallVector<ModuleFlagProfileSummaryDetailedAttr>> detailed =
+ convertProfileSummaryDetailed(mlirModule, llvmModule,
+ mdTuple->getOperand(summayIdx));
+ if (failed(detailed))
+ return nullptr;
+
+ // Build the final profile summary attribute.
+ return ModuleFlagProfileSummaryAttr::get(
+ mlirModule->getContext(), *format, *totalCount, *maxCount,
+ *maxInternalCount, *maxFunctionCount, *numCounts, *numFunctions,
+ *isPartialProfile, *partialProfileRatio, *detailed);
+}
+
/// 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) {
+static Attribute
+convertModuleFlagValueFromMDTuple(ModuleOp mlirModule,
+ const llvm::Module *llvmModule, StringRef key,
+ llvm::MDTuple *mdTuple) {
if (key == LLVMDialect::getModuleFlagKeyCGProfileName())
return convertCGProfileModuleFlagValue(mlirModule, mdTuple);
+ if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName())
+ return convertProfileSummaryModuleFlagValue(mlirModule, llvmModule,
+ mdTuple);
return nullptr;
}
@@ -576,8 +848,8 @@ LogicalResult ModuleImport::convertModuleFlagsMetadata() {
} else if (auto *mdString = dyn_cast<llvm::MDString>(val)) {
valAttr = builder.getStringAttr(mdString->getString());
} else if (auto *mdTuple = dyn_cast<llvm::MDTuple>(val)) {
- valAttr = convertModuleFlagValueFromMDTuple(mlirModule, key->getString(),
- mdTuple);
+ valAttr = convertModuleFlagValueFromMDTuple(mlirModule, llvmModule.get(),
+ key->getString(), mdTuple);
}
if (!valAttr) {
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 5dea94026b248..f9ea066a63624 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1800,6 +1800,29 @@ module {
// -----
+module {
+ // expected-error at below {{'ProfileSummary' key expects a '#llvm.profile_summary' attribute}}
+ llvm.module_flags [#llvm.mlir.module_flag<append, "ProfileSummary", 3 : i64>]
+}
+
+// -----
+
+llvm.module_flags [#llvm.mlir.module_flag<error, "ProfileSummary",
+ // expected-error at below {{expected one of [SampleProfile, InstrProf, CSInstrProf] for LLVM ProfileSummary format kinds, got: YoloFmt}}
+ #llvm.profile_summary<format = "YoloFmt", total_count = 263646, max_count = 86427,
+ // expected-error at above {{failed to parse ModuleFlagProfileSummaryAttr parameter 'format' which is to be a `ProfileSummaryFormatKind`}}
+ max_internal_count = 86427, max_function_count = 4691,
+ num_counts = 3712, num_functions = 796,
+ is_partial_profile = 0,
+ partial_profile_ratio = 0.000000e+00 : f64,
+ detailed_summary =
+ <cut_off = 10000, min_count = 86427, num_counts = 1>,
+ <cut_off = 100000, min_count = 86427, num_counts = 1>
+ // expected-error at below {{failed to parse ModuleFlagAttr parameter}}
+>>]
+
+// -----
+
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 025d9b2287c42..85abd57df53c8 100644
--- a/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
@@ -11,7 +11,17 @@ module {
#llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
#llvm.cgprofile_entry<from = @from, count = 222>,
#llvm.cgprofile_entry<from = @to, to = @from, count = 222>
- ]>]
+ ]>,
+ #llvm.mlir.module_flag<error, "ProfileSummary",
+ #llvm.profile_summary<format = InstrProf, total_count = 263646, max_count = 86427,
+ max_internal_count = 86427, max_function_count = 4691,
+ num_counts = 3712, num_functions = 796,
+ is_partial_profile = 0,
+ partial_profile_ratio = 0.000000e+00 : f64,
+ detailed_summary =
+ <cut_off = 10000, min_count = 86427, num_counts = 1>,
+ <cut_off = 100000, min_count = 86427, num_counts = 1>
+ >>]
}
// CHECK: llvm.module_flags [
@@ -25,4 +35,14 @@ module {
// CHECK-SAME: #llvm.cgprofile_entry<from = @from, to = @to, count = 222>,
// CHECK-SAME: #llvm.cgprofile_entry<from = @from, count = 222>,
// CHECK-SAME: #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
-// CHECK-SAME: ]>]
+// CHECK-SAME: ]>,
+// CHECK-SAME: #llvm.mlir.module_flag<error, "ProfileSummary",
+// CHECK-SAME: #llvm.profile_summary<format = InstrProf, total_count = 263646, max_count = 86427,
+// CHECK-SAME: max_internal_count = 86427, max_function_count = 4691,
+// CHECK-SAME: num_counts = 3712, num_functions = 796,
+// CHECK-SAME: is_partial_profile = 0,
+// CHECK-SAME: partial_profile_ratio = 0.000000e+00 : f64,
+// CHECK-SAME: detailed_summary =
+// CHECK-SAME: <cut_off = 10000, min_count = 86427, num_counts = 1>,
+// CHECK-SAME: <cut_off = 100000, min_count = 86427, num_counts = 1>
+// CHECK-SAME: >>]
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 782925a0a938e..7571158a57d14 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -348,3 +348,127 @@ define void @fn() {
bb1:
ret void
}
+
+; // -----
+
+!10 = !{ i32 1, !"foo", i32 1 }
+!11 = !{ i32 4, !"bar", i32 37 }
+!12 = !{ i32 2, !"qux", i32 42 }
+; CHECK: unsupported module flag value for key 'qux' : !4 = !{!"foo", i32 1}
+!13 = !{ i32 3, !"qux", !{ !"foo", i32 1 }}
+!llvm.module.flags = !{ !10, !11, !12, !13 }
+
+; // -----
+
+!llvm.module.flags = !{!41873}
+
+!41873 = !{i32 1, !"ProfileSummary", !41874}
+!41874 = !{!41875, !41876, !41877, !41878, !41880, !41881, !41882, !41883, !41884}
+!41875 = !{!"ProfileFormat", !"InstrProf"}
+!41876 = !{!"TotalCount", i64 263646}
+!41877 = !{!"MaxCount", i64 86427}
+!41878 = !{!"MaxInternalCount", i64 86427}
+; CHECK: expected 'MaxFunctionCount' key, but found: !"NumCounts"
+!41880 = !{!"NumCounts", i64 3712}
+!41881 = !{!"NumFunctions", i64 796}
+!41882 = !{!"IsPartialProfile", i64 0}
+!41883 = !{!"PartialProfileRatio", double 0.000000e+00}
+!41884 = !{!"DetailedSummary", !41885}
+!41885 = !{!41886, !41887}
+!41886 = !{i32 10000, i64 86427, i32 1}
+!41887 = !{i32 100000, i64 86427, i32 1}
+
+; // -----
+
+!llvm.module.flags = !{!51873}
+
+!51873 = !{i32 1, !"ProfileSummary", !51874}
+!51874 = !{!51875, !51876, !51877, !51878, !51879, !51880, !51881, !51882, !51883, !51884}
+!51875 = !{!"ProfileFormat", !"InstrProf"}
+!51876 = !{!"TotalCount", i64 263646}
+!51877 = !{!"MaxCount", i64 86427}
+!51878 = !{!"MaxInternalCount", i64 86427}
+!51879 = !{!"MaxFunctionCount", i64 4691}
+!51880 = !{!"NumCounts", i64 3712}
+; CHECK: expected integer metadata value for key 'NumFunctions'
+!51881 = !{!"NumFunctions", double 0.000000e+00}
+!51882 = !{!"IsPartialProfile", i64 0}
+!51883 = !{!"PartialProfileRatio", double 0.000000e+00}
+!51884 = !{!"DetailedSummary", !51885}
+!51885 = !{!51886, !51887}
+!51886 = !{i32 10000, i64 86427, i32 1}
+!51887 = !{i32 100000, i64 86427, i32 1}
+
+; // -----
+
+!llvm.module.flags = !{!61873}
+
+!61873 = !{i32 1, !"ProfileSummary", !61874}
+!61874 = !{!61875, !61876, !61877, !61878, !61879, !61880, !61881, !61882, !61883, !61884}
+; CHECK: expected 'SampleProfile', 'InstrProf' or 'CSInstrProf' values, but found: !"MyThingyFmt"
+!61875 = !{!"ProfileFormat", !"MyThingyFmt"}
+!61876 = !{!"TotalCount", i64 263646}
+!61877 = !{!"MaxCount", i64 86427}
+!61878 = !{!"MaxInternalCount", i64 86427}
+!61879 = !{!"MaxFunctionCount", i64 4691}
+!61880 = !{!"NumCounts", i64 3712}
+!61881 = !{!"NumFunctions", i64 796}
+!61882 = !{!"IsPartialProfile", i64 0}
+!61883 = !{!"PartialProfileRatio", double 0.000000e+00}
+!61884 = !{!"DetailedSummary", !61885}
+!61885 = !{!61886, !61887}
+!61886 = !{i32 10000, i64 86427, i32 1}
+!61887 = !{i32 100000, i64 86427, i32 1}
+
+; // -----
+
+!llvm.module.flags = !{!71873}
+
+!71873 = !{i32 1, !"ProfileSummary", !71874}
+!71874 = !{!71875, !71876, !71877, !71878, !71879, !71880, !71881, !71882, !71883}
+!71875 = !{!"ProfileFormat", !"InstrProf"}
+!71876 = !{!"TotalCount", i64 263646}
+!71877 = !{!"MaxCount", i64 86427}
+!71878 = !{!"MaxInternalCount", i64 86427}
+!71879 = !{!"MaxFunctionCount", i64 4691}
+!71880 = !{!"NumCounts", i64 3712}
+!71881 = !{!"NumFunctions", i64 796}
+!71882 = !{!"IsPartialProfile", i64 0}
+; CHECK: the last summary entry is 'PartialProfileRatio', expected 'DetailedSummary'
+!71883 = !{!"PartialProfileRatio", double 0.000000e+00}
+
+; // -----
+
+!llvm.module.flags = !{!81873}
+
+!81873 = !{i32 1, !"ProfileSummary", !81874}
+; CHECK: expected at 8 entries in 'ProfileSummary'
+!81874 = !{!81875, !81876, !81877, !81878, !81879, !81880, !81881}
+!81875 = !{!"ProfileFormat", !"InstrProf"}
+!81876 = !{!"TotalCount", i64 263646}
+!81877 = !{!"MaxCount", i64 86427}
+!81878 = !{!"MaxInternalCount", i64 86427}
+!81879 = !{!"MaxFunctionCount", i64 4691}
+!81880 = !{!"NumCounts", i64 3812}
+!81881 = !{!"NumFunctions", i64 796}
+
+; // -----
+
+!llvm.module.flags = !{!91873}
+
+!91873 = !{i32 1, !"ProfileSummary", !91874}
+!91874 = !{!91875, !91876, !91877, !91878, !91879, !91880, !91881, !91882, !91883, !91884}
+!91875 = !{!"ProfileFormat", !"InstrProf"}
+; CHECK: expected 2-element tuple metadata
+!91876 = !{!"TotalCount", i64 263646, i64 263646}
+!91877 = !{!"MaxCount", i64 86427}
+!91878 = !{!"MaxInternalCount", i64 86427}
+!91879 = !{!"MaxFunctionCount", i64 4691}
+!91880 = !{!"NumCounts", i64 3712}
+!91881 = !{!"NumFunctions", i64 796}
+!91882 = !{!"IsPartialProfile", i64 0}
+!91883 = !{!"PartialProfileRatio", double 0.000000e+00}
+!91884 = !{!"DetailedSummary", !91885}
+!91885 = !{!91886, !91887}
+!91886 = !{i32 10000, i64 86427, i32 1}
+!91887 = !{i32 100000, i64 86427, i32 1}
diff --git a/mlir/test/Target/LLVMIR/Import/module-flags.ll b/mlir/test/Target/LLVMIR/Import/module-flags.ll
index 09e708de0cc93..725bd14deb651 100644
--- a/mlir/test/Target/LLVMIR/Import/module-flags.ll
+++ b/mlir/test/Target/LLVMIR/Import/module-flags.ll
@@ -18,14 +18,6 @@
; CHECK-SAME: #llvm.mlir.module_flag<max, "frame-pointer", 1 : i32>,
; CHECK-SAME: #llvm.mlir.module_flag<override, "probe-stack", "inline-asm">]
-; // -----
-; expected-warning at -2 {{unsupported module flag value for key 'qux' : !4 = !{!"foo", i32 1}}}
-!10 = !{ i32 1, !"foo", i32 1 }
-!11 = !{ i32 4, !"bar", i32 37 }
-!12 = !{ i32 2, !"qux", i32 42 }
-!13 = !{ i32 3, !"qux", !{ !"foo", i32 1 }}
-!llvm.module.flags = !{ !10, !11, !12, !13 }
-
; // -----
declare void @from(i32)
@@ -44,3 +36,62 @@ declare void @to()
; CHECK-SAME: #llvm.cgprofile_entry<from = @from, count = 222>,
; CHECK-SAME: #llvm.cgprofile_entry<from = @to, to = @from, count = 222>
; CHECK-SAME: ]>]
+
+; // -----
+
+!llvm.module.flags = !{!31873}
+
+!31873 = !{i32 1, !"ProfileSummary", !31874}
+!31874 = !{!31875, !31876, !31877, !31878, !31879, !31880, !31881, !31882, !31883, !31884}
+!31875 = !{!"ProfileFormat", !"InstrProf"}
+!31876 = !{!"TotalCount", i64 263646}
+!31877 = !{!"MaxCount", i64 86427}
+!31878 = !{!"MaxInternalCount", i64 86427}
+!31879 = !{!"MaxFunctionCount", i64 4691}
+!31880 = !{!"NumCounts", i64 3712}
+!31881 = !{!"NumFunctions", i64 796}
+!31882 = !{!"IsPartialProfile", i64 0}
+!31883 = !{!"PartialProfileRatio", double 0.000000e+00}
+!31884 = !{!"DetailedSummary", !31885}
+!31885 = !{!31886, !31887}
+!31886 = !{i32 10000, i64 86427, i32 1}
+!31887 = !{i32 100000, i64 86427, i32 1}
+
+; CHECK: llvm.module_flags [#llvm.mlir.module_flag<error, "ProfileSummary",
+; CHECK-SAME: #llvm.profile_summary<format = InstrProf, total_count = 263646,
+; CHECK-SAME: max_count = 86427, max_internal_count = 86427, max_function_count = 4691,
+; CHECK-SAME: num_counts = 3712, num_functions = 796, is_partial_profile = 0,
+; CHECK-SAME: partial_profile_ratio = 0.000000e+00 : f64,
+; CHECK-SAME: detailed_summary =
+; CHECK-SAME: <cut_off = 10000, min_count = 86427, num_counts = 1>,
+; CHECK-SAME: <cut_off = 100000, min_count = 86427, num_counts = 1>
+; CHECK-SAME: >>]
+
+; // -----
+
+; Test optional fields
+
+!llvm.module.flags = !{!41873}
+
+!41873 = !{i32 1, !"ProfileSummary", !41874}
+!41874 = !{!41875, !41876, !41877, !41878, !41879, !41880, !41881, !41884}
+!41875 = !{!"ProfileFormat", !"InstrProf"}
+!41876 = !{!"TotalCount", i64 263646}
+!41877 = !{!"MaxCount", i64 86427}
+!41878 = !{!"MaxInternalCount", i64 86427}
+!41879 = !{!"MaxFunctionCount", i64 4691}
+!41880 = !{!"NumCounts", i64 3712}
+!41881 = !{!"NumFunctions", i64 796}
+!41884 = !{!"DetailedSummary", !41885}
+!41885 = !{!41886, !41887}
+!41886 = !{i32 10000, i64 86427, i32 1}
+!41887 = !{i32 100000, i64 86427, i32 1}
+
+; CHECK: llvm.module_flags [#llvm.mlir.module_flag<error, "ProfileSummary",
+; CHECK-SAME: #llvm.profile_summary<format = InstrProf, total_count = 263646,
+; CHECK-SAME: max_count = 86427, max_internal_count = 86427, max_function_count = 4691,
+; CHECK-SAME: num_counts = 3712, num_functions = 796,
+; CHECK-SAME: detailed_summary =
+; CHECK-SAME: <cut_off = 10000, min_count = 86427, num_counts = 1>,
+; CHECK-SAME: <cut_off = 100000, min_count = 86427, num_counts = 1>
+; CHECK-SAME: >>]
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index f60fc1a5ed55e..4ef68fa83a70d 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2891,6 +2891,37 @@ llvm.func @to()
// -----
+llvm.module_flags [#llvm.mlir.module_flag<error, "ProfileSummary",
+ #llvm.profile_summary<format = InstrProf, total_count = 263646, max_count = 86427,
+ max_internal_count = 86427, max_function_count = 4691,
+ num_counts = 3712, num_functions = 796,
+ is_partial_profile = 0,
+ partial_profile_ratio = 0.000000e+00 : f64,
+ detailed_summary =
+ <cut_off = 10000, min_count = 86427, num_counts = 1>,
+ <cut_off = 100000, min_count = 86427, num_counts = 1>
+ >>]
+
+// CHECK: !llvm.module.flags = !{![[#PSUM:]], {{.*}}}
+
+// CHECK: ![[#PSUM]] = !{i32 1, !"ProfileSummary", ![[#SUMLIST:]]}
+// CHECK: ![[#SUMLIST]] = !{![[#FMT:]], ![[#TC:]], ![[#MC:]], ![[#MIC:]], ![[#MFC:]], ![[#NC:]], ![[#NF:]], ![[#IPP:]], ![[#PPR:]], ![[#DS:]]}
+// CHECK: ![[#FMT]] = !{!"ProfileFormat", !"InstrProf"}
+// CHECK: ![[#TC]] = !{!"TotalCount", i64 263646}
+// CHECK: ![[#MC]] = !{!"MaxCount", i64 86427}
+// CHECK: ![[#MIC]] = !{!"MaxInternalCount", i64 86427}
+// CHECK: ![[#MFC]] = !{!"MaxFunctionCount", i64 4691}
+// CHECK: ![[#NC]] = !{!"NumCounts", i64 3712}
+// CHECK: ![[#NF]] = !{!"NumFunctions", i64 796}
+// CHECK: ![[#IPP]] = !{!"IsPartialProfile", i64 0}
+// CHECK: ![[#PPR]] = !{!"PartialProfileRatio", double 0.000000e+00}
+// CHECK: ![[#DS]] = !{!"DetailedSummary", ![[#DETAILED:]]}
+// CHECK: ![[#DETAILED]] = !{![[#DS0:]], ![[#DS1:]]}
+// CHECK: ![[#DS0:]] = !{i64 10000, i64 86427, i64 1}
+// CHECK: ![[#DS1:]] = !{i64 100000, i64 86427, i64 1}
+
+// -----
+
module attributes {llvm.dependent_libraries = ["foo", "bar"]} {}
// CHECK: !llvm.dependent-libraries = !{![[#LIBFOO:]], ![[#LIBBAR:]]}
More information about the Mlir-commits
mailing list