[llvm] [mlir] [mlir][bytecode] Add builtin dialect version (PR #184678)

Jacques Pienaar via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 5 00:44:13 PST 2026


https://github.com/jpienaar updated https://github.com/llvm/llvm-project/pull/184678

>From 4de19167e7717b39cb5d7bd7dded1adb1b4137e3 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <jacques+gh at japienaar.info>
Date: Wed, 4 Mar 2026 14:34:09 +0000
Subject: [PATCH 1/2] [mlir][bytecode] Add builtin dialect version

This adds a singular Builtin dialect version for use with bytecode
serialization. This version is not currently print unless set and not 0
(not planned a bump until next LLVM version). Created a unit test as
this was easiest way to track.

Additionally add emitWarning virtual method to DialectBytecodeReader,
mirroring emitError.
---
 .../mlir/Bytecode/BytecodeImplementation.h    |  3 +
 mlir/include/mlir/IR/BuiltinDialect.h         | 20 +++++++
 mlir/include/mlir/IR/BuiltinDialect.td        |  5 +-
 mlir/lib/Bytecode/Reader/BytecodeReader.cpp   | 11 ++++
 mlir/lib/IR/BuiltinDialectBytecode.cpp        | 35 ++++++++++++
 .../IR/BuiltinDialectVersionTest.cpp          | 56 +++++++++++++++++++
 mlir/unittests/IR/CMakeLists.txt              |  1 +
 .../mlir/unittests/BUILD.bazel                |  1 +
 8 files changed, 131 insertions(+), 1 deletion(-)
 create mode 100644 mlir/unittests/IR/BuiltinDialectVersionTest.cpp

diff --git a/mlir/include/mlir/Bytecode/BytecodeImplementation.h b/mlir/include/mlir/Bytecode/BytecodeImplementation.h
index 49c5b33bd8290..4a42f0f6c8020 100644
--- a/mlir/include/mlir/Bytecode/BytecodeImplementation.h
+++ b/mlir/include/mlir/Bytecode/BytecodeImplementation.h
@@ -50,6 +50,9 @@ class DialectBytecodeReader {
   /// Emit an error to the reader.
   virtual InFlightDiagnostic emitError(const Twine &msg = {}) const = 0;
 
+  /// Emit a warning to the reader.
+  virtual InFlightDiagnostic emitWarning(const Twine &msg = {}) const = 0;
+
   /// Retrieve the dialect version by name if available.
   virtual FailureOr<const DialectVersion *>
   getDialectVersion(StringRef dialectName) const = 0;
diff --git a/mlir/include/mlir/IR/BuiltinDialect.h b/mlir/include/mlir/IR/BuiltinDialect.h
index 15b98d5112e53..d06b63da6b892 100644
--- a/mlir/include/mlir/IR/BuiltinDialect.h
+++ b/mlir/include/mlir/IR/BuiltinDialect.h
@@ -14,8 +14,28 @@
 #ifndef MLIR_IR_BUILTINDIALECT_H_
 #define MLIR_IR_BUILTINDIALECT_H_
 
+#include "mlir/Bytecode/BytecodeImplementation.h"
 #include "mlir/IR/Dialect.h"
 
+//===----------------------------------------------------------------------===//
+// BuiltinDialectVersion
+//===----------------------------------------------------------------------===//
+
+struct BuiltinDialectVersion : public mlir::DialectVersion {
+  BuiltinDialectVersion(int64_t version) : version(version) {}
+
+  int64_t getVersion() const { return version; }
+
+  static BuiltinDialectVersion getCurrentVersion() { return {0}; }
+
+  bool operator<(const BuiltinDialectVersion &other) const {
+    return version < other.version;
+  }
+
+private:
+  int64_t version;
+};
+
 //===----------------------------------------------------------------------===//
 // Dialect
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/IR/BuiltinDialect.td b/mlir/include/mlir/IR/BuiltinDialect.td
index c131107634b44..c770dd50f3622 100644
--- a/mlir/include/mlir/IR/BuiltinDialect.td
+++ b/mlir/include/mlir/IR/BuiltinDialect.td
@@ -24,6 +24,9 @@ def Builtin_Dialect : Dialect {
   let useDefaultAttributePrinterParser = 0;
   let useDefaultTypePrinterParser = 0;
   let extraClassDeclaration = [{
+    std::optional<BuiltinDialectVersion> getVersion() const { return version; }
+    void setVersion(std::optional<BuiltinDialectVersion> v) { version = v; }
+
   private:
     // Register the builtin Attributes.
     void registerAttributes();
@@ -32,7 +35,7 @@ def Builtin_Dialect : Dialect {
     // Register the builtin Types.
     void registerTypes();
 
-  public:
+    std::optional<BuiltinDialectVersion> version;
   }];
 
 }
diff --git a/mlir/lib/Bytecode/Reader/BytecodeReader.cpp b/mlir/lib/Bytecode/Reader/BytecodeReader.cpp
index c974603bb9235..07a9266dcd1fa 100644
--- a/mlir/lib/Bytecode/Reader/BytecodeReader.cpp
+++ b/mlir/lib/Bytecode/Reader/BytecodeReader.cpp
@@ -144,6 +144,13 @@ class EncodingReader {
   }
   InFlightDiagnostic emitError() const { return ::emitError(fileLoc); }
 
+  /// Emit a warning using the given arguments.
+  template <typename... Args>
+  InFlightDiagnostic emitWarning(Args &&...args) const {
+    return ::emitWarning(fileLoc).append(std::forward<Args>(args)...);
+  }
+  InFlightDiagnostic emitWarning() const { return ::emitWarning(fileLoc); }
+
   /// Parse a single byte from the stream.
   template <typename T>
   LogicalResult parseByte(T &value) {
@@ -1036,6 +1043,10 @@ class DialectReader : public DialectBytecodeReader {
     return reader.emitError(msg);
   }
 
+  InFlightDiagnostic emitWarning(const Twine &msg) const override {
+    return reader.emitWarning(msg);
+  }
+
   FailureOr<const DialectVersion *>
   getDialectVersion(StringRef dialectName) const override {
     // First check if the dialect is available in the map.
diff --git a/mlir/lib/IR/BuiltinDialectBytecode.cpp b/mlir/lib/IR/BuiltinDialectBytecode.cpp
index 8cf25391ba11a..de71e42952b1d 100644
--- a/mlir/lib/IR/BuiltinDialectBytecode.cpp
+++ b/mlir/lib/IR/BuiltinDialectBytecode.cpp
@@ -239,6 +239,41 @@ struct BuiltinDialectBytecodeInterface : public BytecodeDialectInterface {
                           DialectBytecodeWriter &writer) const override {
     return ::writeType(type, writer);
   }
+
+  //===--------------------------------------------------------------------===//
+  // Version
+
+  void writeVersion(DialectBytecodeWriter &writer) const override {
+    auto configVersion = writer.getDialectVersion(getDialect()->getNamespace());
+    // Write version set in config.
+    if (succeeded(configVersion)) {
+      auto *version =
+          static_cast<const BuiltinDialectVersion *>(*configVersion);
+      writer.writeVarInt(static_cast<uint64_t>(version->getVersion()));
+      return;
+    }
+    // Else, write current set version version if not 0.
+    if (auto version = cast<BuiltinDialect>(getDialect())->getVersion();
+        version && version->getVersion() > 0) {
+      writer.writeVarInt(static_cast<uint64_t>(version->getVersion()));
+    }
+  }
+
+  std::unique_ptr<DialectVersion>
+  readVersion(DialectBytecodeReader &reader) const override {
+    uint64_t version;
+    if (failed(reader.readVarInt(version)))
+      return nullptr;
+
+    auto dialectVersion = std::make_unique<BuiltinDialectVersion>(version);
+    if (BuiltinDialectVersion::getCurrentVersion() < *dialectVersion) {
+      reader.emitWarning()
+          << "reading newer builtin dialect version than supported";
+      return nullptr;
+    }
+
+    return dialectVersion;
+  }
 };
 } // namespace
 
diff --git a/mlir/unittests/IR/BuiltinDialectVersionTest.cpp b/mlir/unittests/IR/BuiltinDialectVersionTest.cpp
new file mode 100644
index 0000000000000..3eec05cb36a9b
--- /dev/null
+++ b/mlir/unittests/IR/BuiltinDialectVersionTest.cpp
@@ -0,0 +1,56 @@
+//===- BuiltinDialectVersionTest.cpp - Test builtin dialect versioning ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "mlir/Bytecode/BytecodeWriter.h"
+#include "mlir/IR/BuiltinDialect.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/Parser/Parser.h"
+
+using namespace mlir;
+
+TEST(BuiltinDialectVersionTest, RejectFutureVersion) {
+  MLIRContext ctx;
+  auto module = ModuleOp::create(UnknownLoc::get(&ctx));
+
+  auto writeBytecode = [&](std::string &out,
+                           std::optional<int64_t> version =
+                               std::nullopt) -> LogicalResult {
+    BytecodeWriterConfig config;
+    if (version)
+      config.setDialectVersion<BuiltinDialect>(
+          std::make_unique<BuiltinDialectVersion>(*version));
+    llvm::raw_string_ostream os(out);
+    return writeBytecodeToFile(module, os, config);
+  };
+
+  std::string bytecode;
+  ASSERT_TRUE(succeeded(writeBytecode(bytecode)));
+  std::string bytecodeWithFutureVersion;
+  ASSERT_TRUE(succeeded(writeBytecode(bytecodeWithFutureVersion, 99)));
+
+  EXPECT_NE(bytecode, bytecodeWithFutureVersion);
+
+  std::string warning;
+  ScopedDiagnosticHandler handler(&ctx, [&](Diagnostic &diag) {
+    if (diag.getSeverity() == DiagnosticSeverity::Warning)
+      warning = diag.str();
+    return success();
+  });
+
+  auto parsed =
+      parseSourceString(StringRef(bytecodeWithFutureVersion),
+                        ParserConfig(&ctx, /*verifyAfterParse=*/true));
+  EXPECT_TRUE(warning.find("reading newer builtin dialect version") !=
+              std::string::npos);
+
+  module->erase();
+}
diff --git a/mlir/unittests/IR/CMakeLists.txt b/mlir/unittests/IR/CMakeLists.txt
index dd3b110dcd295..ebc2f6678ae8a 100644
--- a/mlir/unittests/IR/CMakeLists.txt
+++ b/mlir/unittests/IR/CMakeLists.txt
@@ -4,6 +4,7 @@ add_mlir_unittest(MLIRIRTests
   AffineMapTest.cpp
   AttributeTest.cpp
   AttrTypeReplacerTest.cpp
+  BuiltinDialectVersionTest.cpp
   Diagnostic.cpp
   DialectTest.cpp
   DistinctAttributeAllocatorTest.cpp
diff --git a/utils/bazel/llvm-project-overlay/mlir/unittests/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/unittests/BUILD.bazel
index dfb5be5f85027..47c5e4d0ebe20 100644
--- a/utils/bazel/llvm-project-overlay/mlir/unittests/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/unittests/BUILD.bazel
@@ -41,6 +41,7 @@ cc_test(
         "//llvm:Remarks",
         "//llvm:Support",
         "//mlir:BytecodeReader",
+        "//mlir:BytecodeWriter",
         "//mlir:CallOpInterfaces",
         "//mlir:FunctionInterfaces",
         "//mlir:IR",

>From 4d905dad4bd6be1fab53792636be385320be8594 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <jacques+gh at japienaar.info>
Date: Thu, 5 Mar 2026 08:44:00 +0000
Subject: [PATCH 2/2] Fix cmake deps

---
 mlir/unittests/IR/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/mlir/unittests/IR/CMakeLists.txt b/mlir/unittests/IR/CMakeLists.txt
index ebc2f6678ae8a..366e4dac4f7fe 100644
--- a/mlir/unittests/IR/CMakeLists.txt
+++ b/mlir/unittests/IR/CMakeLists.txt
@@ -29,5 +29,6 @@ add_mlir_unittest(MLIRIRTests
 )
 target_include_directories(MLIRIRTests PRIVATE "${MLIR_BINARY_DIR}/test/lib/Dialect/Test")
 mlir_target_link_libraries(MLIRIRTests PRIVATE MLIRIR)
+target_link_libraries(MLIRIRTests PRIVATE MLIRBytecodeWriter)
 target_link_libraries(MLIRIRTests PRIVATE MLIRTestDialect)
 target_link_libraries(MLIRIRTests PRIVATE MLIRRemarkStreamer)



More information about the llvm-commits mailing list