[Mlir-commits] [mlir] [mlir][Printer] Honor --mlir-elide-resource-strings-if-larger when serializing of large blobs (PR #213920)

Natanael Cintean llvmlistbot at llvm.org
Wed Aug 5 06:07:27 PDT 2026


https://github.com/natanael-cintean updated https://github.com/llvm/llvm-project/pull/213920

>From 280ee792819534778f6fb8cb171b8c0f063d65f6 Mon Sep 17 00:00:00 2001
From: Natanael Cintean <natanael.cintean at intel.com>
Date: Tue, 4 Aug 2026 10:54:41 +0000
Subject: [PATCH 1/2] Add size check and skip serialization of large blobs.

---
 mlir/lib/IR/AsmPrinter.cpp               | 58 +++++++++++++++------
 mlir/test/IR/pretty-resources-print.mlir | 64 +++++++++++++++++++++++-
 2 files changed, 105 insertions(+), 17 deletions(-)

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: {

>From b6bf0cc3f730e3181a66ce7f4f3c8b1ef2f934f8 Mon Sep 17 00:00:00 2001
From: Natanael Cintean <natanael.cintean at intel.com>
Date: Wed, 5 Aug 2026 13:06:19 +0000
Subject: [PATCH 2/2] Remove debug print and testcase based on it as it's not
 needed.

---
 mlir/lib/IR/AsmPrinter.cpp               |  6 +-----
 mlir/test/IR/pretty-resources-print.mlir | 10 ----------
 2 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index 74b5c85a020cb..248d2943b9514 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -3589,12 +3589,8 @@ void OperationPrinter::printResourceFileMetadata(
 
         // 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");
+        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 bd3b271ca7500..a2733d13cebe8 100644
--- a/mlir/test/IR/pretty-resources-print.mlir
+++ b/mlir/test/IR/pretty-resources-print.mlir
@@ -1,4 +1,3 @@
-// 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
@@ -10,12 +9,6 @@
 // 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>
@@ -35,9 +28,6 @@
 // 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: {



More information about the Mlir-commits mailing list