[Mlir-commits] [mlir] 837d1ce - [MLIR] Add native Bytecode support for properties
Mehdi Amini
llvmlistbot at llvm.org
Thu May 25 15:16:03 PDT 2023
Author: Mehdi Amini
Date: 2023-05-25T15:15:47-07:00
New Revision: 837d1ce0dc8eec5b17255291b3462e6296cb369b
URL: https://github.com/llvm/llvm-project/commit/837d1ce0dc8eec5b17255291b3462e6296cb369b
DIFF: https://github.com/llvm/llvm-project/commit/837d1ce0dc8eec5b17255291b3462e6296cb369b.diff
LOG: [MLIR] Add native Bytecode support for properties
This is adding a new interface (`BytecodeOpInterface`) to allow operations to
opt-in skipping conversion to attribute and serializing properties to native
bytecode.
The scheme relies on a new section where properties are stored in sequence
{ size, serialize_properties }, ...
The operations are storing the index of a properties, a table of offset is
built when loading the properties section the first time.
Back-deployment to version prior to 4 are relying on getAttrDictionnary() which
we intend to deprecate and remove: that is putting a de-factor end-of-support
horizon for supporting deployments to version older than 4.
Differential Revision: https://reviews.llvm.org/D151065
Added:
mlir/include/mlir/Bytecode/BytecodeOpInterface.h
mlir/include/mlir/Bytecode/BytecodeOpInterface.td
mlir/include/mlir/Bytecode/CMakeLists.txt
mlir/lib/Bytecode/BytecodeOpInterface.cpp
Modified:
mlir/examples/standalone/include/Standalone/StandaloneDialect.h
mlir/include/mlir/Bytecode/BytecodeImplementation.h
mlir/include/mlir/Bytecode/BytecodeWriter.h
mlir/include/mlir/Bytecode/Encoding.h
mlir/include/mlir/CMakeLists.txt
mlir/include/mlir/Dialect/AMDGPU/IR/AMDGPUDialect.h
mlir/include/mlir/Dialect/AMX/AMXDialect.h
mlir/include/mlir/Dialect/Affine/TransformOps/AffineTransformOps.h
mlir/include/mlir/Dialect/Arith/IR/Arith.h
mlir/include/mlir/Dialect/ArmNeon/ArmNeonDialect.h
mlir/include/mlir/Dialect/ArmSVE/ArmSVEDialect.h
mlir/include/mlir/Dialect/Async/IR/Async.h
mlir/include/mlir/Dialect/Bufferization/IR/Bufferization.h
mlir/include/mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.h
mlir/include/mlir/Dialect/Complex/IR/Complex.h
mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlow.h
mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlowOps.h
mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
mlir/include/mlir/Dialect/Func/IR/FuncOps.h
mlir/include/mlir/Dialect/GPU/IR/GPUDialect.h
mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
mlir/include/mlir/Dialect/Index/IR/IndexOps.h
mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
mlir/include/mlir/Dialect/LLVMIR/NVVMDialect.h
mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.h
mlir/include/mlir/Dialect/Linalg/IR/Linalg.h
mlir/include/mlir/Dialect/MLProgram/IR/MLProgram.h
mlir/include/mlir/Dialect/Math/IR/Math.h
mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.h
mlir/include/mlir/Dialect/NVGPU/IR/NVGPUDialect.h
mlir/include/mlir/Dialect/OpenACC/OpenACC.h
mlir/include/mlir/Dialect/PDL/IR/PDLOps.h
mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterp.h
mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.h
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h
mlir/include/mlir/Dialect/Shape/IR/Shape.h
mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensor.h
mlir/include/mlir/Dialect/Tensor/IR/Tensor.h
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
mlir/include/mlir/Dialect/Transform/IR/TransformOps.h
mlir/include/mlir/Dialect/Transform/PDLExtension/PDLExtensionOps.h
mlir/include/mlir/Dialect/Vector/IR/VectorOps.h
mlir/include/mlir/Dialect/X86Vector/X86VectorDialect.h
mlir/include/mlir/IR/OpBase.td
mlir/include/mlir/TableGen/Property.h
mlir/lib/Bytecode/CMakeLists.txt
mlir/lib/Bytecode/Reader/BytecodeReader.cpp
mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
mlir/lib/Bytecode/Writer/CMakeLists.txt
mlir/lib/Bytecode/Writer/IRNumbering.cpp
mlir/lib/Bytecode/Writer/IRNumbering.h
mlir/lib/TableGen/Property.cpp
mlir/test/Bytecode/invalid/invalid-structure.mlir
mlir/test/lib/Dialect/Test/TestDialect.cpp
mlir/test/lib/Dialect/Test/TestOps.td
mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.h
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
Removed:
################################################################################
diff --git a/mlir/examples/standalone/include/Standalone/StandaloneDialect.h b/mlir/examples/standalone/include/Standalone/StandaloneDialect.h
index d3eb24cc308df..71bbefbc72c2f 100644
--- a/mlir/examples/standalone/include/Standalone/StandaloneDialect.h
+++ b/mlir/examples/standalone/include/Standalone/StandaloneDialect.h
@@ -9,6 +9,7 @@
#ifndef STANDALONE_STANDALONEDIALECT_H
#define STANDALONE_STANDALONEDIALECT_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/Dialect.h"
#include "Standalone/StandaloneOpsDialect.h.inc"
diff --git a/mlir/include/mlir/Bytecode/BytecodeImplementation.h b/mlir/include/mlir/Bytecode/BytecodeImplementation.h
index 027df35135683..1cc96e4c764e3 100644
--- a/mlir/include/mlir/Bytecode/BytecodeImplementation.h
+++ b/mlir/include/mlir/Bytecode/BytecodeImplementation.h
@@ -74,6 +74,10 @@ class DialectBytecodeReader {
/// Read a reference to the given attribute.
virtual LogicalResult readAttribute(Attribute &result) = 0;
+ /// Read an optional reference to the given attribute. Returns success even if
+ /// the Attribute isn't present.
+ virtual LogicalResult readOptionalAttribute(Attribute &attr) = 0;
+
template <typename T>
LogicalResult readAttributes(SmallVectorImpl<T> &attrs) {
return readList(attrs, [this](T &attr) { return readAttribute(attr); });
@@ -88,6 +92,18 @@ class DialectBytecodeReader {
return emitError() << "expected " << llvm::getTypeName<T>()
<< ", but got: " << baseResult;
}
+ template <typename T>
+ LogicalResult readOptionalAttribute(T &result) {
+ Attribute baseResult;
+ if (failed(readOptionalAttribute(baseResult)))
+ return failure();
+ if (!baseResult)
+ return success();
+ if ((result = dyn_cast<T>(baseResult)))
+ return success();
+ return emitError() << "expected " << llvm::getTypeName<T>()
+ << ", but got: " << baseResult;
+ }
/// Read a reference to the given type.
virtual LogicalResult readType(Type &result) = 0;
@@ -179,6 +195,7 @@ class DialectBytecodeWriter {
/// Write a reference to the given attribute.
virtual void writeAttribute(Attribute attr) = 0;
+ virtual void writeOptionalAttribute(Attribute attr) = 0;
template <typename T>
void writeAttributes(ArrayRef<T> attrs) {
writeList(attrs, [this](T attr) { writeAttribute(attr); });
diff --git a/mlir/include/mlir/Bytecode/BytecodeOpInterface.h b/mlir/include/mlir/Bytecode/BytecodeOpInterface.h
new file mode 100644
index 0000000000000..b83600fd35e14
--- /dev/null
+++ b/mlir/include/mlir/Bytecode/BytecodeOpInterface.h
@@ -0,0 +1,27 @@
+//===- CallInterfaces.h - Call Interfaces for MLIR --------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the definitions of the BytecodeOpInterface defined in
+// `BytecodeOpInterface.td`.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_BYTECODE_BYTECODEOPINTERFACE_H
+#define MLIR_BYTECODE_BYTECODEOPINTERFACE_H
+
+#include "mlir/Bytecode/BytecodeImplementation.h"
+#include "mlir/Bytecode/BytecodeOpInterface.h"
+#include "mlir/Bytecode/BytecodeReader.h"
+#include "mlir/Bytecode/BytecodeWriter.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/Support/LogicalResult.h"
+
+/// Include the generated interface declarations.
+#include "mlir/Bytecode/BytecodeOpInterface.h.inc"
+
+#endif // MLIR_BYTECODE_BYTECODEOPINTERFACE_H
diff --git a/mlir/include/mlir/Bytecode/BytecodeOpInterface.td b/mlir/include/mlir/Bytecode/BytecodeOpInterface.td
new file mode 100644
index 0000000000000..54fb03e34ec51
--- /dev/null
+++ b/mlir/include/mlir/Bytecode/BytecodeOpInterface.td
@@ -0,0 +1,43 @@
+//===- BytecodeOpInterface.td - Bytecode OpInterface -------*- tablegen -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains an interface for operation interactions with the bytecode
+// serialization/deserialization, in particular for properties.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_BYTECODE_BYTECODEOPINTERFACES
+#define MLIR_BYTECODE_BYTECODEOPINTERFACES
+
+include "mlir/IR/OpBase.td"
+
+// `BytecodeOpInterface`
+def BytecodeOpInterface : OpInterface<"BytecodeOpInterface"> {
+ let description = [{
+ This interface allows operation to control the serialization of their
+ properties.
+ }];
+ let cppNamespace = "::mlir";
+
+ let methods = [
+ StaticInterfaceMethod<[{
+ Read the properties for this operation from the bytecode and populate the state.
+ }],
+ "LogicalResult", "readProperties", (ins
+ "::mlir::DialectBytecodeReader &":$reader,
+ "::mlir::OperationState &":$state)
+ >,
+ InterfaceMethod<[{
+ Write the properties for this operation to the bytecode.
+ }],
+ "void", "writeProperties", (ins "::mlir::DialectBytecodeWriter &":$writer)
+ >,
+ ];
+}
+
+#endif // MLIR_BYTECODE_BYTECODEOPINTERFACES
diff --git a/mlir/include/mlir/Bytecode/BytecodeWriter.h b/mlir/include/mlir/Bytecode/BytecodeWriter.h
index bd4087f6c498d..4a4cec822ff0e 100644
--- a/mlir/include/mlir/Bytecode/BytecodeWriter.h
+++ b/mlir/include/mlir/Bytecode/BytecodeWriter.h
@@ -46,6 +46,9 @@ class BytecodeWriterConfig {
/// is returned by bytecode writer entry point.
void setDesiredBytecodeVersion(int64_t bytecodeVersion);
+ /// Get the set desired bytecode version to emit.
+ int64_t getDesiredBytecodeVersion() const;
+
//===--------------------------------------------------------------------===//
// Resources
//===--------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Bytecode/CMakeLists.txt b/mlir/include/mlir/Bytecode/CMakeLists.txt
new file mode 100644
index 0000000000000..8da03ae06a611
--- /dev/null
+++ b/mlir/include/mlir/Bytecode/CMakeLists.txt
@@ -0,0 +1 @@
+add_mlir_interface(BytecodeOpInterface)
diff --git a/mlir/include/mlir/Bytecode/Encoding.h b/mlir/include/mlir/Bytecode/Encoding.h
index a94bd50510e99..c721b91f934a7 100644
--- a/mlir/include/mlir/Bytecode/Encoding.h
+++ b/mlir/include/mlir/Bytecode/Encoding.h
@@ -69,8 +69,11 @@ enum ID : uint8_t {
/// This section contains the versions of each dialect.
kDialectVersions = 7,
+ /// This section contains the properties for the operations.
+ kProperties = 8,
+
/// The total number of section types.
- kNumSections = 8,
+ kNumSections = 9,
};
} // namespace Section
@@ -90,6 +93,7 @@ enum : uint8_t {
kHasSuccessors = 0b00001000,
kHasInlineRegions = 0b00010000,
kHasUseListOrders = 0b00100000,
+ kHasProperties = 0b01000000,
// clang-format on
};
} // namespace OpEncodingMask
diff --git a/mlir/include/mlir/CMakeLists.txt b/mlir/include/mlir/CMakeLists.txt
index 1e31d7c29e1e4..9cf3b442aa4ad 100644
--- a/mlir/include/mlir/CMakeLists.txt
+++ b/mlir/include/mlir/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(Bytecode)
add_subdirectory(Conversion)
add_subdirectory(Dialect)
add_subdirectory(IR)
diff --git a/mlir/include/mlir/Dialect/AMDGPU/IR/AMDGPUDialect.h b/mlir/include/mlir/Dialect/AMDGPU/IR/AMDGPUDialect.h
index 90b7936def019..0a2e6bb5e9fe4 100644
--- a/mlir/include/mlir/Dialect/AMDGPU/IR/AMDGPUDialect.h
+++ b/mlir/include/mlir/Dialect/AMDGPU/IR/AMDGPUDialect.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_AMDGPU_IR_AMDGPUDIALECT_H_
#define MLIR_DIALECT_AMDGPU_IR_AMDGPUDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/AMX/AMXDialect.h b/mlir/include/mlir/Dialect/AMX/AMXDialect.h
index 8439c2af82c2a..47c92479814de 100644
--- a/mlir/include/mlir/Dialect/AMX/AMXDialect.h
+++ b/mlir/include/mlir/Dialect/AMX/AMXDialect.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_AMX_AMXDIALECT_H_
#define MLIR_DIALECT_AMX_AMXDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/Affine/TransformOps/AffineTransformOps.h b/mlir/include/mlir/Dialect/Affine/TransformOps/AffineTransformOps.h
index fb6f96ec684c2..f52f04ada036f 100644
--- a/mlir/include/mlir/Dialect/Affine/TransformOps/AffineTransformOps.h
+++ b/mlir/include/mlir/Dialect/Affine/TransformOps/AffineTransformOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_AFFINE_TRANSFORMOPS_AFFINETRANSFORMOPS_H
#define MLIR_DIALECT_AFFINE_TRANSFORMOPS_AFFINETRANSFORMOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
#include "mlir/Dialect/Transform/IR/TransformTypes.h"
#include "mlir/IR/OpImplementation.h"
diff --git a/mlir/include/mlir/Dialect/Arith/IR/Arith.h b/mlir/include/mlir/Dialect/Arith/IR/Arith.h
index 1b516ff1e5aa1..e93af36d871a4 100644
--- a/mlir/include/mlir/Dialect/Arith/IR/Arith.h
+++ b/mlir/include/mlir/Dialect/Arith/IR/Arith.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_ARITH_IR_ARITH_H_
#define MLIR_DIALECT_ARITH_IR_ARITH_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/OpImplementation.h"
diff --git a/mlir/include/mlir/Dialect/ArmNeon/ArmNeonDialect.h b/mlir/include/mlir/Dialect/ArmNeon/ArmNeonDialect.h
index 18535353a104c..923d04e82f979 100644
--- a/mlir/include/mlir/Dialect/ArmNeon/ArmNeonDialect.h
+++ b/mlir/include/mlir/Dialect/ArmNeon/ArmNeonDialect.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_ARMNEON_ARMNEONDIALECT_H_
#define MLIR_DIALECT_ARMNEON_ARMNEONDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/ArmSVE/ArmSVEDialect.h b/mlir/include/mlir/Dialect/ArmSVE/ArmSVEDialect.h
index 8882619e3de53..6ecee1e4552b9 100644
--- a/mlir/include/mlir/Dialect/ArmSVE/ArmSVEDialect.h
+++ b/mlir/include/mlir/Dialect/ArmSVE/ArmSVEDialect.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_ARMSVE_ARMSVEDIALECT_H
#define MLIR_DIALECT_ARMSVE_ARMSVEDIALECT_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/Async/IR/Async.h b/mlir/include/mlir/Dialect/Async/IR/Async.h
index 9265e2f8065a1..c3d530f793735 100644
--- a/mlir/include/mlir/Dialect/Async/IR/Async.h
+++ b/mlir/include/mlir/Dialect/Async/IR/Async.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_ASYNC_IR_ASYNC_H
#define MLIR_DIALECT_ASYNC_IR_ASYNC_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Async/IR/AsyncTypes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
diff --git a/mlir/include/mlir/Dialect/Bufferization/IR/Bufferization.h b/mlir/include/mlir/Dialect/Bufferization/IR/Bufferization.h
index 42d88156300c2..08d7126eca315 100644
--- a/mlir/include/mlir/Dialect/Bufferization/IR/Bufferization.h
+++ b/mlir/include/mlir/Dialect/Bufferization/IR/Bufferization.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_BUFFERIZATION_IR_BUFFERIZATION_H_
#define MLIR_DIALECT_BUFFERIZATION_IR_BUFFERIZATION_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h"
#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Interfaces/CopyOpInterface.h"
diff --git a/mlir/include/mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.h b/mlir/include/mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.h
index 426e9d02efda5..75ce4b484165b 100644
--- a/mlir/include/mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.h
+++ b/mlir/include/mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_BUFFERIZATION_TRANSFORMOPS_BUFFERIZATIONTRANSFORMOPS_H
#define MLIR_DIALECT_BUFFERIZATION_TRANSFORMOPS_BUFFERIZATIONTRANSFORMOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
#include "mlir/Dialect/Transform/IR/TransformTypes.h"
diff --git a/mlir/include/mlir/Dialect/Complex/IR/Complex.h b/mlir/include/mlir/Dialect/Complex/IR/Complex.h
index f6c1bf9966098..663e81c71d860 100644
--- a/mlir/include/mlir/Dialect/Complex/IR/Complex.h
+++ b/mlir/include/mlir/Dialect/Complex/IR/Complex.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_COMPLEX_IR_COMPLEX_H_
#define MLIR_DIALECT_COMPLEX_IR_COMPLEX_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
diff --git a/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlow.h b/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlow.h
index f535bdc7db071..0ae076120018f 100644
--- a/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlow.h
+++ b/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlow.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_CONTROLFLOW_IR_CONTROLFLOW_H
#define MLIR_DIALECT_CONTROLFLOW_IR_CONTROLFLOW_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/Dialect.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOpsDialect.h.inc"
diff --git a/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlowOps.h b/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlowOps.h
index 259be091490e6..adbc2db59d013 100644
--- a/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlowOps.h
+++ b/mlir/include/mlir/Dialect/ControlFlow/IR/ControlFlowOps.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_CONTROLFLOW_IR_CONTROLFLOWOPS_H
#define MLIR_DIALECT_CONTROLFLOW_IR_CONTROLFLOWOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
index 857d1430f9418..cd8b9748e14e7 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_EMITC_IR_EMITC_H
#define MLIR_DIALECT_EMITC_IR_EMITC_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
diff --git a/mlir/include/mlir/Dialect/Func/IR/FuncOps.h b/mlir/include/mlir/Dialect/Func/IR/FuncOps.h
index c2d3581ca407a..5ba15eeacdf92 100644
--- a/mlir/include/mlir/Dialect/Func/IR/FuncOps.h
+++ b/mlir/include/mlir/Dialect/Func/IR/FuncOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_FUNC_IR_OPS_H
#define MLIR_DIALECT_FUNC_IR_OPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
diff --git a/mlir/include/mlir/Dialect/GPU/IR/GPUDialect.h b/mlir/include/mlir/Dialect/GPU/IR/GPUDialect.h
index a775066362cab..22b5b56074b6a 100644
--- a/mlir/include/mlir/Dialect/GPU/IR/GPUDialect.h
+++ b/mlir/include/mlir/Dialect/GPU/IR/GPUDialect.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_GPU_IR_GPUDIALECT_H
#define MLIR_DIALECT_GPU_IR_GPUDIALECT_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/DLTI/Traits.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
diff --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
index 1b32691c00b84..0595b345b11ef 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
@@ -13,11 +13,13 @@
#ifndef MLIR_DIALECT_IRDL_IR_IRDL_H_
#define MLIR_DIALECT_IRDL_IR_IRDL_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/IRDL/IR/IRDLInterfaces.h"
#include "mlir/Dialect/IRDL/IR/IRDLTraits.h"
#include "mlir/IR/SymbolTable.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
+
#include <memory>
// Forward declaration.
diff --git a/mlir/include/mlir/Dialect/Index/IR/IndexOps.h b/mlir/include/mlir/Dialect/Index/IR/IndexOps.h
index 2f1ab42964bb2..d9daf892d27e4 100644
--- a/mlir/include/mlir/Dialect/Index/IR/IndexOps.h
+++ b/mlir/include/mlir/Dialect/Index/IR/IndexOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_INDEX_IR_INDEXOPS_H
#define MLIR_DIALECT_INDEX_IR_INDEXOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Index/IR/IndexAttrs.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
index 3725cdd838b9e..d53e90260f757 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_LLVMIR_LLVMDIALECT_H_
#define MLIR_DIALECT_LLVMIR_LLVMDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/NVVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/NVVMDialect.h
index 7d82e82eba225..2376bcad41853 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/NVVMDialect.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/NVVMDialect.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_LLVMIR_NVVMDIALECT_H_
#define MLIR_DIALECT_LLVMIR_NVVMDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.h b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.h
index 478b31f3a6d8a..6e1072423a0f5 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/ROCDLDialect.h
@@ -22,6 +22,7 @@
#ifndef MLIR_DIALECT_LLVMIR_ROCDLDIALECT_H_
#define MLIR_DIALECT_LLVMIR_ROCDLDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/Linalg/IR/Linalg.h b/mlir/include/mlir/Dialect/Linalg/IR/Linalg.h
index 4b628054c4929..801d744f909ac 100644
--- a/mlir/include/mlir/Dialect/Linalg/IR/Linalg.h
+++ b/mlir/include/mlir/Dialect/Linalg/IR/Linalg.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_LINALG_IR_LINALG_H
#define MLIR_DIALECT_LINALG_IR_LINALG_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
#include "mlir/IR/AffineExpr.h"
diff --git a/mlir/include/mlir/Dialect/MLProgram/IR/MLProgram.h b/mlir/include/mlir/Dialect/MLProgram/IR/MLProgram.h
index 11b4213d128bc..f0b5204ae31c5 100644
--- a/mlir/include/mlir/Dialect/MLProgram/IR/MLProgram.h
+++ b/mlir/include/mlir/Dialect/MLProgram/IR/MLProgram.h
@@ -8,6 +8,7 @@
#ifndef MLIR_DIALECT_MLPROGRAM_IR_MLPROGRAM_H_
#define MLIR_DIALECT_MLPROGRAM_IR_MLPROGRAM_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/MLProgram/IR/MLProgramAttributes.h"
#include "mlir/Dialect/MLProgram/IR/MLProgramTypes.h"
#include "mlir/IR/Dialect.h"
diff --git a/mlir/include/mlir/Dialect/Math/IR/Math.h b/mlir/include/mlir/Dialect/Math/IR/Math.h
index 98416d1c9abdf..dcbcb1572fb80 100644
--- a/mlir/include/mlir/Dialect/Math/IR/Math.h
+++ b/mlir/include/mlir/Dialect/Math/IR/Math.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_MATH_IR_MATH_H_
#define MLIR_DIALECT_MATH_IR_MATH_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h b/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
index 9e4f7e2d5c458..0c2ea33496862 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_MEMREF_IR_MEMREF_H_
#define MLIR_DIALECT_MEMREF_IR_MEMREF_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
#include "mlir/IR/Dialect.h"
@@ -21,6 +22,7 @@
#include "mlir/Interfaces/ShapedOpInterfaces.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Interfaces/ViewLikeInterface.h"
+
#include <optional>
namespace mlir {
diff --git a/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.h b/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.h
index 3d85a1b3a2ce4..ee7c696831488 100644
--- a/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.h
+++ b/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_MEMREF_TRANSFORMOPS_MEMREFTRANSFORMOPS_H
#define MLIR_DIALECT_MEMREF_TRANSFORMOPS_MEMREFTRANSFORMOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
#include "mlir/IR/OpImplementation.h"
diff --git a/mlir/include/mlir/Dialect/NVGPU/IR/NVGPUDialect.h b/mlir/include/mlir/Dialect/NVGPU/IR/NVGPUDialect.h
index bdc887f68c199..ede8b781b2ca1 100644
--- a/mlir/include/mlir/Dialect/NVGPU/IR/NVGPUDialect.h
+++ b/mlir/include/mlir/Dialect/NVGPU/IR/NVGPUDialect.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_NVGPU_NVGPUDIALECT_H_
#define MLIR_DIALECT_NVGPU_NVGPUDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index 00fe7faf416f0..5d76030dcc67e 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -18,6 +18,7 @@
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/SymbolTable.h"
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.h.inc"
#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.h.inc"
#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.h.inc"
diff --git a/mlir/include/mlir/Dialect/PDL/IR/PDLOps.h b/mlir/include/mlir/Dialect/PDL/IR/PDLOps.h
index 8e560ae09ee8d..22935827519d3 100644
--- a/mlir/include/mlir/Dialect/PDL/IR/PDLOps.h
+++ b/mlir/include/mlir/Dialect/PDL/IR/PDLOps.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_PDL_IR_PDLOPS_H_
#define MLIR_DIALECT_PDL_IR_PDLOPS_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/PDL/IR/PDLTypes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/OpImplementation.h"
diff --git a/mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterp.h b/mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterp.h
index 9cde220331dc9..9bbb1e31f5574 100644
--- a/mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterp.h
+++ b/mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterp.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_PDLINTERP_IR_PDLINTERP_H_
#define MLIR_DIALECT_PDLINTERP_IR_PDLINTERP_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/PDL/IR/PDL.h"
#include "mlir/Dialect/PDL/IR/PDLTypes.h"
#include "mlir/IR/FunctionInterfaces.h"
diff --git a/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.h b/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.h
index c5cc2da232846..9437f893961b2 100644
--- a/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.h
+++ b/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_SCF_TRANSFORMOPS_SCFTRANSFORMOPS_H
#define MLIR_DIALECT_SCF_TRANSFORMOPS_SCFTRANSFORMOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
#include "mlir/Dialect/Transform/IR/TransformTypes.h"
#include "mlir/IR/OpImplementation.h"
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h
index ee4c95c9564b5..5387299d00158 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_SPIRV_IR_SPIRVOPS_H_
#define MLIR_DIALECT_SPIRV_IR_SPIRVOPS_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVOpTraits.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"
diff --git a/mlir/include/mlir/Dialect/Shape/IR/Shape.h b/mlir/include/mlir/Dialect/Shape/IR/Shape.h
index 8d2e3100a488f..6efa57819b491 100644
--- a/mlir/include/mlir/Dialect/Shape/IR/Shape.h
+++ b/mlir/include/mlir/Dialect/Shape/IR/Shape.h
@@ -14,6 +14,7 @@
#ifndef MLIR_DIALECT_SHAPE_IR_SHAPE_H
#define MLIR_DIALECT_SHAPE_IR_SHAPE_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/FunctionInterfaces.h"
diff --git a/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensor.h b/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensor.h
index 41fd19e71cb76..2e3753cbae8d4 100644
--- a/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensor.h
+++ b/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensor.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_SPARSETENSOR_IR_SPARSETENSOR_H_
#define MLIR_DIALECT_SPARSETENSOR_IR_SPARSETENSOR_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/SparseTensor/IR/Enums.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
diff --git a/mlir/include/mlir/Dialect/Tensor/IR/Tensor.h b/mlir/include/mlir/Dialect/Tensor/IR/Tensor.h
index cbc93849c0a85..c64959bfbd74a 100644
--- a/mlir/include/mlir/Dialect/Tensor/IR/Tensor.h
+++ b/mlir/include/mlir/Dialect/Tensor/IR/Tensor.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_TENSOR_IR_TENSOR_H_
#define MLIR_DIALECT_TENSOR_IR_TENSOR_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
index e8db8542c919b..4447247475f9a 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_TOSA_IR_TOSAOPS_H
#define MLIR_DIALECT_TOSA_IR_TOSAOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Traits.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
diff --git a/mlir/include/mlir/Dialect/Transform/IR/TransformOps.h b/mlir/include/mlir/Dialect/Transform/IR/TransformOps.h
index f77982f1790c6..9ddc11de3ce2d 100644
--- a/mlir/include/mlir/Dialect/Transform/IR/TransformOps.h
+++ b/mlir/include/mlir/Dialect/Transform/IR/TransformOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_TRANSFORM_IR_TRANSFORMOPS_H
#define MLIR_DIALECT_TRANSFORM_IR_TRANSFORMOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Transform/IR/MatchInterfaces.h"
#include "mlir/Dialect/Transform/IR/TransformAttrs.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
diff --git a/mlir/include/mlir/Dialect/Transform/PDLExtension/PDLExtensionOps.h b/mlir/include/mlir/Dialect/Transform/PDLExtension/PDLExtensionOps.h
index a159c30df86d3..9077e9fc9ffbd 100644
--- a/mlir/include/mlir/Dialect/Transform/PDLExtension/PDLExtensionOps.h
+++ b/mlir/include/mlir/Dialect/Transform/PDLExtension/PDLExtensionOps.h
@@ -9,6 +9,7 @@
#ifndef MLIR_DIALECT_TRANSFORM_PDLEXTENSION_PDLEXTENSIONOPS_H
#define MLIR_DIALECT_TRANSFORM_PDLEXTENSION_PDLEXTENSIONOPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Transform/IR/TransformDialect.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/Vector/IR/VectorOps.h b/mlir/include/mlir/Dialect/Vector/IR/VectorOps.h
index 2edb239d5a61b..def4869e3274b 100644
--- a/mlir/include/mlir/Dialect/Vector/IR/VectorOps.h
+++ b/mlir/include/mlir/Dialect/Vector/IR/VectorOps.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_VECTOR_IR_VECTOROPS_H
#define MLIR_DIALECT_VECTOR_IR_VECTOROPS_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/Vector/Interfaces/MaskableOpInterface.h"
#include "mlir/Dialect/Vector/Interfaces/MaskingOpInterface.h"
#include "mlir/IR/AffineMap.h"
diff --git a/mlir/include/mlir/Dialect/X86Vector/X86VectorDialect.h b/mlir/include/mlir/Dialect/X86Vector/X86VectorDialect.h
index 28651cd124a8f..4017bc1a917e2 100644
--- a/mlir/include/mlir/Dialect/X86Vector/X86VectorDialect.h
+++ b/mlir/include/mlir/Dialect/X86Vector/X86VectorDialect.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_X86VECTOR_X86VECTORDIALECT_H_
#define MLIR_DIALECT_X86VECTOR_X86VECTORDIALECT_H_
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td
index 2dd62c114b07b..a3e34f44e76fc 100644
--- a/mlir/include/mlir/IR/OpBase.td
+++ b/mlir/include/mlir/IR/OpBase.td
@@ -238,6 +238,25 @@ class Property<string storageTypeParam = "", string desc = ""> {
llvm::hash_value($_storage);
}];
+ // The call expression to emit the storage type to bytecode.
+ //
+ // Format:
+ // - `$_storage` is the storage type value.
+ // - `$_writer` is a `DialectBytecodeWriter`.
+ code writeToMlirBytecode = [{
+ writeToMlirBytecode($_writer, $_storage)
+ }];
+
+ // The call expression to read the storage type from bytecode.
+ //
+ // Format:
+ // - `$_storage` is the storage type value.
+ // - `$_reader` is a `DialectBytecodeReader`.
+ code readFromMlirBytecode = [{
+ if (failed(readFromMlirBytecode($_reader, $_storage)))
+ return failure();
+ }];
+
// Default value for the property.
string defaultValue = ?;
}
@@ -1156,6 +1175,20 @@ class DefaultValuedOptionalStrAttr<Attr attr, string val>
//===----------------------------------------------------------------------===//
// Primitive property kinds
+// Any kind of integer stored as properties.
+class IntProperty<string storageTypeParam = "", string desc = ""> :
+ Property<storageTypeParam, desc> {
+ code writeToMlirBytecode = [{
+ $_writer.writeVarInt($_storage);
+ }];
+ code readFromMlirBytecode = [{
+ uint64_t val;
+ if (failed($_reader.readVarInt(val)))
+ return ::mlir::failure();
+ $_storage = val;
+ }];
+}
+
class ArrayProperty<string storageTypeParam = "", int n, string desc = ""> :
Property<storageTypeParam # "[" # n # "]", desc> {
let interfaceType = "::llvm::ArrayRef<" # storageTypeParam # ">";
diff --git a/mlir/include/mlir/TableGen/Property.h b/mlir/include/mlir/TableGen/Property.h
index 7118ca496de07..597543d6f7261 100644
--- a/mlir/include/mlir/TableGen/Property.h
+++ b/mlir/include/mlir/TableGen/Property.h
@@ -58,6 +58,14 @@ class Property {
// in the provided interface type and assign it to the storage.
StringRef getConvertFromAttributeCall() const;
+ // Returns the method call which reads this property from
+ // bytecode and assign it to the storage.
+ StringRef getReadFromMlirBytecodeCall() const;
+
+ // Returns the method call which write this property's
+ // to the the bytecode.
+ StringRef getWriteToMlirBytecodeCall() const;
+
// Returns the code to compute the hash for this property.
StringRef getHashPropertyCall() const;
diff --git a/mlir/lib/Bytecode/BytecodeOpInterface.cpp b/mlir/lib/Bytecode/BytecodeOpInterface.cpp
new file mode 100644
index 0000000000000..e767f57b9bb44
--- /dev/null
+++ b/mlir/lib/Bytecode/BytecodeOpInterface.cpp
@@ -0,0 +1,17 @@
+//===- BytecodeOpInterface.cpp - Bytecode Op Interfaces -------------------===//
+//
+// 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 "mlir/Bytecode/BytecodeOpInterface.h"
+
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+// BytecodeOpInterface
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Bytecode/BytecodeOpInterface.cpp.inc"
diff --git a/mlir/lib/Bytecode/CMakeLists.txt b/mlir/lib/Bytecode/CMakeLists.txt
index ff7e290cad1bb..c89415f60d124 100644
--- a/mlir/lib/Bytecode/CMakeLists.txt
+++ b/mlir/lib/Bytecode/CMakeLists.txt
@@ -1,2 +1,13 @@
add_subdirectory(Reader)
add_subdirectory(Writer)
+
+add_mlir_library(MLIRBytecodeOpInterface
+ BytecodeOpInterface.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${MLIR_MAIN_INCLUDE_DIR}/mlir/Bytecode
+
+ LINK_LIBS PUBLIC
+ MLIRIR
+ MLIRSupport
+ )
diff --git a/mlir/lib/Bytecode/Reader/BytecodeReader.cpp b/mlir/lib/Bytecode/Reader/BytecodeReader.cpp
index ca05eac1e3e16..bd9f045a1020c 100644
--- a/mlir/lib/Bytecode/Reader/BytecodeReader.cpp
+++ b/mlir/lib/Bytecode/Reader/BytecodeReader.cpp
@@ -11,6 +11,7 @@
#include "mlir/Bytecode/BytecodeReader.h"
#include "mlir/AsmParser/AsmParser.h"
#include "mlir/Bytecode/BytecodeImplementation.h"
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Bytecode/Encoding.h"
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/BuiltinOps.h"
@@ -20,6 +21,7 @@
#include "mlir/IR/Visitors.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Support/LogicalResult.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
@@ -28,6 +30,7 @@
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/SourceMgr.h"
+#include <cstddef>
#include <list>
#include <memory>
#include <numeric>
@@ -56,13 +59,15 @@ static std::string toString(bytecode::Section::ID sectionID) {
return "ResourceOffset (6)";
case bytecode::Section::kDialectVersions:
return "DialectVersions (7)";
+ case bytecode::Section::kProperties:
+ return "Properties (8)";
default:
return ("Unknown (" + Twine(static_cast<unsigned>(sectionID)) + ")").str();
}
}
/// Returns true if the given top-level section ID is optional.
-static bool isSectionOptional(bytecode::Section::ID sectionID) {
+static bool isSectionOptional(bytecode::Section::ID sectionID, int version) {
switch (sectionID) {
case bytecode::Section::kString:
case bytecode::Section::kDialect:
@@ -74,6 +79,8 @@ static bool isSectionOptional(bytecode::Section::ID sectionID) {
case bytecode::Section::kResourceOffset:
case bytecode::Section::kDialectVersions:
return true;
+ case bytecode::Section::kProperties:
+ return version < 4;
default:
llvm_unreachable("unknown section ID");
}
@@ -362,6 +369,17 @@ class StringSectionReader {
return parseEntry(reader, strings, result, "string");
}
+ /// Parse a shared string from the string section. The shared string is
+ /// encoded using an index to a corresponding string in the string section.
+ /// This variant parses a flag compressed with the index.
+ LogicalResult parseStringWithFlag(EncodingReader &reader, StringRef &result,
+ bool &flag) {
+ uint64_t entryIdx;
+ if (failed(reader.parseVarIntWithFlag(entryIdx, flag)))
+ return failure();
+ return parseStringAtIndex(reader, entryIdx, result);
+ }
+
/// Parse a shared string from the string section. The shared string is
/// encoded using an index to a corresponding string in the string section.
LogicalResult parseStringAtIndex(EncodingReader &reader, uint64_t index,
@@ -459,8 +477,9 @@ struct BytecodeDialect {
/// This struct represents an operation name entry within the bytecode.
struct BytecodeOperationName {
- BytecodeOperationName(BytecodeDialect *dialect, StringRef name)
- : dialect(dialect), name(name) {}
+ BytecodeOperationName(BytecodeDialect *dialect, StringRef name,
+ bool wasRegistered)
+ : dialect(dialect), name(name), wasRegistered(wasRegistered) {}
/// The loaded operation name, or std::nullopt if it hasn't been processed
/// yet.
@@ -471,6 +490,10 @@ struct BytecodeOperationName {
/// The name of the operation, without the dialect prefix.
StringRef name;
+
+ /// Whether this operation was registered when the bytecode was produced.
+ /// This flag is populated when bytecode version >=4.
+ bool wasRegistered;
};
} // namespace
@@ -791,6 +814,18 @@ class AttrTypeReader {
result = resolveAttribute(attrIdx);
return success(!!result);
}
+ LogicalResult parseOptionalAttribute(EncodingReader &reader,
+ Attribute &result) {
+ uint64_t attrIdx;
+ bool flag;
+ if (failed(reader.parseVarIntWithFlag(attrIdx, flag)))
+ return failure();
+ if (!flag)
+ return success();
+ result = resolveAttribute(attrIdx);
+ return success(!!result);
+ }
+
LogicalResult parseType(EncodingReader &reader, Type &result) {
uint64_t typeIdx;
if (failed(reader.parseVarInt(typeIdx)))
@@ -870,7 +905,9 @@ class DialectReader : public DialectBytecodeReader {
LogicalResult readAttribute(Attribute &result) override {
return attrTypeReader.parseAttribute(reader, result);
}
-
+ LogicalResult readOptionalAttribute(Attribute &result) override {
+ return attrTypeReader.parseOptionalAttribute(reader, result);
+ }
LogicalResult readType(Type &result) override {
return attrTypeReader.parseType(reader, result);
}
@@ -957,6 +994,87 @@ class DialectReader : public DialectBytecodeReader {
ResourceSectionReader &resourceReader;
EncodingReader &reader;
};
+
+/// Wraps the properties section and handles reading properties out of it.
+class PropertiesSectionReader {
+public:
+ /// Initialize the properties section reader with the given section data.
+ LogicalResult initialize(Location fileLoc, ArrayRef<uint8_t> sectionData) {
+ if (sectionData.empty())
+ return success();
+ EncodingReader propReader(sectionData, fileLoc);
+ size_t count;
+ if (failed(propReader.parseVarInt(count)))
+ return failure();
+ // Parse the raw properties buffer.
+ if (failed(propReader.parseBytes(propReader.size(), propertiesBuffers)))
+ return failure();
+
+ EncodingReader offsetsReader(propertiesBuffers, fileLoc);
+ offsetTable.reserve(count);
+ for (auto idx : llvm::seq<int64_t>(0, count)) {
+ (void)idx;
+ offsetTable.push_back(propertiesBuffers.size() - offsetsReader.size());
+ ArrayRef<uint8_t> rawProperties;
+ uint64_t dataSize;
+ if (failed(offsetsReader.parseVarInt(dataSize)) ||
+ failed(offsetsReader.parseBytes(dataSize, rawProperties)))
+ return failure();
+ }
+ if (!offsetsReader.empty())
+ return offsetsReader.emitError()
+ << "Broken properties section: didn't exhaust the offsets table";
+ return success();
+ }
+
+ LogicalResult read(Location fileLoc, DialectReader &dialectReader,
+ OperationName *opName, OperationState &opState) {
+ size_t propertiesIdx;
+ if (failed(dialectReader.readVarInt(propertiesIdx)))
+ return failure();
+ if (propertiesIdx >= offsetTable.size())
+ return dialectReader.emitError("Properties idx out-of-bound for ")
+ << opName->getStringRef();
+ size_t propertiesOffset = offsetTable[propertiesIdx];
+ if (propertiesIdx >= propertiesBuffers.size())
+ return dialectReader.emitError("Properties offset out-of-bound for ")
+ << opName->getStringRef();
+
+ // Acquire the sub-buffer that represent the requested properties.
+ ArrayRef<char> rawProperties;
+ {
+ // "Seek" to the requested offset by getting a new reader with the right
+ // sub-buffer.
+ EncodingReader reader(propertiesBuffers.drop_front(propertiesOffset),
+ fileLoc);
+ // Properties are stored as a sequence of {size + raw_data}.
+ if (failed(
+ dialectReader.withEncodingReader(reader).readBlob(rawProperties)))
+ return failure();
+ }
+ // Setup a new reader to read from the `rawProperties` sub-buffer.
+ EncodingReader reader(
+ StringRef(rawProperties.begin(), rawProperties.size()), fileLoc);
+ DialectReader propReader = dialectReader.withEncodingReader(reader);
+
+ auto *iface = opName->getInterface<BytecodeOpInterface>();
+ if (iface)
+ return iface->readProperties(propReader, opState);
+ if (opName->isRegistered())
+ return propReader.emitError(
+ "has properties but missing BytecodeOpInterface for ")
+ << opName->getStringRef();
+ // Unregistered op are storing properties as an attribute.
+ return propReader.readAttribute(opState.propertiesAttr);
+ }
+
+private:
+ /// The properties buffer referenced within the bytecode file.
+ ArrayRef<uint8_t> propertiesBuffers;
+
+ /// Table of offset in the buffer above.
+ SmallVector<int64_t> offsetTable;
+};
} // namespace
LogicalResult
@@ -1194,7 +1312,9 @@ class mlir::BytecodeReader::Impl {
lazyLoadableOps.erase(it->getSecond());
lazyLoadableOpsMap.erase(it);
auto result = parseRegions(regionStack, regionStack.back());
- assert(regionStack.empty());
+ assert((regionStack.empty() || failed(result)) &&
+ "broken invariant: regionStack should be empty when parseRegions "
+ "succeeds");
return result;
}
@@ -1210,7 +1330,8 @@ class mlir::BytecodeReader::Impl {
LogicalResult parseDialectSection(ArrayRef<uint8_t> sectionData);
/// Parse an operation name reference using the given reader.
- FailureOr<OperationName> parseOpName(EncodingReader &reader);
+ FailureOr<OperationName> parseOpName(EncodingReader &reader,
+ bool &wasRegistered);
//===--------------------------------------------------------------------===//
// Attribute/Type Section
@@ -1398,6 +1519,9 @@ class mlir::BytecodeReader::Impl {
/// The table of strings referenced within the bytecode file.
StringSectionReader stringReader;
+ /// The table of properties referenced by the operation in the bytecode file.
+ PropertiesSectionReader propertiesReader;
+
/// The current set of available IR value scopes.
std::vector<ValueScope> valueScopes;
@@ -1466,7 +1590,7 @@ LogicalResult BytecodeReader::Impl::read(
// Check that all of the required sections were found.
for (int i = 0; i < bytecode::Section::kNumSections; ++i) {
bytecode::Section::ID sectionID = static_cast<bytecode::Section::ID>(i);
- if (!sectionDatas[i] && !isSectionOptional(sectionID)) {
+ if (!sectionDatas[i] && !isSectionOptional(sectionID, version)) {
return reader.emitError("missing data for top-level section: ",
::toString(sectionID));
}
@@ -1477,6 +1601,12 @@ LogicalResult BytecodeReader::Impl::read(
fileLoc, *sectionDatas[bytecode::Section::kString])))
return failure();
+ // Process the properties section.
+ if (sectionDatas[bytecode::Section::kProperties] &&
+ failed(propertiesReader.initialize(
+ fileLoc, *sectionDatas[bytecode::Section::kProperties])))
+ return failure();
+
// Process the dialect section.
if (failed(parseDialectSection(*sectionDatas[bytecode::Section::kDialect])))
return failure();
@@ -1598,9 +1728,18 @@ BytecodeReader::Impl::parseDialectSection(ArrayRef<uint8_t> sectionData) {
// Parse the operation names, which are grouped by dialect.
auto parseOpName = [&](BytecodeDialect *dialect) {
StringRef opName;
- if (failed(stringReader.parseString(sectionReader, opName)))
- return failure();
- opNames.emplace_back(dialect, opName);
+ bool wasRegistered;
+ // Prior to version 4, the information about wheter an op was registered or
+ // not wasn't encoded.
+ if (version < 4) {
+ if (failed(stringReader.parseString(sectionReader, opName)))
+ return failure();
+ } else {
+ if (failed(stringReader.parseStringWithFlag(sectionReader, opName,
+ wasRegistered)))
+ return failure();
+ }
+ opNames.emplace_back(dialect, opName, wasRegistered);
return success();
};
// Avoid re-allocation in bytecode version > 3 where the number of ops are
@@ -1618,11 +1757,11 @@ BytecodeReader::Impl::parseDialectSection(ArrayRef<uint8_t> sectionData) {
}
FailureOr<OperationName>
-BytecodeReader::Impl::parseOpName(EncodingReader &reader) {
+BytecodeReader::Impl::parseOpName(EncodingReader &reader, bool &wasRegistered) {
BytecodeOperationName *opName = nullptr;
if (failed(parseEntry(reader, opNames, opName, "operation name")))
return failure();
-
+ wasRegistered = opName->wasRegistered;
// Check to see if this operation name has already been resolved. If we
// haven't, load the dialect and build the operation name.
if (!opName->opName) {
@@ -1994,7 +2133,8 @@ BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
RegionReadState &readState,
bool &isIsolatedFromAbove) {
// Parse the name of the operation.
- FailureOr<OperationName> opName = parseOpName(reader);
+ bool wasRegistered;
+ FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
if (failed(opName))
return failure();
@@ -2021,6 +2161,21 @@ BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
opState.attributes = dictAttr;
}
+ if (opMask & bytecode::OpEncodingMask::kHasProperties) {
+ if (wasRegistered) {
+ DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
+ reader);
+ if (failed(
+ propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
+ return failure();
+ } else {
+ // If the operation wasn't registered when it was emitted, the properties
+ // was serialized as an attribute.
+ if (failed(parseAttribute(reader, opState.propertiesAttr)))
+ return failure();
+ }
+ }
+
/// Parse the results of the operation.
if (opMask & bytecode::OpEncodingMask::kHasResults) {
uint64_t numResults;
diff --git a/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp b/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
index 93484913548ab..82d81f763893b 100644
--- a/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
+++ b/mlir/lib/Bytecode/Writer/BytecodeWriter.cpp
@@ -9,11 +9,22 @@
#include "mlir/Bytecode/BytecodeWriter.h"
#include "IRNumbering.h"
#include "mlir/Bytecode/BytecodeImplementation.h"
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Bytecode/Encoding.h"
+#include "mlir/IR/Attributes.h"
#include "mlir/IR/OpImplementation.h"
+#include "mlir/Support/LogicalResult.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <sys/types.h>
#define DEBUG_TYPE "mlir-bytecode-writer"
@@ -58,6 +69,10 @@ void BytecodeWriterConfig::setDesiredBytecodeVersion(int64_t bytecodeVersion) {
std::min<int64_t>(bytecodeVersion, bytecode::kVersion);
}
+int64_t BytecodeWriterConfig::getDesiredBytecodeVersion() const {
+ return impl->bytecodeVersion;
+}
+
//===----------------------------------------------------------------------===//
// EncodingEmitter
//===----------------------------------------------------------------------===//
@@ -318,6 +333,14 @@ class DialectWriter : public DialectBytecodeWriter {
void writeAttribute(Attribute attr) override {
emitter.emitVarInt(numberingState.getNumber(attr));
}
+ void writeOptionalAttribute(Attribute attr) override {
+ if (!attr) {
+ emitter.emitVarInt(0);
+ return;
+ }
+ emitter.emitVarIntWithFlag(numberingState.getNumber(attr), true);
+ }
+
void writeType(Type type) override {
emitter.emitVarInt(numberingState.getNumber(type));
}
@@ -382,6 +405,102 @@ class DialectWriter : public DialectBytecodeWriter {
StringSectionBuilder &stringSection;
};
+namespace {
+class PropertiesSectionBuilder {
+public:
+ PropertiesSectionBuilder(IRNumberingState &numberingState,
+ StringSectionBuilder &stringSection,
+ const BytecodeWriterConfig::Impl &config)
+ : numberingState(numberingState), stringSection(stringSection),
+ config(config) {}
+
+ /// Emit the op properties in the properties section and return the index of
+ /// the properties within the section. Return -1 if no properties was emitted.
+ std::optional<ssize_t> emit(Operation *op) {
+ EncodingEmitter propertiesEmitter;
+ if (!op->getPropertiesStorageSize())
+ return std::nullopt;
+ if (!op->isRegistered()) {
+ // Unregistered op are storing properties as an optional attribute.
+ Attribute prop = *op->getPropertiesStorage().as<Attribute *>();
+ if (!prop)
+ return std::nullopt;
+ EncodingEmitter sizeEmitter;
+ sizeEmitter.emitVarInt(numberingState.getNumber(prop));
+ scratch.clear();
+ llvm::raw_svector_ostream os(scratch);
+ sizeEmitter.writeTo(os);
+ return emit(scratch);
+ }
+
+ EncodingEmitter emitter;
+ DialectWriter propertiesWriter(config.bytecodeVersion, emitter,
+ numberingState, stringSection);
+ auto iface = cast<BytecodeOpInterface>(op);
+ iface.writeProperties(propertiesWriter);
+ scratch.clear();
+ llvm::raw_svector_ostream os(scratch);
+ emitter.writeTo(os);
+ return emit(scratch);
+ }
+
+ /// Write the current set of properties to the given emitter.
+ void write(EncodingEmitter &emitter) {
+ emitter.emitVarInt(propertiesStorage.size());
+ if (propertiesStorage.empty())
+ return;
+ for (const auto &storage : propertiesStorage) {
+ if (storage.empty()) {
+ emitter.emitBytes(ArrayRef<uint8_t>());
+ continue;
+ }
+ emitter.emitBytes(ArrayRef(reinterpret_cast<const uint8_t *>(&storage[0]),
+ storage.size()));
+ }
+ }
+
+private:
+ /// Emit raw data and returns the offset in the internal buffer.
+ /// Data are deduplicated and will be copied in the internal buffer only if
+ /// they don't exist there already.
+ ssize_t emit(ArrayRef<char> rawProperties) {
+ // Populate a scratch buffer with the properties size.
+ SmallVector<char> sizeScratch;
+ {
+ EncodingEmitter sizeEmitter;
+ sizeEmitter.emitVarInt(rawProperties.size());
+ llvm::raw_svector_ostream os(sizeScratch);
+ sizeEmitter.writeTo(os);
+ }
+ // Append a new storage to the table now.
+ size_t index = propertiesStorage.size();
+ propertiesStorage.emplace_back();
+ std::vector<char> &newStorage = propertiesStorage.back();
+ size_t propertiesSize = sizeScratch.size() + rawProperties.size();
+ newStorage.reserve(propertiesSize);
+ newStorage.insert(newStorage.end(), sizeScratch.begin(), sizeScratch.end());
+ newStorage.insert(newStorage.end(), rawProperties.begin(),
+ rawProperties.end());
+
+ // Try to de-duplicate the new serialized properties.
+ // If the properties is a duplicate, pop it back from the storage.
+ auto inserted = propertiesUniquing.insert(
+ std::make_pair(ArrayRef<char>(newStorage), index));
+ if (!inserted.second)
+ propertiesStorage.pop_back();
+ return inserted.first->getSecond();
+ }
+
+ /// Storage for properties.
+ std::vector<std::vector<char>> propertiesStorage;
+ SmallVector<char> scratch;
+ DenseMap<ArrayRef<char>, int64_t> propertiesUniquing;
+ IRNumberingState &numberingState;
+ StringSectionBuilder &stringSection;
+ const BytecodeWriterConfig::Impl &config;
+};
+} // namespace
+
/// A simple raw_ostream wrapper around a EncodingEmitter. This removes the need
/// to go through an intermediate buffer when interacting with code that wants a
/// raw_ostream.
@@ -435,11 +554,12 @@ void EncodingEmitter::emitMultiByteVarInt(uint64_t value) {
namespace {
class BytecodeWriter {
public:
- BytecodeWriter(Operation *op, const BytecodeWriterConfig::Impl &config)
- : numberingState(op), config(config) {}
+ BytecodeWriter(Operation *op, const BytecodeWriterConfig &config)
+ : numberingState(op, config), config(config.getImpl()),
+ propertiesSection(numberingState, stringSection, config.getImpl()) {}
/// Write the bytecode for the given root operation.
- void write(Operation *rootOp, raw_ostream &os);
+ LogicalResult write(Operation *rootOp, raw_ostream &os);
private:
//===--------------------------------------------------------------------===//
@@ -455,10 +575,10 @@ class BytecodeWriter {
//===--------------------------------------------------------------------===//
// Operations
- void writeBlock(EncodingEmitter &emitter, Block *block);
- void writeOp(EncodingEmitter &emitter, Operation *op);
- void writeRegion(EncodingEmitter &emitter, Region *region);
- void writeIRSection(EncodingEmitter &emitter, Operation *op);
+ LogicalResult writeBlock(EncodingEmitter &emitter, Block *block);
+ LogicalResult writeOp(EncodingEmitter &emitter, Operation *op);
+ LogicalResult writeRegion(EncodingEmitter &emitter, Region *region);
+ LogicalResult writeIRSection(EncodingEmitter &emitter, Operation *op);
//===--------------------------------------------------------------------===//
// Resources
@@ -470,6 +590,11 @@ class BytecodeWriter {
void writeStringSection(EncodingEmitter &emitter);
+ //===--------------------------------------------------------------------===//
+ // Properties
+
+ void writePropertiesSection(EncodingEmitter &emitter);
+
//===--------------------------------------------------------------------===//
// Helpers
@@ -487,10 +612,13 @@ class BytecodeWriter {
/// Configuration dictating bytecode emission.
const BytecodeWriterConfig::Impl &config;
+
+ /// Storage for the properties section
+ PropertiesSectionBuilder propertiesSection;
};
} // namespace
-void BytecodeWriter::write(Operation *rootOp, raw_ostream &os) {
+LogicalResult BytecodeWriter::write(Operation *rootOp, raw_ostream &os) {
EncodingEmitter emitter;
// Emit the bytecode file header. This is how we identify the output as a
@@ -510,7 +638,8 @@ void BytecodeWriter::write(Operation *rootOp, raw_ostream &os) {
writeAttrTypeSection(emitter);
// Emit the IR section.
- writeIRSection(emitter, rootOp);
+ if (failed(writeIRSection(emitter, rootOp)))
+ return failure();
// Emit the resources section.
writeResourceSection(rootOp, emitter);
@@ -518,8 +647,13 @@ void BytecodeWriter::write(Operation *rootOp, raw_ostream &os) {
// Emit the string section.
writeStringSection(emitter);
+ // Emit the properties section.
+ writePropertiesSection(emitter);
+
// Write the generated bytecode to the provided output stream.
emitter.writeTo(os);
+
+ return success();
}
//===----------------------------------------------------------------------===//
@@ -590,7 +724,11 @@ void BytecodeWriter::writeDialectSection(EncodingEmitter &emitter) {
// Emit the referenced operation names grouped by dialect.
auto emitOpName = [&](OpNameNumbering &name) {
- dialectEmitter.emitVarInt(stringSection.insert(name.name.stripDialect()));
+ size_t stringId = stringSection.insert(name.name.stripDialect());
+ if (config.bytecodeVersion < 4)
+ dialectEmitter.emitVarInt(stringId);
+ else
+ dialectEmitter.emitVarIntWithFlag(stringId, name.name.isRegistered());
};
writeDialectGrouping(dialectEmitter, numberingState.getOpNames(), emitOpName);
@@ -659,7 +797,8 @@ void BytecodeWriter::writeAttrTypeSection(EncodingEmitter &emitter) {
//===----------------------------------------------------------------------===//
// Operations
-void BytecodeWriter::writeBlock(EncodingEmitter &emitter, Block *block) {
+LogicalResult BytecodeWriter::writeBlock(EncodingEmitter &emitter,
+ Block *block) {
ArrayRef<BlockArgument> args = block->getArguments();
bool hasArgs = !args.empty();
@@ -696,10 +835,12 @@ void BytecodeWriter::writeBlock(EncodingEmitter &emitter, Block *block) {
// Emit the operations within the block.
for (Operation &op : *block)
- writeOp(emitter, &op);
+ if (failed(writeOp(emitter, &op)))
+ return failure();
+ return success();
}
-void BytecodeWriter::writeOp(EncodingEmitter &emitter, Operation *op) {
+LogicalResult BytecodeWriter::writeOp(EncodingEmitter &emitter, Operation *op) {
emitter.emitVarInt(numberingState.getNumber(op->getName()));
// Emit a mask for the operation components. We need to fill this in later
@@ -713,10 +854,24 @@ void BytecodeWriter::writeOp(EncodingEmitter &emitter, Operation *op) {
emitter.emitVarInt(numberingState.getNumber(op->getLoc()));
// Emit the attributes of this operation.
- DictionaryAttr attrs = op->getAttrDictionary();
+ DictionaryAttr attrs = op->getDiscardableAttrDictionary();
+ // Allow deployment to version <4 by merging inherent attribute with the
+ // discardable ones. We should fail if there are any conflicts.
+ if (config.bytecodeVersion < 4)
+ attrs = op->getAttrDictionary();
if (!attrs.empty()) {
opEncodingMask |= bytecode::OpEncodingMask::kHasAttrs;
- emitter.emitVarInt(numberingState.getNumber(op->getAttrDictionary()));
+ emitter.emitVarInt(numberingState.getNumber(attrs));
+ }
+
+ // Emit the properties of this operation, for now we still support deployment
+ // to version <4.
+ if (config.bytecodeVersion >= 4) {
+ std::optional<ssize_t> propertiesId = propertiesSection.emit(op);
+ if (propertiesId.has_value()) {
+ opEncodingMask |= bytecode::OpEncodingMask::kHasProperties;
+ emitter.emitVarInt(*propertiesId);
+ }
}
// Emit the result types of the operation.
@@ -768,15 +923,18 @@ void BytecodeWriter::writeOp(EncodingEmitter &emitter, Operation *op) {
// If the region is not isolated from above, or we are emitting bytecode
// targeting version <2, we don't use a section.
if (!isIsolatedFromAbove || config.bytecodeVersion < 2) {
- writeRegion(emitter, ®ion);
+ if (failed(writeRegion(emitter, ®ion)))
+ return failure();
continue;
}
EncodingEmitter regionEmitter;
- writeRegion(regionEmitter, ®ion);
+ if (failed(writeRegion(regionEmitter, ®ion)))
+ return failure();
emitter.emitSection(bytecode::Section::kIR, std::move(regionEmitter));
}
}
+ return success();
}
void BytecodeWriter::writeUseListOrders(EncodingEmitter &emitter,
@@ -867,11 +1025,14 @@ void BytecodeWriter::writeUseListOrders(EncodingEmitter &emitter,
}
}
-void BytecodeWriter::writeRegion(EncodingEmitter &emitter, Region *region) {
+LogicalResult BytecodeWriter::writeRegion(EncodingEmitter &emitter,
+ Region *region) {
// If the region is empty, we only need to emit the number of blocks (which is
// zero).
- if (region->empty())
- return emitter.emitVarInt(/*numBlocks*/ 0);
+ if (region->empty()) {
+ emitter.emitVarInt(/*numBlocks*/ 0);
+ return success();
+ }
// Emit the number of blocks and values within the region.
unsigned numBlocks, numValues;
@@ -881,10 +1042,13 @@ void BytecodeWriter::writeRegion(EncodingEmitter &emitter, Region *region) {
// Emit the blocks within the region.
for (Block &block : *region)
- writeBlock(emitter, &block);
+ if (failed(writeBlock(emitter, &block)))
+ return failure();
+ return success();
}
-void BytecodeWriter::writeIRSection(EncodingEmitter &emitter, Operation *op) {
+LogicalResult BytecodeWriter::writeIRSection(EncodingEmitter &emitter,
+ Operation *op) {
EncodingEmitter irEmitter;
// Write the IR section the same way as a block with no arguments. Note that
@@ -893,9 +1057,11 @@ void BytecodeWriter::writeIRSection(EncodingEmitter &emitter, Operation *op) {
irEmitter.emitVarIntWithFlag(/*numOps*/ 1, /*hasArgs*/ false);
// Emit the operations.
- writeOp(irEmitter, op);
+ if (failed(writeOp(irEmitter, op)))
+ return failure();
emitter.emitSection(bytecode::Section::kIR, std::move(irEmitter));
+ return success();
}
//===----------------------------------------------------------------------===//
@@ -1011,14 +1177,22 @@ void BytecodeWriter::writeStringSection(EncodingEmitter &emitter) {
emitter.emitSection(bytecode::Section::kString, std::move(stringEmitter));
}
+//===----------------------------------------------------------------------===//
+// Properties
+
+void BytecodeWriter::writePropertiesSection(EncodingEmitter &emitter) {
+ EncodingEmitter propertiesEmitter;
+ propertiesSection.write(propertiesEmitter);
+ emitter.emitSection(bytecode::Section::kProperties,
+ std::move(propertiesEmitter));
+}
+
//===----------------------------------------------------------------------===//
// Entry Points
//===----------------------------------------------------------------------===//
LogicalResult mlir::writeBytecodeToFile(Operation *op, raw_ostream &os,
const BytecodeWriterConfig &config) {
- BytecodeWriter writer(op, config.getImpl());
- writer.write(op, os);
- // Currently there is no failure case.
- return success();
+ BytecodeWriter writer(op, config);
+ return writer.write(op, os);
}
diff --git a/mlir/lib/Bytecode/Writer/CMakeLists.txt b/mlir/lib/Bytecode/Writer/CMakeLists.txt
index 7d260568249a0..45d7f2158097b 100644
--- a/mlir/lib/Bytecode/Writer/CMakeLists.txt
+++ b/mlir/lib/Bytecode/Writer/CMakeLists.txt
@@ -8,4 +8,5 @@ add_mlir_library(MLIRBytecodeWriter
LINK_LIBS PUBLIC
MLIRIR
MLIRSupport
+ MLIRBytecodeOpInterface
)
diff --git a/mlir/lib/Bytecode/Writer/IRNumbering.cpp b/mlir/lib/Bytecode/Writer/IRNumbering.cpp
index 129437cf0245f..1829a42c943bc 100644
--- a/mlir/lib/Bytecode/Writer/IRNumbering.cpp
+++ b/mlir/lib/Bytecode/Writer/IRNumbering.cpp
@@ -8,6 +8,7 @@
#include "IRNumbering.h"
#include "mlir/Bytecode/BytecodeImplementation.h"
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/AsmState.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"
@@ -24,6 +25,10 @@ struct IRNumberingState::NumberingDialectWriter : public DialectBytecodeWriter {
NumberingDialectWriter(IRNumberingState &state) : state(state) {}
void writeAttribute(Attribute attr) override { state.number(attr); }
+ void writeOptionalAttribute(Attribute attr) override {
+ if (attr)
+ state.number(attr);
+ }
void writeType(Type type) override { state.number(type); }
void writeResourceHandle(const AsmDialectResourceHandle &resource) override {
state.number(resource.getDialect(), resource);
@@ -106,7 +111,9 @@ static void groupByDialectPerByte(T range) {
value->number = idx;
}
-IRNumberingState::IRNumberingState(Operation *op) {
+IRNumberingState::IRNumberingState(Operation *op,
+ const BytecodeWriterConfig &config)
+ : config(config) {
// Compute a global operation ID numbering according to the pre-order walk of
// the IR. This is used as reference to construct use-list orders.
unsigned operationID = 0;
@@ -276,10 +283,29 @@ void IRNumberingState::number(Operation &op) {
}
// Only number the operation's dictionary if it isn't empty.
- DictionaryAttr dictAttr = op.getAttrDictionary();
+ DictionaryAttr dictAttr = op.getDiscardableAttrDictionary();
+ if (config.getDesiredBytecodeVersion() < 4)
+ dictAttr = op.getAttrDictionary();
if (!dictAttr.empty())
number(dictAttr);
+ // Visit the operation properties (if any) to make sure referenced attributes
+ // are numbered.
+ if (config.getDesiredBytecodeVersion() >= 4 &&
+ op.getPropertiesStorageSize()) {
+ if (op.isRegistered()) {
+ // Operation that have properties *must* implement this interface.
+ auto iface = cast<BytecodeOpInterface>(op);
+ NumberingDialectWriter writer(*this);
+ iface.writeProperties(writer);
+ } else {
+ // Unregistered op are storing properties as an optional attribute.
+ Attribute prop = *op.getPropertiesStorage().as<Attribute *>();
+ if (prop)
+ number(prop);
+ }
+ }
+
number(op.getLoc());
}
diff --git a/mlir/lib/Bytecode/Writer/IRNumbering.h b/mlir/lib/Bytecode/Writer/IRNumbering.h
index 91f0be05b36d3..329ca2db8a80a 100644
--- a/mlir/lib/Bytecode/Writer/IRNumbering.h
+++ b/mlir/lib/Bytecode/Writer/IRNumbering.h
@@ -18,6 +18,8 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/CodeGen/NonRelocatableStringpool.h"
+#include <cstdint>
namespace mlir {
class BytecodeDialectInterface;
@@ -133,7 +135,7 @@ struct DialectNumbering {
/// emission.
class IRNumberingState {
public:
- IRNumberingState(Operation *op);
+ IRNumberingState(Operation *op, const BytecodeWriterConfig &config);
/// Return the numbered dialects.
auto getDialects() {
@@ -241,6 +243,9 @@ class IRNumberingState {
/// The next value ID to assign when numbering.
unsigned nextValueID = 0;
+
+ // Configuration: useful to query the required version to emit.
+ const BytecodeWriterConfig &config;
};
} // namespace detail
} // namespace bytecode
diff --git a/mlir/lib/TableGen/Property.cpp b/mlir/lib/TableGen/Property.cpp
index 966c65da16788..b0bea43dd5fda 100644
--- a/mlir/lib/TableGen/Property.cpp
+++ b/mlir/lib/TableGen/Property.cpp
@@ -72,6 +72,16 @@ StringRef Property::getConvertFromAttributeCall() const {
return getValueAsString(init);
}
+StringRef Property::getReadFromMlirBytecodeCall() const {
+ const auto *init = def->getValueInit("readFromMlirBytecode");
+ return getValueAsString(init);
+}
+
+StringRef Property::getWriteToMlirBytecodeCall() const {
+ const auto *init = def->getValueInit("writeToMlirBytecode");
+ return getValueAsString(init);
+}
+
StringRef Property::getHashPropertyCall() const {
return getValueAsString(def->getValueInit("hashProperty"));
}
diff --git a/mlir/test/Bytecode/invalid/invalid-structure.mlir b/mlir/test/Bytecode/invalid/invalid-structure.mlir
index 1d2ed4833083e..1bd4ac4eabbbb 100644
--- a/mlir/test/Bytecode/invalid/invalid-structure.mlir
+++ b/mlir/test/Bytecode/invalid/invalid-structure.mlir
@@ -9,7 +9,7 @@
//===--------------------------------------------------------------------===//
// RUN: not mlir-opt %S/invalid-structure-version.mlirbc 2>&1 | FileCheck %s --check-prefix=VERSION
-// VERSION: bytecode version 127 is newer than the current version
+// VERSION: bytecode version 127 is newer than the current version {{[0-9]+}}
//===--------------------------------------------------------------------===//
// Producer
diff --git a/mlir/test/lib/Dialect/Test/TestDialect.cpp b/mlir/test/lib/Dialect/Test/TestDialect.cpp
index 715c77b9a3963..d167d0274aad6 100644
--- a/mlir/test/lib/Dialect/Test/TestDialect.cpp
+++ b/mlir/test/lib/Dialect/Test/TestDialect.cpp
@@ -28,12 +28,14 @@
#include "mlir/IR/Verifier.h"
#include "mlir/Interfaces/InferIntRangeInterface.h"
#include "mlir/Reducer/ReductionPatternInterface.h"
+#include "mlir/Support/LogicalResult.h"
#include "mlir/Transforms/FoldUtils.h"
#include "mlir/Transforms/InliningUtils.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include <cstdint>
#include <numeric>
#include <optional>
@@ -62,6 +64,44 @@ llvm::hash_code MyPropStruct::hash() const {
return hash_value(StringRef(content));
}
+static LogicalResult readFromMlirBytecode(DialectBytecodeReader &reader,
+ MyPropStruct &prop) {
+ StringRef str;
+ if (failed(reader.readString(str)))
+ return failure();
+ prop.content = str.str();
+ return success();
+}
+
+static void writeToMlirBytecode(::mlir::DialectBytecodeWriter &writer,
+ MyPropStruct &prop) {
+ writer.writeOwnedString(prop.content);
+}
+
+static LogicalResult readFromMlirBytecode(DialectBytecodeReader &reader,
+ MutableArrayRef<int64_t> prop) {
+ uint64_t size;
+ if (failed(reader.readVarInt(size)))
+ return failure();
+ if (size != prop.size())
+ return reader.emitError("array size mismach when reading properties: ")
+ << size << " vs expected " << prop.size();
+ for (auto &elt : prop) {
+ uint64_t value;
+ if (failed(reader.readVarInt(value)))
+ return failure();
+ elt = value;
+ }
+ return success();
+}
+
+static void writeToMlirBytecode(::mlir::DialectBytecodeWriter &writer,
+ ArrayRef<int64_t> prop) {
+ writer.writeVarInt(prop.size());
+ for (auto elt : prop)
+ writer.writeVarInt(elt);
+}
+
static LogicalResult setPropertiesFromAttribute(PropertiesWithCustomPrint &prop,
Attribute attr,
InFlightDiagnostic *diagnostic);
diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index dd9e62b03b89d..cc53425df8339 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -3324,7 +3324,7 @@ def TestVersionedOpB : TEST_Op<"versionedB"> {
def TestOpWithProperties : TEST_Op<"with_properties"> {
let assemblyFormat = "prop-dict attr-dict";
let arguments = (ins
- Property<"int64_t">:$a,
+ IntProperty<"int64_t">:$a,
StrAttr:$b, // Attributes can directly be used here.
ArrayProperty<"int64_t", 4>:$array // example of an array
);
@@ -3369,8 +3369,31 @@ def TestOpWithNiceProperties : TEST_Op<"with_nice_properties"> {
const Properties &prop);
static ::mlir::ParseResult parseProperties(::mlir::OpAsmParser &parser,
::mlir::OperationState &result);
+ static ::mlir::LogicalResult readFromMlirBytecode(
+ ::mlir::DialectBytecodeReader &,
+ test::PropertiesWithCustomPrint &prop);
+ static void writeToMlirBytecode(
+ ::mlir::DialectBytecodeWriter &,
+ const test::PropertiesWithCustomPrint &prop);
}];
let extraClassDefinition = [{
+ ::mlir::LogicalResult TestOpWithNiceProperties::readFromMlirBytecode(
+ ::mlir::DialectBytecodeReader &reader,
+ test::PropertiesWithCustomPrint &prop) {
+ StringRef label;
+ uint64_t value;
+ if (failed(reader.readString(label)) || failed(reader.readVarInt(value)))
+ return failure();
+ prop.label = std::make_shared<std::string>(label.str());
+ prop.value = value;
+ return success();
+ }
+ void TestOpWithNiceProperties::writeToMlirBytecode(
+ ::mlir::DialectBytecodeWriter &writer,
+ const test::PropertiesWithCustomPrint &prop) {
+ writer.writeOwnedString(*prop.label);
+ writer.writeVarInt(prop.value);
+ }
void TestOpWithNiceProperties::printProperties(::mlir::MLIRContext *ctx,
::mlir::OpAsmPrinter &p, const Properties &prop) {
customPrintProperties(p, prop.prop);
diff --git a/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.h b/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.h
index b7ebc9baf94c0..95950e4c5af1f 100644
--- a/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.h
+++ b/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.h
@@ -14,6 +14,7 @@
#ifndef MLIR_TESTTRANSFORMDIALECTEXTENSION_H
#define MLIR_TESTTRANSFORMDIALECTEXTENSION_H
+#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/Dialect/PDL/IR/PDLTypes.h"
#include "mlir/Dialect/Transform/IR/MatchInterfaces.h"
#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index c287f5254c1f7..f7dec4526b021 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1103,6 +1103,21 @@ void OpEmitter::genPropertiesSupport() {
"getDiag"))
->body();
+ auto &readPropertiesMethod =
+ opClass
+ .addStaticMethod(
+ "::mlir::LogicalResult", "readProperties",
+ MethodParameter("::mlir::DialectBytecodeReader &", "reader"),
+ MethodParameter("::mlir::OperationState &", "state"))
+ ->body();
+
+ auto &writePropertiesMethod =
+ opClass
+ .addMethod(
+ "void", "writeProperties",
+ MethodParameter("::mlir::DialectBytecodeWriter &", "writer"))
+ ->body();
+
opClass.declare<UsingDeclaration>("Properties", "FoldAdaptor::Properties");
// Convert the property to the attribute form.
@@ -1304,6 +1319,66 @@ void OpEmitter::genPropertiesSupport() {
}
}
verifyInherentAttrsMethod << " return ::mlir::success();";
+
+ // Populate bytecode serialization logic.
+ readPropertiesMethod
+ << " auto &prop = state.getOrAddProperties<Properties>(); (void)prop;";
+ writePropertiesMethod << " auto &prop = getProperties(); (void)prop;\n";
+ for (const auto &attrOrProp : attrOrProperties) {
+ if (const auto *namedProperty =
+ attrOrProp.dyn_cast<const NamedProperty *>()) {
+ StringRef name = namedProperty->name;
+ FmtContext fctx;
+ fctx.addSubst("_reader", "reader")
+ .addSubst("_writer", "writer")
+ .addSubst("_storage", propertyStorage);
+ readPropertiesMethod << formatv(
+ R"(
+ {{
+ auto &propStorage = prop.{0};
+ auto readProp = [&]() {
+ {1};
+ return ::mlir::success();
+ };
+ if (failed(readProp()))
+ return ::mlir::failure();
+ }
+)",
+ name,
+ tgfmt(namedProperty->prop.getReadFromMlirBytecodeCall(), &fctx));
+ writePropertiesMethod << formatv(
+ R"(
+ {{
+ auto &propStorage = prop.{0};
+ {1};
+ }
+)",
+ name, tgfmt(namedProperty->prop.getWriteToMlirBytecodeCall(), &fctx));
+ continue;
+ }
+ const auto *namedAttr = attrOrProp.dyn_cast<const AttributeMetadata *>();
+ StringRef name = namedAttr->attrName;
+ if (namedAttr->isRequired) {
+ readPropertiesMethod << formatv(R"(
+ if (failed(reader.readAttribute(prop.{0})))
+ return failure();
+)",
+ name);
+ writePropertiesMethod
+ << formatv(" writer.writeAttribute(prop.{0});\n", name);
+ } else {
+ readPropertiesMethod << formatv(R"(
+ if (failed(reader.readOptionalAttribute(prop.{0})))
+ return failure();
+)",
+ name);
+ writePropertiesMethod << formatv(R"(
+ writer.writeOptionalAttribute(prop.{0});
+)",
+ name);
+ }
+ }
+ readPropertiesMethod << " return success();";
}
void OpEmitter::genAttrGetters() {
@@ -3300,6 +3375,9 @@ void OpEmitter::genTraits() {
// native/interface traits and after all the traits with `StructuralOpTrait`.
opClass.addTrait("::mlir::OpTrait::OpInvariants");
+ if (emitHelper.hasProperties())
+ opClass.addTrait("::mlir::BytecodeOpInterface::Trait");
+
// Add the native and interface traits.
for (const auto &trait : op.getTraits()) {
if (auto *opTrait = dyn_cast<tblgen::NativeTrait>(&trait)) {
More information about the Mlir-commits
mailing list