[Mlir-commits] [mlir] 64bccb9 - [mlir][bytecode] Allow selecting dialect versions in mlir-opt (#233149)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Oct 20 01:56:24 PDT 2026


Author: Mehdi Amini
Date: 2026-10-20T10:56:18+02:00
New Revision: 64bccb9d9ac016ec576971b1591fd8e82e7be801

URL: https://github.com/llvm/llvm-project/commit/64bccb9d9ac016ec576971b1591fd8e82e7be801
DIFF: https://github.com/llvm/llvm-project/commit/64bccb9d9ac016ec576971b1591fd8e82e7be801.diff

LOG: [mlir][bytecode] Allow selecting dialect versions in mlir-opt (#233149)

Added: 
    mlir/test/Bytecode/versioning/emit-builtin-version-dlti.mlir
    mlir/test/Bytecode/versioning/emit-dialect-version.mlir
    mlir/test/Bytecode/versioning/emit-test-version-lossy.mlir
    mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_1.mlirbc

Modified: 
    mlir/docs/BytecodeFormat.md
    mlir/include/mlir/Bytecode/BytecodeDialectInterface.td
    mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
    mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
    mlir/lib/IR/BuiltinDialectBytecode.cpp
    mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
    mlir/test/Bytecode/bytecode_downgrade.mlir
    mlir/test/Bytecode/versioning/versioned_op_with_native_properties.mlir
    mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
    mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc
    mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
    mlir/test/lib/Dialect/Test/TestOpDefs.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/docs/BytecodeFormat.md b/mlir/docs/BytecodeFormat.md
index f50ddeb25cc332..27ce718fa3a62a 100644
--- a/mlir/docs/BytecodeFormat.md
+++ b/mlir/docs/BytecodeFormat.md
@@ -21,6 +21,18 @@ upgrades post-parsing through the `upgradeFromVersion` method.
 There is no restriction on what kind of information a dialect
 is allowed to encode to model its versioning.
 
+When emitting bytecode, `mlir-opt --emit-bytecode-version=<version>` selects the
+overall bytecode format version. Dialect versions are selected separately with
+`--emit-bytecode-dialect-version=<dialect>=<version>`, which may be repeated for
+
diff erent dialects. For example, `mlir-opt --emit-bytecode
+--emit-bytecode-dialect-version=builtin=0` selects the historical builtin dialect
+encoding. A dialect must implement `BytecodeDialectInterface::parseVersion` to
+accept a version string; the dialect defines its syntax and supported versions.
+The resulting version object is passed to the bytecode writer through
+`BytecodeWriterConfig::setDialectVersion`. Before emission, the writer invokes
+`BytecodeDialectInterface::verifyVersion` for explicitly selected versions so
+dialects can reject IR that cannot be represented without losing information.
+
 [TOC]
 
 ## Magic Number

diff  --git a/mlir/include/mlir/Bytecode/BytecodeDialectInterface.td b/mlir/include/mlir/Bytecode/BytecodeDialectInterface.td
index f06715e2339604..11d9b4db7cb940 100644
--- a/mlir/include/mlir/Bytecode/BytecodeDialectInterface.td
+++ b/mlir/include/mlir/Bytecode/BytecodeDialectInterface.td
@@ -57,6 +57,27 @@ def BytecodeDialectInterface : DialectInterface<"BytecodeDialectInterface"> {
         return ::llvm::failure();
       }]
     >,
+    InterfaceMethod<[{
+        Parse a target dialect version for bytecode emission from a string, for
+        example from a command-line option. Return null if the version is invalid
+        or unsupported. The dialect defines the syntax of the version string.
+      }],
+      "std::unique_ptr<::mlir::DialectVersion>", "parseVersion",
+      (ins "::llvm::StringRef":$version),
+      [{ return nullptr; }]
+    >,
+    InterfaceMethod<[{
+        Verify that the given operation and its nested IR can be emitted for the
+        requested dialect version without losing information. This hook is
+        invoked before bytecode emission when a target version is explicitly
+        configured. Emit a diagnostic and return failure if the IR cannot be
+        represented in that version.
+      }],
+      "::llvm::LogicalResult", "verifyVersion",
+      (ins "::mlir::Operation *":$topLevelOp,
+           "const ::mlir::DialectVersion &":$version),
+      [{ return ::llvm::success(); }]
+    >,
     InterfaceMethod<[{
         Write the version of this dialect to the given writer.
       }],

diff  --git a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
index 7e0b7024608c91..e6697b376fa005 100644
--- a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
+++ b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
@@ -15,6 +15,7 @@
 
 #include "mlir/Debug/CLOptionsSetup.h"
 #include "mlir/Support/ToolUtilities.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 
 #include <cstdlib>
@@ -128,6 +129,17 @@ class MlirOptMainConfig {
     return emitBytecodeVersion;
   }
 
+  /// Set target dialect versions as strings of the form "dialect=version".
+  /// The dialect defines the syntax of its version string.
+  MlirOptMainConfig &
+  setEmitBytecodeDialectVersions(ArrayRef<std::string> versions) {
+    emitBytecodeDialectVersions.assign(versions.begin(), versions.end());
+    return *this;
+  }
+  ArrayRef<std::string> bytecodeDialectVersionsToEmit() const {
+    return emitBytecodeDialectVersions;
+  }
+
   /// Set the bytecode producer to use.
   MlirOptMainConfig &emitBytecodeProducer(StringRef producer) {
     emitBytecodeProducerFlag = producer.str();
@@ -320,6 +332,9 @@ class MlirOptMainConfig {
   /// Emit bytecode at given version.
   std::optional<int64_t> emitBytecodeVersion = std::nullopt;
 
+  /// Target dialect versions for bytecode emission, as "dialect=version".
+  std::vector<std::string> emitBytecodeDialectVersions;
+
   /// Emit bytecode with given producer.
   std::string emitBytecodeProducerFlag = "";
 

diff  --git a/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp b/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
index 89aa731c5cca05..8cd4658d804765 100644
--- a/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
+++ b/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
@@ -13,6 +13,7 @@
 #include "mlir/Bytecode/Encoding.h"
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/MLIRContext.h"
 #include "mlir/IR/OpImplementation.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/CachedHashString.h"
@@ -1373,6 +1374,16 @@ void BytecodeWriter::writePropertiesSection(EncodingEmitter &emitter) {
 
 LogicalResult mlir::writeBytecodeToFile(Operation *op, raw_ostream &os,
                                         const BytecodeWriterConfig &config) {
+  // Validate before numbering the IR, which may invoke dialect writers.
+  for (const auto &entry : config.getDialectVersionMap()) {
+    Dialect *dialect = op->getContext()->getLoadedDialect(entry.getKey());
+    if (!dialect)
+      continue;
+    auto *interface =
+        dialect->getRegisteredInterface<BytecodeDialectInterface>();
+    if (interface && failed(interface->verifyVersion(op, *entry.getValue())))
+      return failure();
+  }
   BytecodeWriter writer(op, config);
   return writer.write(op, os);
 }

diff  --git a/mlir/lib/IR/BuiltinDialectBytecode.cpp b/mlir/lib/IR/BuiltinDialectBytecode.cpp
index e5476082cd6a04..1390769dd8e6ff 100644
--- a/mlir/lib/IR/BuiltinDialectBytecode.cpp
+++ b/mlir/lib/IR/BuiltinDialectBytecode.cpp
@@ -13,6 +13,7 @@
 #include "mlir/IR/AffineMap.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/BuiltinDialect.h"
+#include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/Diagnostics.h"
 #include "mlir/IR/DialectResourceBlobManager.h"
@@ -578,13 +579,38 @@ struct BuiltinDialectBytecodeInterface : public BytecodeDialectInterface {
   //===--------------------------------------------------------------------===//
   // Version
 
+  std::unique_ptr<DialectVersion>
+  parseVersion(StringRef version) const override {
+    int64_t parsedVersion;
+    if (version.getAsInteger(10, parsedVersion) || parsedVersion < 0 ||
+        parsedVersion > BuiltinDialectVersion::getCurrentVersion().getVersion())
+      return nullptr;
+    return std::make_unique<BuiltinDialectVersion>(parsedVersion);
+  }
+
+  LogicalResult verifyVersion(Operation *topLevelOp,
+                              const DialectVersion &version) const override {
+    if (static_cast<const BuiltinDialectVersion &>(version).getVersion() >= 1)
+      return success();
+    WalkResult result = topLevelOp->walk([](ModuleOp module) {
+      if (!module.getDltiAttr())
+        return WalkResult::advance();
+      module.emitOpError("cannot emit builtin dialect version 0 with a 'dlti' "
+                         "property");
+      return WalkResult::interrupt();
+    });
+    return failure(result.wasInterrupted());
+  }
+
   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()));
+      // Version 0 predates dialect version metadata. Preserve its encoding.
+      if (version->getVersion() > 0)
+        writer.writeVarInt(static_cast<uint64_t>(version->getVersion()));
       return;
     }
     // Else, write current set version version if not 0.

diff  --git a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
index d4812aec50fc19..490e0c20f86f6c 100644
--- a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
+++ b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Tools/mlir-opt/MlirOptMain.h"
+#include "mlir/Bytecode/BytecodeImplementation.h"
 #include "mlir/Bytecode/BytecodeWriter.h"
 #include "mlir/Debug/CLOptionsSetup.h"
 #include "mlir/Debug/Counter.h"
@@ -36,6 +37,7 @@
 #include "mlir/Tools/Plugins/PassPlugin.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Remarks/RemarkFormat.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
@@ -107,6 +109,15 @@ struct MlirOptMainConfigCLOptions : public MlirOptMainConfig {
             cl::desc("Use specified bytecode when generating output"),
             cl::location(emitBytecodeVersion), cl::init(std::nullopt));
 
+    static cl::list<std::string, std::vector<std::string>>
+        bytecodeDialectVersions(
+            "emit-bytecode-dialect-version",
+            cl::desc(
+                "Use the specified dialect version when generating bytecode "
+                "(may be repeated for 
diff erent dialects)"),
+            cl::value_desc("dialect=version"),
+            cl::location(emitBytecodeDialectVersions));
+
     static cl::opt<std::string, /*ExternalStorage=*/true> irdlFile(
         "irdl-file",
         cl::desc("IRDL file to register before processing the input"),
@@ -620,6 +631,30 @@ performActions(raw_ostream &os,
                  : BytecodeWriterConfig(fallbackResourceMap);
     if (auto v = config.bytecodeVersionToEmit())
       writerConfig.setDesiredBytecodeVersion(*v);
+    llvm::StringSet<> versionedDialects;
+    for (StringRef entry : config.bytecodeDialectVersionsToEmit()) {
+      auto [name, version] = entry.split('=');
+      if (name.empty() || version.empty())
+        return op.get()->emitError() << "expected 'dialect=version' for "
+                                        "--emit-bytecode-dialect-version, got '"
+                                     << entry << "'";
+      if (!versionedDialects.insert(name).second)
+        return op.get()->emitError()
+               << "duplicate bytecode version for dialect '" << name << "'";
+      Dialect *dialect = context->getOrLoadDialect(name);
+      if (!dialect)
+        return op.get()->emitError()
+               << "unknown dialect '" << name << "' for bytecode emission";
+      auto *interface =
+          dialect->getRegisteredInterface<BytecodeDialectInterface>();
+      std::unique_ptr<DialectVersion> parsedVersion =
+          interface ? interface->parseVersion(version) : nullptr;
+      if (!parsedVersion)
+        return op.get()->emitError()
+               << "dialect '" << name << "' does not support emitting bytecode "
+               << "version '" << version << "'";
+      writerConfig.setDialectVersion(name, std::move(parsedVersion));
+    }
     if (config.shouldElideResourceDataFromBytecode())
       writerConfig.setElideResourceDataFlag();
     return writeBytecodeToFile(op.get(), os, writerConfig);
@@ -629,6 +664,10 @@ performActions(raw_ostream &os,
     return emitError(UnknownLoc::get(pm.getContext()))
            << "bytecode version while not emitting bytecode";
 
+  if (!config.bytecodeDialectVersionsToEmit().empty())
+    return emitError(UnknownLoc::get(pm.getContext()))
+           << "dialect bytecode version while not emitting bytecode";
+
   // Don't re-run the verifier if we already ran the verifier at the end of the
   // pass pipeline.
   AsmState asmState(op.get(),

diff  --git a/mlir/test/Bytecode/bytecode_downgrade.mlir b/mlir/test/Bytecode/bytecode_downgrade.mlir
index fd98b9d7ee6a58..71decad979f0b4 100644
--- a/mlir/test/Bytecode/bytecode_downgrade.mlir
+++ b/mlir/test/Bytecode/bytecode_downgrade.mlir
@@ -4,7 +4,5 @@ module {
   "test.versionedA"() <{dims = 123 : i64, modifier = false}> : () -> ()
 }
 
-// COM: the property downgrader is executed twice: first for IR numbering and then for emission.
 // CHECK: downgrading op...
-// CHECK: downgrading op properties...
-// CHECK: downgrading op properties...
+// CHECK: "test.versionedA"() <{dims = 123 : i64, modifier = false}>

diff  --git a/mlir/test/Bytecode/versioning/emit-builtin-version-dlti.mlir b/mlir/test/Bytecode/versioning/emit-builtin-version-dlti.mlir
new file mode 100644
index 00000000000000..0c4cc638aafd3c
--- /dev/null
+++ b/mlir/test/Bytecode/versioning/emit-builtin-version-dlti.mlir
@@ -0,0 +1,16 @@
+// RUN: mlir-opt %s -split-input-file -emit-bytecode -emit-bytecode-dialect-version=builtin=0 -verify-diagnostics
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin=1 | mlir-opt | FileCheck %s
+
+// A property introduced in version 1 cannot be silently dropped for version 0.
+// CHECK: module <dlti = #dlti.map<"chip" = "sm_90">>
+// expected-error at +1 {{cannot emit builtin dialect version 0 with a 'dlti' property}}
+module <{dlti = #dlti.map<"chip" = "sm_90">}> {}
+
+// -----
+
+// Also reject DLTI properties on nested modules.
+// CHECK: module @nested <dlti = #dlti.map<"chip" = "sm_90">>
+module {
+  // expected-error at +1 {{cannot emit builtin dialect version 0 with a 'dlti' property}}
+  module @nested <{dlti = #dlti.map<"chip" = "sm_90">}> {}
+}

diff  --git a/mlir/test/Bytecode/versioning/emit-dialect-version.mlir b/mlir/test/Bytecode/versioning/emit-dialect-version.mlir
new file mode 100644
index 00000000000000..ba477ad302d4b5
--- /dev/null
+++ b/mlir/test/Bytecode/versioning/emit-dialect-version.mlir
@@ -0,0 +1,36 @@
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-producer=fixed -emit-bytecode-dialect-version=builtin=0 -emit-bytecode-dialect-version=test=2.0 -o %t.0
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-producer=fixed -emit-bytecode-dialect-version=builtin=1 -emit-bytecode-dialect-version=test=2.0 -o %t.1
+// RUN: not cmp -s %t.0 %t.1
+// RUN: mlir-opt %t.0 | FileCheck %s
+// RUN: mlir-opt %t.1 | FileCheck %s
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-producer=fixed -o %t.default
+// RUN: cmp -s %t.1 %t.default
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-producer=fixed -emit-bytecode-dialect-version=builtin=1 -emit-bytecode-dialect-version=test=1.12 -o %t.old-test
+// RUN: not cmp -s %t.old-test %t.1
+// RUN: mlir-opt %t.old-test | FileCheck %s
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=test=1.12 | mlir-opt | FileCheck %s
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-version=0 -emit-bytecode-dialect-version=test=1.12 | mlir-opt | FileCheck %s
+// RUN: not mlir-opt %s -emit-bytecode-dialect-version=builtin=0 2>&1 | FileCheck %s --check-prefix=NO-BYTECODE
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin 2>&1 | FileCheck %s --check-prefix=MALFORMED
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin= 2>&1 | FileCheck %s --check-prefix=MALFORMED
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version==0 2>&1 | FileCheck %s --check-prefix=MALFORMED
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=unknown=0 2>&1 | FileCheck %s --check-prefix=UNKNOWN
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=arith=0 2>&1 | FileCheck %s --check-prefix=UNSUPPORTED-DIALECT
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=func=1 2>&1 | FileCheck %s --check-prefix=UNSUPPORTED-PARSER
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin=-1 2>&1 | FileCheck %s --check-prefix=UNSUPPORTED-VERSION
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin=2 2>&1 | FileCheck %s --check-prefix=UNSUPPORTED-VERSION
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin=abc 2>&1 | FileCheck %s --check-prefix=UNSUPPORTED-VERSION
+// RUN: not mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=builtin=0 -emit-bytecode-dialect-version=builtin=1 2>&1 | FileCheck %s --check-prefix=DUPLICATE
+
+// NO-BYTECODE: dialect bytecode version while not emitting bytecode
+// MALFORMED: expected 'dialect=version' for --emit-bytecode-dialect-version
+// UNKNOWN: unknown dialect 'unknown' for bytecode emission
+// UNSUPPORTED-DIALECT: dialect 'arith' does not support emitting bytecode version '0'
+// UNSUPPORTED-PARSER: dialect 'func' does not support emitting bytecode version '1'
+// UNSUPPORTED-VERSION: dialect 'builtin' does not support emitting bytecode version
+// DUPLICATE: duplicate bytecode version for dialect 'builtin'
+
+// CHECK: "test.versionedA"() <{dims = 123 : i64, modifier = false}>
+"test.versionedA"() <{dims = 123 : i64, modifier = false}> : () -> ()
+// CHECK: "test.versionedC"() <{attribute = #test.attr_params<42, 24>}>
+"test.versionedC"() <{attribute = #test.attr_params<42, 24>}> : () -> ()

diff  --git a/mlir/test/Bytecode/versioning/emit-test-version-lossy.mlir b/mlir/test/Bytecode/versioning/emit-test-version-lossy.mlir
new file mode 100644
index 00000000000000..d95607cd8fe081
--- /dev/null
+++ b/mlir/test/Bytecode/versioning/emit-test-version-lossy.mlir
@@ -0,0 +1,12 @@
+// RUN: mlir-opt %s -split-input-file -emit-bytecode -emit-bytecode-dialect-version=test=1.12 -verify-diagnostics
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=test=2.0 | mlir-opt | FileCheck %s
+
+// CHECK: "test.versionedA"() <{dims = 123 : i64, modifier = true}>
+// expected-error at +1 {{cannot emit test dialect versions before 2.0 with 'modifier = true'}}
+"test.versionedA"() <{dims = 123 : i64, modifier = true}> : () -> ()
+
+// -----
+
+// CHECK: test.with_versioned_properties 1 | 2
+// expected-error at +1 {{cannot emit test dialect versions before 2.0 with a nonzero 'value2' property}}
+test.with_versioned_properties 1 | 2

diff  --git a/mlir/test/Bytecode/versioning/versioned_op_with_native_properties.mlir b/mlir/test/Bytecode/versioning/versioned_op_with_native_properties.mlir
index 823a559cbca146..77ae93d22fb22c 100644
--- a/mlir/test/Bytecode/versioning/versioned_op_with_native_properties.mlir
+++ b/mlir/test/Bytecode/versioning/versioned_op_with_native_properties.mlir
@@ -26,3 +26,9 @@
 // COM: }
 // RUN: mlir-opt %S/versioned-op-with-native-prop-1.12.mlirbc 2>&1 | FileCheck %s --check-prefix=CHECK3
 // CHECK3: test.with_versioned_properties 1 | 0
+
+// Verify emission for both historical and current dialect versions.
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=test=1.12 | mlir-opt | FileCheck %s --check-prefix=EMIT
+// RUN: mlir-opt %s -emit-bytecode -emit-bytecode-dialect-version=test=2.0 | mlir-opt | FileCheck %s --check-prefix=EMIT
+// EMIT: test.with_versioned_properties 1 | 0
+test.with_versioned_properties 1 | 0

diff  --git a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
index ebb198456b3c12..1a2527a45f01b5 100644
--- a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
+++ b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed.mlir
@@ -1,8 +1,14 @@
+// Verify that both historical and current builtin encodings are unchanged.
+// RUN: mlir-opt -allow-unregistered-dialect -emit-bytecode -emit-bytecode-producer=fixed -emit-bytecode-dialect-version=builtin=0 %s -o %t.0
+// RUN: cmp -s %t.0 %p/builtin_fixed_0.mlirbc
+// RUN: mlir-opt -allow-unregistered-dialect -emit-bytecode -emit-bytecode-producer=fixed -emit-bytecode-dialect-version=builtin=1 %s -o %t.1
+// RUN: cmp -s %t.1 %p/builtin_fixed_1.mlirbc
+// Verify that the default encoding is the current version.
 // RUN: mlir-opt -allow-unregistered-dialect -emit-bytecode -emit-bytecode-producer=fixed %s -o %t
-// Verify unchanged.
-// RUN: cmp -s %t %p/builtin_fixed_0.mlirbc
-// Verify can read as expected.
-// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-local-scope %t | FileCheck %s
+// RUN: cmp -s %t %t.1
+// Verify that the checked-in fixtures can be read as expected.
+// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-local-scope %p/builtin_fixed_0.mlirbc | FileCheck %s
+// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-local-scope %p/builtin_fixed_1.mlirbc | FileCheck %s
 
 // Regression test for all builtin dialect bytecode attribute and
 // type encodings. Exercises every entry in BuiltinDialectAttributes and

diff  --git a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc
index ee79226875ffae..4f661b5a1d2333 100644
Binary files a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc and b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_0.mlirbc 
diff er

diff  --git a/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_1.mlirbc b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_1.mlirbc
new file mode 100644
index 00000000000000..ee79226875ffae
Binary files /dev/null and b/mlir/test/Dialect/Builtin/Bytecode/builtin_fixed_1.mlirbc 
diff er

diff  --git a/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp b/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
index 2b52978fe3636d..f77a0fe06aa9f7 100644
--- a/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
+++ b/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
@@ -9,6 +9,7 @@
 #include "TestDialect.h"
 #include "TestOps.h"
 #include "TestTypes.h"
+#include "mlir/Bytecode/Encoding.h"
 #include "mlir/Conversion/ConvertToEmitC/ToEmitCInterface.h"
 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
 #include "mlir/Dialect/EmitC/IR/EmitC.h"
@@ -74,9 +75,19 @@ struct TestBytecodeDialectInterface : public BytecodeDialectInterface {
   LogicalResult writeAttribute(Attribute attr,
                                DialectBytecodeWriter &writer) const final {
     if (auto concreteAttr = llvm::dyn_cast<TestAttrParamsAttr>(attr)) {
+      // Without dialect version metadata, use the textual fallback rather than
+      // emit a historical encoding that a reader would interpret as current.
+      if (writer.getBytecodeVersion() < bytecode::kDialectVersioning)
+        return failure();
       writer.writeVarInt(test_encoding::k_attr_params);
-      writer.writeVarInt(concreteAttr.getV0());
-      writer.writeVarInt(concreteAttr.getV1());
+      auto version = writer.getDialectVersion<TestDialect>();
+      bool useOldEncoding =
+          succeeded(version) &&
+          static_cast<const TestDialectVersion *>(*version)->major_ < 2;
+      writer.writeVarInt(useOldEncoding ? concreteAttr.getV1()
+                                        : concreteAttr.getV0());
+      writer.writeVarInt(useOldEncoding ? concreteAttr.getV0()
+                                        : concreteAttr.getV1());
       return success();
     }
     return failure();
@@ -97,6 +108,39 @@ struct TestBytecodeDialectInterface : public BytecodeDialectInterface {
     return Attribute();
   }
 
+  std::unique_ptr<DialectVersion> parseVersion(StringRef version) const final {
+    auto [major, minor] = version.split('.');
+    uint32_t majorVersion, minorVersion;
+    if (major.getAsInteger(10, majorVersion) ||
+        minor.getAsInteger(10, minorVersion) || majorVersion > 2 ||
+        (majorVersion == 2 && minorVersion > 0))
+      return nullptr;
+    return std::make_unique<TestDialectVersion>(majorVersion, minorVersion);
+  }
+
+  LogicalResult verifyVersion(Operation *topLevelOp,
+                              const DialectVersion &version) const final {
+    if (static_cast<const TestDialectVersion &>(version).major_ >= 2)
+      return success();
+    WalkResult result = topLevelOp->walk([](TestVersionedOpA op) {
+      if (!op.getModifier())
+        return WalkResult::advance();
+      op.emitOpError("cannot emit test dialect versions before 2.0 with "
+                     "'modifier = true'");
+      return WalkResult::interrupt();
+    });
+    if (result.wasInterrupted())
+      return failure();
+    result = topLevelOp->walk([](TestOpWithVersionedProperties op) {
+      if (op.getProperties().prop.value2 == 0)
+        return WalkResult::advance();
+      op.emitOpError("cannot emit test dialect versions before 2.0 with "
+                     "a nonzero 'value2' property");
+      return WalkResult::interrupt();
+    });
+    return failure(result.wasInterrupted());
+  }
+
   // Emit a specific version of the dialect.
   void writeVersion(DialectBytecodeWriter &writer) const final {
     // Construct the current dialect version.

diff  --git a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
index e2ec23e2a68a1e..57cd56f70fac0f 100644
--- a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
+++ b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
@@ -1778,7 +1778,6 @@ void TestVersionedOpA::writeProperties(mlir::DialectBytecodeWriter &writer) {
     const auto *version =
         reinterpret_cast<const TestDialectVersion *>(*maybeVersion);
     if ((version->major_ < 2)) {
-      llvm::outs() << "downgrading op properties...\n";
       return;
     }
   }
@@ -1819,6 +1818,10 @@ void TestOpWithVersionedProperties::writeToMlirBytecode(
     mlir::DialectBytecodeWriter &writer,
     const test::VersionedProperties &prop) {
   writer.writeVarInt(prop.value1);
+  auto version = writer.getDialectVersion<test::TestDialect>();
+  if (succeeded(version) &&
+      static_cast<const TestDialectVersion *>(*version)->major_ < 2)
+    return;
   writer.writeVarInt(prop.value2);
 }
 


        


More information about the Mlir-commits mailing list