MLIR  17.0.0git
BytecodeImplementation.h
Go to the documentation of this file.
1 //===- BytecodeImplementation.h - MLIR Bytecode Implementation --*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This header defines various interfaces and utilities necessary for dialects
10 // to hook into bytecode serialization.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_BYTECODE_BYTECODEIMPLEMENTATION_H
15 #define MLIR_BYTECODE_BYTECODEIMPLEMENTATION_H
16 
17 #include "mlir/IR/Attributes.h"
18 #include "mlir/IR/Diagnostics.h"
19 #include "mlir/IR/Dialect.h"
23 #include "llvm/ADT/Twine.h"
24 
25 namespace mlir {
26 //===----------------------------------------------------------------------===//
27 // DialectBytecodeReader
28 //===----------------------------------------------------------------------===//
29 
30 /// This class defines a virtual interface for reading a bytecode stream,
31 /// providing hooks into the bytecode reader. As such, this class should only be
32 /// derived and defined by the main bytecode reader, users (i.e. dialects)
33 /// should generally only interact with this class via the
34 /// BytecodeDialectInterface below.
36 public:
37  virtual ~DialectBytecodeReader() = default;
38 
39  /// Emit an error to the reader.
40  virtual InFlightDiagnostic emitError(const Twine &msg = {}) = 0;
41 
42  /// Read out a list of elements, invoking the provided callback for each
43  /// element. The callback function may be in any of the following forms:
44  /// * LogicalResult(T &)
45  /// * FailureOr<T>()
46  template <typename T, typename CallbackFn>
47  LogicalResult readList(SmallVectorImpl<T> &result, CallbackFn &&callback) {
48  uint64_t size;
49  if (failed(readVarInt(size)))
50  return failure();
51  result.reserve(size);
52 
53  for (uint64_t i = 0; i < size; ++i) {
54  // Check if the callback uses FailureOr, or populates the result by
55  // reference.
56  if constexpr (llvm::function_traits<std::decay_t<CallbackFn>>::num_args) {
57  T element = {};
58  if (failed(callback(element)))
59  return failure();
60  result.emplace_back(std::move(element));
61  } else {
62  FailureOr<T> element = callback();
63  if (failed(element))
64  return failure();
65  result.emplace_back(std::move(*element));
66  }
67  }
68  return success();
69  }
70 
71  //===--------------------------------------------------------------------===//
72  // IR
73  //===--------------------------------------------------------------------===//
74 
75  /// Read a reference to the given attribute.
76  virtual LogicalResult readAttribute(Attribute &result) = 0;
77  template <typename T>
79  return readList(attrs, [this](T &attr) { return readAttribute(attr); });
80  }
81  template <typename T>
83  Attribute baseResult;
84  if (failed(readAttribute(baseResult)))
85  return failure();
86  if ((result = baseResult.dyn_cast<T>()))
87  return success();
88  return emitError() << "expected " << llvm::getTypeName<T>()
89  << ", but got: " << baseResult;
90  }
91 
92  /// Read a reference to the given type.
93  virtual LogicalResult readType(Type &result) = 0;
94  template <typename T>
96  return readList(types, [this](T &type) { return readType(type); });
97  }
98  template <typename T>
99  LogicalResult readType(T &result) {
100  Type baseResult;
101  if (failed(readType(baseResult)))
102  return failure();
103  if ((result = baseResult.dyn_cast<T>()))
104  return success();
105  return emitError() << "expected " << llvm::getTypeName<T>()
106  << ", but got: " << baseResult;
107  }
108 
109  /// Read a handle to a dialect resource.
110  template <typename ResourceT>
113  if (failed(handle))
114  return failure();
115  if (auto *result = dyn_cast<ResourceT>(&*handle))
116  return std::move(*result);
117  return emitError() << "provided resource handle differs from the "
118  "expected resource type";
119  }
120 
121  //===--------------------------------------------------------------------===//
122  // Primitives
123  //===--------------------------------------------------------------------===//
124 
125  /// Read a variable width integer.
126  virtual LogicalResult readVarInt(uint64_t &result) = 0;
127 
128  /// Read a signed variable width integer.
129  virtual LogicalResult readSignedVarInt(int64_t &result) = 0;
131  return readList(result,
132  [this](int64_t &value) { return readSignedVarInt(value); });
133  }
134 
135  /// Read an APInt that is known to have been encoded with the given width.
136  virtual FailureOr<APInt> readAPIntWithKnownWidth(unsigned bitWidth) = 0;
137 
138  /// Read an APFloat that is known to have been encoded with the given
139  /// semantics.
140  virtual FailureOr<APFloat>
141  readAPFloatWithKnownSemantics(const llvm::fltSemantics &semantics) = 0;
142 
143  /// Read a string from the bytecode.
144  virtual LogicalResult readString(StringRef &result) = 0;
145 
146  /// Read a blob from the bytecode.
147  virtual LogicalResult readBlob(ArrayRef<char> &result) = 0;
148 
149 private:
150  /// Read a handle to a dialect resource.
152 };
153 
154 //===----------------------------------------------------------------------===//
155 // DialectBytecodeWriter
156 //===----------------------------------------------------------------------===//
157 
158 /// This class defines a virtual interface for writing to a bytecode stream,
159 /// providing hooks into the bytecode writer. As such, this class should only be
160 /// derived and defined by the main bytecode writer, users (i.e. dialects)
161 /// should generally only interact with this class via the
162 /// BytecodeDialectInterface below.
164 public:
165  virtual ~DialectBytecodeWriter() = default;
166 
167  //===--------------------------------------------------------------------===//
168  // IR
169  //===--------------------------------------------------------------------===//
170 
171  /// Write out a list of elements, invoking the provided callback for each
172  /// element.
173  template <typename RangeT, typename CallbackFn>
174  void writeList(RangeT &&range, CallbackFn &&callback) {
175  writeVarInt(llvm::size(range));
176  for (auto &element : range)
177  callback(element);
178  }
179 
180  /// Write a reference to the given attribute.
181  virtual void writeAttribute(Attribute attr) = 0;
182  template <typename T>
184  writeList(attrs, [this](T attr) { writeAttribute(attr); });
185  }
186 
187  /// Write a reference to the given type.
188  virtual void writeType(Type type) = 0;
189  template <typename T>
190  void writeTypes(ArrayRef<T> types) {
191  writeList(types, [this](T type) { writeType(type); });
192  }
193 
194  /// Write the given handle to a dialect resource.
195  virtual void
197 
198  //===--------------------------------------------------------------------===//
199  // Primitives
200  //===--------------------------------------------------------------------===//
201 
202  /// Write a variable width integer to the output stream. This should be the
203  /// preferred method for emitting integers whenever possible.
204  virtual void writeVarInt(uint64_t value) = 0;
205 
206  /// Write a signed variable width integer to the output stream. This should be
207  /// the preferred method for emitting signed integers whenever possible.
208  virtual void writeSignedVarInt(int64_t value) = 0;
210  writeList(value, [this](int64_t value) { writeSignedVarInt(value); });
211  }
212 
213  /// Write an APInt to the bytecode stream whose bitwidth will be known
214  /// externally at read time. This method is useful for encoding APInt values
215  /// when the width is known via external means, such as via a type. This
216  /// method should generally only be invoked if you need an APInt, otherwise
217  /// use the varint methods above. APInt values are generally encoded using
218  /// zigzag encoding, to enable more efficient encodings for negative values.
219  virtual void writeAPIntWithKnownWidth(const APInt &value) = 0;
220 
221  /// Write an APFloat to the bytecode stream whose semantics will be known
222  /// externally at read time. This method is useful for encoding APFloat values
223  /// when the semantics are known via external means, such as via a type.
224  virtual void writeAPFloatWithKnownSemantics(const APFloat &value) = 0;
225 
226  /// Write a string to the bytecode, which is owned by the caller and is
227  /// guaranteed to not die before the end of the bytecode process. This should
228  /// only be called if such a guarantee can be made, such as when the string is
229  /// owned by an attribute or type.
230  virtual void writeOwnedString(StringRef str) = 0;
231 
232  /// Write a blob to the bytecode, which is owned by the caller and is
233  /// guaranteed to not die before the end of the bytecode process. The blob is
234  /// written as-is, with no additional compression or compaction.
235  virtual void writeOwnedBlob(ArrayRef<char> blob) = 0;
236 };
237 
238 //===----------------------------------------------------------------------===//
239 // BytecodeDialectInterface
240 //===----------------------------------------------------------------------===//
241 
243  : public DialectInterface::Base<BytecodeDialectInterface> {
244 public:
245  using Base::Base;
246 
247  //===--------------------------------------------------------------------===//
248  // Reading
249  //===--------------------------------------------------------------------===//
250 
251  /// Read an attribute belonging to this dialect from the given reader. This
252  /// method should return null in the case of failure.
254  reader.emitError() << "dialect " << getDialect()->getNamespace()
255  << " does not support reading attributes from bytecode";
256  return Attribute();
257  }
258 
259  /// Read a type belonging to this dialect from the given reader. This method
260  /// should return null in the case of failure.
261  virtual Type readType(DialectBytecodeReader &reader) const {
262  reader.emitError() << "dialect " << getDialect()->getNamespace()
263  << " does not support reading types from bytecode";
264  return Type();
265  }
266 
267  //===--------------------------------------------------------------------===//
268  // Writing
269  //===--------------------------------------------------------------------===//
270 
271  /// Write the given attribute, which belongs to this dialect, to the given
272  /// writer. This method may return failure to indicate that the given
273  /// attribute could not be encoded, in which case the textual format will be
274  /// used to encode this attribute instead.
276  DialectBytecodeWriter &writer) const {
277  return failure();
278  }
279 
280  /// Write the given type, which belongs to this dialect, to the given writer.
281  /// This method may return failure to indicate that the given type could not
282  /// be encoded, in which case the textual format will be used to encode this
283  /// type instead.
285  DialectBytecodeWriter &writer) const {
286  return failure();
287  }
288 };
289 
290 } // namespace mlir
291 
292 #endif // MLIR_BYTECODE_BYTECODEIMPLEMENTATION_H
This class represents an opaque handle to a dialect resource entry.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
U dyn_cast() const
Definition: Attributes.h:169
virtual Type readType(DialectBytecodeReader &reader) const
Read a type belonging to this dialect from the given reader.
virtual Attribute readAttribute(DialectBytecodeReader &reader) const
Read an attribute belonging to this dialect from the given reader.
virtual LogicalResult writeAttribute(Attribute attr, DialectBytecodeWriter &writer) const
Write the given attribute, which belongs to this dialect, to the given writer.
virtual LogicalResult writeType(Type type, DialectBytecodeWriter &writer) const
Write the given type, which belongs to this dialect, to the given writer.
This class defines a virtual interface for reading a bytecode stream, providing hooks into the byteco...
virtual ~DialectBytecodeReader()=default
virtual LogicalResult readBlob(ArrayRef< char > &result)=0
Read a blob from the bytecode.
LogicalResult readAttributes(SmallVectorImpl< T > &attrs)
FailureOr< ResourceT > readResourceHandle()
Read a handle to a dialect resource.
virtual FailureOr< APInt > readAPIntWithKnownWidth(unsigned bitWidth)=0
Read an APInt that is known to have been encoded with the given width.
LogicalResult readTypes(SmallVectorImpl< T > &types)
virtual LogicalResult readVarInt(uint64_t &result)=0
Read a variable width integer.
virtual LogicalResult readType(Type &result)=0
Read a reference to the given type.
LogicalResult readType(T &result)
LogicalResult readSignedVarInts(SmallVectorImpl< int64_t > &result)
virtual InFlightDiagnostic emitError(const Twine &msg={})=0
Emit an error to the reader.
LogicalResult readAttribute(T &result)
virtual FailureOr< APFloat > readAPFloatWithKnownSemantics(const llvm::fltSemantics &semantics)=0
Read an APFloat that is known to have been encoded with the given semantics.
virtual LogicalResult readString(StringRef &result)=0
Read a string from the bytecode.
virtual LogicalResult readSignedVarInt(int64_t &result)=0
Read a signed variable width integer.
LogicalResult readList(SmallVectorImpl< T > &result, CallbackFn &&callback)
Read out a list of elements, invoking the provided callback for each element.
virtual LogicalResult readAttribute(Attribute &result)=0
Read a reference to the given attribute.
This class defines a virtual interface for writing to a bytecode stream, providing hooks into the byt...
virtual void writeVarInt(uint64_t value)=0
Write a variable width integer to the output stream.
void writeList(RangeT &&range, CallbackFn &&callback)
Write out a list of elements, invoking the provided callback for each element.
virtual void writeType(Type type)=0
Write a reference to the given type.
virtual void writeAPIntWithKnownWidth(const APInt &value)=0
Write an APInt to the bytecode stream whose bitwidth will be known externally at read time.
virtual void writeOwnedBlob(ArrayRef< char > blob)=0
Write a blob to the bytecode, which is owned by the caller and is guaranteed to not die before the en...
virtual void writeAttribute(Attribute attr)=0
Write a reference to the given attribute.
virtual ~DialectBytecodeWriter()=default
void writeAttributes(ArrayRef< T > attrs)
virtual void writeSignedVarInt(int64_t value)=0
Write a signed variable width integer to the output stream.
virtual void writeResourceHandle(const AsmDialectResourceHandle &resource)=0
Write the given handle to a dialect resource.
virtual void writeAPFloatWithKnownSemantics(const APFloat &value)=0
Write an APFloat to the bytecode stream whose semantics will be known externally at read time.
void writeSignedVarInts(ArrayRef< int64_t > value)
virtual void writeOwnedString(StringRef str)=0
Write a string to the bytecode, which is owned by the caller and is guaranteed to not die before the ...
void writeTypes(ArrayRef< T > types)
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
U dyn_cast() const
Definition: Types.h:311
The base class used for all derived interface types.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26