[Mlir-commits] [mlir] [mlir]Add size check and skip serialization of large blobs. (PR #213920)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Aug 4 05:14:07 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Natanael Cintean (natanael-cintean)
<details>
<summary>Changes</summary>
Used AI for code changes and description. Reviewed and tested locally.
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.
Added boundary tests to pretty-resources-print.mlir (limit == size vs limit == size - 1) verifying the exact > cutoff behavior is preserved.
Added LLVM_DEBUG-based checks (--debug-only=mlir-asm-printer) confirming the new fast path actually fires (skips encoding) rather than just relying on output equivalence with the old fallback path.
Solves issue:
https://github.com/llvm/llvm-project/issues/213921
---
Full diff: https://github.com/llvm/llvm-project/pull/213920.diff
2 Files Affected:
- (modified) mlir/lib/IR/AsmPrinter.cpp (+42-16)
- (modified) mlir/test/IR/pretty-resources-print.mlir (+63-1)
``````````diff
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index b95ab00bd5fdd..74b5c85a020cb 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -3467,33 +3467,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:
@@ -3558,7 +3574,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;
@@ -3570,6 +3587,15 @@ 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()) {
+ LLVM_DEBUG(llvm::dbgs() << "eliding resource '" << key
+ << "' without materializing (sizeHint="
+ << sizeHint << ")\n");
+ 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..bd3b271ca7500 100644
--- a/mlir/test/IR/pretty-resources-print.mlir
+++ b/mlir/test/IR/pretty-resources-print.mlir
@@ -1,20 +1,49 @@
+// REQUIRES: asserts
// Check printing with --mlir-elide-resource-strings-if-larger elides printing large resources
// RUN: mlir-opt %s --mlir-elide-resource-strings-if-larger=20| FileCheck %s
// 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
+
+// These directly verify the sizeHint fast path itself (not just the resulting output) by
+// checking for its debug log: it must fire when blob3 is elided but not when it is printed.
+// RUN: mlir-opt %s --mlir-elide-resource-strings-if-larger=13 --debug-only=mlir-asm-printer 2>&1 | FileCheck %s --check-prefix=DEBUG-ELIDE
+// RUN: mlir-opt %s --mlir-elide-resource-strings-if-larger=14 --debug-only=mlir-asm-printer 2>&1 | FileCheck %s --check-prefix=DEBUG-PRINT
+
// 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> } : () -> ()
+
+// DEBUG-ELIDE: eliding resource 'blob3' without materializing (sizeHint=14)
+// DEBUG-PRINT-NOT: eliding resource 'blob3' without materializing
+
// 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 +60,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: {
``````````
</details>
https://github.com/llvm/llvm-project/pull/213920
More information about the Mlir-commits
mailing list