[Mlir-commits] [mlir] 6d28f51 - [mlir][Printer] Optimize --mlir-elide-resource-strings-if-larger when serializing of large blobs (#213920)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Aug 20 02:21:31 PDT 2026
Author: Natanael Cintean
Date: 2026-08-20T11:21:25+02:00
New Revision: 6d28f51e2416e1007a406225050a406dc21679e3
URL: https://github.com/llvm/llvm-project/commit/6d28f51e2416e1007a406225050a406dc21679e3
DIFF: https://github.com/llvm/llvm-project/commit/6d28f51e2416e1007a406225050a406dc21679e3.diff
LOG: [mlir][Printer] Optimize --mlir-elide-resource-strings-if-larger when serializing of large blobs (#213920)
OperationPrinter::printResourceFileMetadata elides resource entries
larger than --mlir-elide-resource-strings-if-larger (charLimit), but
always materializes the full serialized string first (e.g. hex-encoding
the entire blob) and only checks the length afterward, discarding the
string if it's too long. For large dialect/external resource blobs, this
wastes significant time and memory hex-encoding data that is guaranteed
to be elided.
The time and memory consumption is especially noticeable when printing
the IR for a large number of passes.
Extend ResourceBuilder::PrintFn to accept an additional sizeHint — the
exact number of characters the value will serialize to when known ahead
of time (currently computed for buildBlob's hex-encoded output; -1 for
buildBool/buildString where it's cheap to compute directly).
printResourceFileMetadata then skips calling the serialization callback
entirely when sizeHint already exceeds charLimit, avoiding the wasted
encoding work while preserving identical printed output.
Used AI for code changes and description. Reviewed and tested locally.
Fixes #213921
Added:
Modified:
mlir/lib/IR/AsmPrinter.cpp
mlir/test/IR/pretty-resources-print.mlir
Removed:
################################################################################
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index c94cf8f77bf6b..47a33a116f92c 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -3470,33 +3470,49 @@ class OperationPrinter : public AsmPrinter::Impl, private OpAsmPrinter {
class ResourceBuilder : public AsmResourceBuilder {
public:
using ValueFn = function_ref<void(raw_ostream &)>;
- using PrintFn = function_ref<void(StringRef, ValueFn)>;
+ // `sizeHint` is the exact number of characters `valueFn` will write, or -1
+ // if unknown, so the char limit can be applied before paying the cost of
+ // invoking `valueFn` (e.g. hex-encoding a large blob).
+ using PrintFn = function_ref<void(StringRef, ValueFn, int64_t sizeHint)>;
ResourceBuilder(PrintFn printFn) : printFn(printFn) {}
~ResourceBuilder() override = default;
void buildBool(StringRef key, bool data) final {
- printFn(key, [&](raw_ostream &os) { os << (data ? "true" : "false"); });
+ printFn(
+ key, [&](raw_ostream &os) { os << (data ? "true" : "false"); },
+ /*sizeHint=*/-1);
}
void buildString(StringRef key, StringRef data) final {
- printFn(key, [&](raw_ostream &os) {
- os << "\"";
- llvm::printEscapedString(data, os);
- os << "\"";
- });
+ printFn(
+ key,
+ [&](raw_ostream &os) {
+ os << "\"";
+ llvm::printEscapedString(data, os);
+ os << "\"";
+ },
+ /*sizeHint=*/-1);
}
void buildBlob(StringRef key, ArrayRef<char> data,
uint32_t dataAlignment) final {
- printFn(key, [&](raw_ostream &os) {
- // Store the blob in a hex string containing the alignment and the data.
- llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
- os << "\"0x"
- << llvm::toHex(StringRef(reinterpret_cast<char *>(&dataAlignmentLE),
- sizeof(dataAlignment)))
- << llvm::toHex(StringRef(data.data(), data.size())) << "\"";
- });
+ // Two hex chars per byte of the alignment word and the data, plus the
+ // `"0x`/`"` wrapping; exact, so the limit can be checked pre-encoding.
+ int64_t sizeHint = 2 * int64_t(sizeof(dataAlignment) + data.size()) + 4;
+ printFn(
+ key,
+ [&](raw_ostream &os) {
+ // Store the blob in a hex string containing the alignment and the
+ // data.
+ llvm::support::ulittle32_t dataAlignmentLE(dataAlignment);
+ os << "\"0x"
+ << llvm::toHex(
+ StringRef(reinterpret_cast<char *>(&dataAlignmentLE),
+ sizeof(dataAlignment)))
+ << llvm::toHex(StringRef(data.data(), data.size())) << "\"";
+ },
+ sizeHint);
}
private:
@@ -3561,7 +3577,8 @@ void OperationPrinter::printResourceFileMetadata(
auto processProvider = [&](StringRef dictName, StringRef name, auto &provider,
auto &&...providerArgs) {
bool hadEntry = false;
- auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn) {
+ auto printFn = [&](StringRef key, ResourceBuilder::ValueFn valueFn,
+ int64_t sizeHint) {
checkAddMetadataDict();
std::string resourceStr;
@@ -3573,6 +3590,11 @@ void OperationPrinter::printResourceFileMetadata(
if (charLimit.value() == 0)
return;
+ // Skip serializing entirely if the exact size already exceeds the
+ // limit, e.g. hex-encoding a large blob.
+ if (sizeHint >= 0 && uint64_t(sizeHint) > charLimit.value())
+ return;
+
llvm::raw_string_ostream ss(resourceStr);
valueFn(ss);
diff --git a/mlir/test/IR/pretty-resources-print.mlir b/mlir/test/IR/pretty-resources-print.mlir
index 980af80343d47..a2733d13cebe8 100644
--- a/mlir/test/IR/pretty-resources-print.mlir
+++ b/mlir/test/IR/pretty-resources-print.mlir
@@ -4,17 +4,36 @@
// RUN: mlir-opt %s --mlir-elide-resource-strings-if-larger=0| FileCheck %s --check-prefix=ZERO
+// blob3's exact serialized size (quotes + "0x" + hex(alignment) + hex(data)) is 14 chars;
+// these two RUN lines check the off-by-one boundary of the sizeHint-based elision.
+// RUN: mlir-opt %s --mlir-elide-resource-strings-if-larger=14| FileCheck %s --check-prefix=BOUND14
+// RUN: mlir-opt %s --mlir-elide-resource-strings-if-larger=13| FileCheck %s --check-prefix=BOUND13
// To ensure we print the resource keys, have reference to them
// CHECK: attr = dense_resource<blob1> : tensor<3xi64>
// ZERO: attr = dense_resource<blob1> : tensor<3xi64>
+// BOUND14: attr = dense_resource<blob1> : tensor<3xi64>
+// BOUND13: attr = dense_resource<blob1> : tensor<3xi64>
"test.blob1op"() {attr = dense_resource<blob1> : tensor<3xi64> } : () -> ()
// CHECK-NEXT: attr = dense_resource<blob2> : tensor<3xi64>
// ZERO-NEXT: attr = dense_resource<blob2> : tensor<3xi64>
+// BOUND14-NEXT: attr = dense_resource<blob2> : tensor<3xi64>
+// BOUND13-NEXT: attr = dense_resource<blob2> : tensor<3xi64>
"test.blob2op"() {attr = dense_resource<blob2> : tensor<3xi64> } : () -> ()
+// CHECK-NEXT: attr = dense_resource<blob3> : tensor<1xi8>
+// ZERO-NEXT: attr = dense_resource<blob3> : tensor<1xi8>
+// BOUND14-NEXT: attr = dense_resource<blob3> : tensor<1xi8>
+// BOUND13-NEXT: attr = dense_resource<blob3> : tensor<1xi8>
+"test.blob3op"() {attr = dense_resource<blob3> : tensor<1xi8> } : () -> ()
+
// CHECK: {-#
+// CHECK-NEXT: dialect_resources: {
+// CHECK-NEXT: builtin: {
+// CHECK-NEXT: blob3: "0x0800000001"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
// CHECK-NEXT: external_resources: {
// CHECK-NEXT: external: {
// CHECK-NEXT: "backslash\\tab\09": true,
@@ -31,11 +50,44 @@
// ZERO-EMPTY:
// ZERO-NEXT: #-}
+// At the exact boundary (limit == blob3's exact size) blob3 must still be printed,
+// since the sizeHint fast-path only elides when size is strictly greater than the limit.
+// BOUND14: {-#
+// BOUND14-NEXT: dialect_resources: {
+// BOUND14-NEXT: builtin: {
+// BOUND14-NEXT: blob3: "0x0800000001"
+// BOUND14-NEXT: }
+// BOUND14-NEXT: },
+// BOUND14-NEXT: external_resources: {
+// BOUND14-NEXT: external: {
+// BOUND14-NEXT: "backslash\\tab\09": true,
+// BOUND14-NEXT: string: "\22string\22"
+// BOUND14-NEXT: },
+// BOUND14-NEXT: other_stuff: {
+// BOUND14-NEXT: bool: true
+// BOUND14-NEXT: }
+// BOUND14-NEXT: }
+// BOUND14-NEXT: #-}
+
+// One below the boundary, blob3 is elided and no dialect_resources dict is emitted.
+// Note: the escaped `string` entry is also exactly 14 chars, so it is elided here too.
+// BOUND13: {-#
+// BOUND13-NEXT: external_resources: {
+// BOUND13-NEXT: external: {
+// BOUND13-NEXT: "backslash\\tab\09": true
+// BOUND13-NEXT: },
+// BOUND13-NEXT: other_stuff: {
+// BOUND13-NEXT: bool: true
+// BOUND13-NEXT: }
+// BOUND13-NEXT: }
+// BOUND13-NEXT: #-}
+
{-#
dialect_resources: {
builtin: {
blob1: "0x08000000010000000000000002000000000000000300000000000000",
- blob2: "0x08000000040000000000000005000000000000000600000000000000"
+ blob2: "0x08000000040000000000000005000000000000000600000000000000",
+ blob3: "0x0800000001"
}
},
external_resources: {
More information about the Mlir-commits
mailing list