xref: /llvm-project/mlir/lib/Bytecode/Reader/BytecodeReader.cpp (revision b77e40265caf1fc459b1c57ac495bbd48e1f7942)
1f3acb54cSRiver Riddle //===- BytecodeReader.cpp - MLIR Bytecode Reader --------------------------===//
2f3acb54cSRiver Riddle //
3f3acb54cSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f3acb54cSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5f3acb54cSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f3acb54cSRiver Riddle //
7f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
8f3acb54cSRiver Riddle 
9f3acb54cSRiver Riddle #include "mlir/Bytecode/BytecodeReader.h"
10f3acb54cSRiver Riddle #include "mlir/AsmParser/AsmParser.h"
1102c2ecb9SRiver Riddle #include "mlir/Bytecode/BytecodeImplementation.h"
12660f714eSMehdi Amini #include "mlir/Bytecode/BytecodeOpInterface.h"
1361278191SMatteo Franciolini #include "mlir/Bytecode/Encoding.h"
14f3acb54cSRiver Riddle #include "mlir/IR/BuiltinOps.h"
153b0106feSMehdi Amini #include "mlir/IR/Diagnostics.h"
16f3acb54cSRiver Riddle #include "mlir/IR/OpImplementation.h"
17f3acb54cSRiver Riddle #include "mlir/IR/Verifier.h"
183128b310SMehdi Amini #include "mlir/IR/Visitors.h"
193128b310SMehdi Amini #include "mlir/Support/LLVM.h"
20660f714eSMehdi Amini #include "llvm/ADT/ArrayRef.h"
21f3acb54cSRiver Riddle #include "llvm/ADT/ScopeExit.h"
226ab2bcffSRiver Riddle #include "llvm/ADT/StringExtras.h"
23cfd90939SMehdi Amini #include "llvm/ADT/StringRef.h"
24bb0bbed6SUlrich Weigand #include "llvm/Support/Endian.h"
25f3acb54cSRiver Riddle #include "llvm/Support/MemoryBufferRef.h"
2618546ff8SRiver Riddle #include "llvm/Support/SourceMgr.h"
271c8c365dSChristian Sigg 
28660f714eSMehdi Amini #include <cstddef>
293128b310SMehdi Amini #include <list>
303128b310SMehdi Amini #include <memory>
3161278191SMatteo Franciolini #include <numeric>
32b2379415SKazu Hirata #include <optional>
33f3acb54cSRiver Riddle 
34f3acb54cSRiver Riddle #define DEBUG_TYPE "mlir-bytecode-reader"
35f3acb54cSRiver Riddle 
36f3acb54cSRiver Riddle using namespace mlir;
37f3acb54cSRiver Riddle 
38f3acb54cSRiver Riddle /// Stringify the given section ID.
39f3acb54cSRiver Riddle static std::string toString(bytecode::Section::ID sectionID) {
40f3acb54cSRiver Riddle   switch (sectionID) {
41f3acb54cSRiver Riddle   case bytecode::Section::kString:
42f3acb54cSRiver Riddle     return "String (0)";
43f3acb54cSRiver Riddle   case bytecode::Section::kDialect:
44f3acb54cSRiver Riddle     return "Dialect (1)";
45f3acb54cSRiver Riddle   case bytecode::Section::kAttrType:
46f3acb54cSRiver Riddle     return "AttrType (2)";
47f3acb54cSRiver Riddle   case bytecode::Section::kAttrTypeOffset:
48f3acb54cSRiver Riddle     return "AttrTypeOffset (3)";
49f3acb54cSRiver Riddle   case bytecode::Section::kIR:
50f3acb54cSRiver Riddle     return "IR (4)";
516ab2bcffSRiver Riddle   case bytecode::Section::kResource:
526ab2bcffSRiver Riddle     return "Resource (5)";
536ab2bcffSRiver Riddle   case bytecode::Section::kResourceOffset:
546ab2bcffSRiver Riddle     return "ResourceOffset (6)";
550e0b6070SMatteo Franciolini   case bytecode::Section::kDialectVersions:
560e0b6070SMatteo Franciolini     return "DialectVersions (7)";
57660f714eSMehdi Amini   case bytecode::Section::kProperties:
58660f714eSMehdi Amini     return "Properties (8)";
59f3acb54cSRiver Riddle   default:
6093cf0e8aSRiver Riddle     return ("Unknown (" + Twine(static_cast<unsigned>(sectionID)) + ")").str();
61f3acb54cSRiver Riddle   }
62f3acb54cSRiver Riddle }
63f3acb54cSRiver Riddle 
646ab2bcffSRiver Riddle /// Returns true if the given top-level section ID is optional.
65660f714eSMehdi Amini static bool isSectionOptional(bytecode::Section::ID sectionID, int version) {
666ab2bcffSRiver Riddle   switch (sectionID) {
676ab2bcffSRiver Riddle   case bytecode::Section::kString:
686ab2bcffSRiver Riddle   case bytecode::Section::kDialect:
696ab2bcffSRiver Riddle   case bytecode::Section::kAttrType:
706ab2bcffSRiver Riddle   case bytecode::Section::kAttrTypeOffset:
716ab2bcffSRiver Riddle   case bytecode::Section::kIR:
726ab2bcffSRiver Riddle     return false;
736ab2bcffSRiver Riddle   case bytecode::Section::kResource:
746ab2bcffSRiver Riddle   case bytecode::Section::kResourceOffset:
750e0b6070SMatteo Franciolini   case bytecode::Section::kDialectVersions:
766ab2bcffSRiver Riddle     return true;
77660f714eSMehdi Amini   case bytecode::Section::kProperties:
789c1e5587SMehdi Amini     return version < bytecode::kNativePropertiesEncoding;
796ab2bcffSRiver Riddle   default:
806ab2bcffSRiver Riddle     llvm_unreachable("unknown section ID");
816ab2bcffSRiver Riddle   }
826ab2bcffSRiver Riddle }
836ab2bcffSRiver Riddle 
84f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
85f3acb54cSRiver Riddle // EncodingReader
86f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
87f3acb54cSRiver Riddle 
88f3acb54cSRiver Riddle namespace {
89f3acb54cSRiver Riddle class EncodingReader {
90f3acb54cSRiver Riddle public:
91f3acb54cSRiver Riddle   explicit EncodingReader(ArrayRef<uint8_t> contents, Location fileLoc)
921c8c365dSChristian Sigg       : buffer(contents), dataIt(buffer.begin()), fileLoc(fileLoc) {}
93f3acb54cSRiver Riddle   explicit EncodingReader(StringRef contents, Location fileLoc)
94f3acb54cSRiver Riddle       : EncodingReader({reinterpret_cast<const uint8_t *>(contents.data()),
95f3acb54cSRiver Riddle                         contents.size()},
96f3acb54cSRiver Riddle                        fileLoc) {}
97f3acb54cSRiver Riddle 
98f3acb54cSRiver Riddle   /// Returns true if the entire section has been read.
991c8c365dSChristian Sigg   bool empty() const { return dataIt == buffer.end(); }
100f3acb54cSRiver Riddle 
101f3acb54cSRiver Riddle   /// Returns the remaining size of the bytecode.
1021c8c365dSChristian Sigg   size_t size() const { return buffer.end() - dataIt; }
103f3acb54cSRiver Riddle 
1046ab2bcffSRiver Riddle   /// Align the current reader position to the specified alignment.
1056ab2bcffSRiver Riddle   LogicalResult alignTo(unsigned alignment) {
1066ab2bcffSRiver Riddle     if (!llvm::isPowerOf2_32(alignment))
1076ab2bcffSRiver Riddle       return emitError("expected alignment to be a power-of-two");
1086ab2bcffSRiver Riddle 
1091c8c365dSChristian Sigg     auto isUnaligned = [&](const uint8_t *ptr) {
1101c8c365dSChristian Sigg       return ((uintptr_t)ptr & (alignment - 1)) != 0;
1111c8c365dSChristian Sigg     };
1121c8c365dSChristian Sigg 
1136ab2bcffSRiver Riddle     // Shift the reader position to the next alignment boundary.
1141c8c365dSChristian Sigg     while (isUnaligned(dataIt)) {
1156ab2bcffSRiver Riddle       uint8_t padding;
1166ab2bcffSRiver Riddle       if (failed(parseByte(padding)))
1176ab2bcffSRiver Riddle         return failure();
1186ab2bcffSRiver Riddle       if (padding != bytecode::kAlignmentByte) {
1196ab2bcffSRiver Riddle         return emitError("expected alignment byte (0xCB), but got: '0x" +
1206ab2bcffSRiver Riddle                          llvm::utohexstr(padding) + "'");
1216ab2bcffSRiver Riddle       }
1226ab2bcffSRiver Riddle     }
1236ab2bcffSRiver Riddle 
124ae461d8bSbzcheeseman     // Ensure the data iterator is now aligned. This case is unlikely because we
125ae461d8bSbzcheeseman     // *just* went through the effort to align the data iterator.
1261c8c365dSChristian Sigg     if (LLVM_UNLIKELY(isUnaligned(dataIt))) {
127ae461d8bSbzcheeseman       return emitError("expected data iterator aligned to ", alignment,
128ae461d8bSbzcheeseman                        ", but got pointer: '0x" +
129ae461d8bSbzcheeseman                            llvm::utohexstr((uintptr_t)dataIt) + "'");
130ae461d8bSbzcheeseman     }
1316ab2bcffSRiver Riddle 
1326ab2bcffSRiver Riddle     return success();
1336ab2bcffSRiver Riddle   }
1346ab2bcffSRiver Riddle 
135f3acb54cSRiver Riddle   /// Emit an error using the given arguments.
136f3acb54cSRiver Riddle   template <typename... Args>
13702c2ecb9SRiver Riddle   InFlightDiagnostic emitError(Args &&...args) const {
138f3acb54cSRiver Riddle     return ::emitError(fileLoc).append(std::forward<Args>(args)...);
139f3acb54cSRiver Riddle   }
1406ab2bcffSRiver Riddle   InFlightDiagnostic emitError() const { return ::emitError(fileLoc); }
141f3acb54cSRiver Riddle 
142f3acb54cSRiver Riddle   /// Parse a single byte from the stream.
143f3acb54cSRiver Riddle   template <typename T>
144f3acb54cSRiver Riddle   LogicalResult parseByte(T &value) {
145f3acb54cSRiver Riddle     if (empty())
146f3acb54cSRiver Riddle       return emitError("attempting to parse a byte at the end of the bytecode");
147f3acb54cSRiver Riddle     value = static_cast<T>(*dataIt++);
148f3acb54cSRiver Riddle     return success();
149f3acb54cSRiver Riddle   }
150f3acb54cSRiver Riddle   /// Parse a range of bytes of 'length' into the given result.
151f3acb54cSRiver Riddle   LogicalResult parseBytes(size_t length, ArrayRef<uint8_t> &result) {
152f3acb54cSRiver Riddle     if (length > size()) {
153f3acb54cSRiver Riddle       return emitError("attempting to parse ", length, " bytes when only ",
154f3acb54cSRiver Riddle                        size(), " remain");
155f3acb54cSRiver Riddle     }
156f3acb54cSRiver Riddle     result = {dataIt, length};
157f3acb54cSRiver Riddle     dataIt += length;
158f3acb54cSRiver Riddle     return success();
159f3acb54cSRiver Riddle   }
160f3acb54cSRiver Riddle   /// Parse a range of bytes of 'length' into the given result, which can be
161f3acb54cSRiver Riddle   /// assumed to be large enough to hold `length`.
162f3acb54cSRiver Riddle   LogicalResult parseBytes(size_t length, uint8_t *result) {
163f3acb54cSRiver Riddle     if (length > size()) {
164f3acb54cSRiver Riddle       return emitError("attempting to parse ", length, " bytes when only ",
165f3acb54cSRiver Riddle                        size(), " remain");
166f3acb54cSRiver Riddle     }
167f3acb54cSRiver Riddle     memcpy(result, dataIt, length);
168f3acb54cSRiver Riddle     dataIt += length;
169f3acb54cSRiver Riddle     return success();
170f3acb54cSRiver Riddle   }
171f3acb54cSRiver Riddle 
1726ab2bcffSRiver Riddle   /// Parse an aligned blob of data, where the alignment was encoded alongside
1736ab2bcffSRiver Riddle   /// the data.
1746ab2bcffSRiver Riddle   LogicalResult parseBlobAndAlignment(ArrayRef<uint8_t> &data,
1756ab2bcffSRiver Riddle                                       uint64_t &alignment) {
1766ab2bcffSRiver Riddle     uint64_t dataSize;
1776ab2bcffSRiver Riddle     if (failed(parseVarInt(alignment)) || failed(parseVarInt(dataSize)) ||
1786ab2bcffSRiver Riddle         failed(alignTo(alignment)))
1796ab2bcffSRiver Riddle       return failure();
1806ab2bcffSRiver Riddle     return parseBytes(dataSize, data);
1816ab2bcffSRiver Riddle   }
1826ab2bcffSRiver Riddle 
183f3acb54cSRiver Riddle   /// Parse a variable length encoded integer from the byte stream. The first
184f3acb54cSRiver Riddle   /// encoded byte contains a prefix in the low bits indicating the encoded
185f3acb54cSRiver Riddle   /// length of the value. This length prefix is a bit sequence of '0's followed
186f3acb54cSRiver Riddle   /// by a '1'. The number of '0' bits indicate the number of _additional_ bytes
187f3acb54cSRiver Riddle   /// (not including the prefix byte). All remaining bits in the first byte,
188f3acb54cSRiver Riddle   /// along with all of the bits in additional bytes, provide the value of the
189f3acb54cSRiver Riddle   /// integer encoded in little-endian order.
190f3acb54cSRiver Riddle   LogicalResult parseVarInt(uint64_t &result) {
191f3acb54cSRiver Riddle     // Parse the first byte of the encoding, which contains the length prefix.
192f3acb54cSRiver Riddle     if (failed(parseByte(result)))
193f3acb54cSRiver Riddle       return failure();
194f3acb54cSRiver Riddle 
195f3acb54cSRiver Riddle     // Handle the overwhelmingly common case where the value is stored in a
196f3acb54cSRiver Riddle     // single byte. In this case, the first bit is the `1` marker bit.
197f3acb54cSRiver Riddle     if (LLVM_LIKELY(result & 1)) {
198f3acb54cSRiver Riddle       result >>= 1;
199f3acb54cSRiver Riddle       return success();
200f3acb54cSRiver Riddle     }
201f3acb54cSRiver Riddle 
202f3acb54cSRiver Riddle     // Handle the overwhelming uncommon case where the value required all 8
203f3acb54cSRiver Riddle     // bytes (i.e. a really really big number). In this case, the marker byte is
204f3acb54cSRiver Riddle     // all zeros: `00000000`.
205bb0bbed6SUlrich Weigand     if (LLVM_UNLIKELY(result == 0)) {
206bb0bbed6SUlrich Weigand       llvm::support::ulittle64_t resultLE;
207bb0bbed6SUlrich Weigand       if (failed(parseBytes(sizeof(resultLE),
208bb0bbed6SUlrich Weigand                             reinterpret_cast<uint8_t *>(&resultLE))))
209bb0bbed6SUlrich Weigand         return failure();
210bb0bbed6SUlrich Weigand       result = resultLE;
211bb0bbed6SUlrich Weigand       return success();
212bb0bbed6SUlrich Weigand     }
213f3acb54cSRiver Riddle     return parseMultiByteVarInt(result);
214f3acb54cSRiver Riddle   }
215f3acb54cSRiver Riddle 
2162f90764cSRiver Riddle   /// Parse a signed variable length encoded integer from the byte stream. A
2172f90764cSRiver Riddle   /// signed varint is encoded as a normal varint with zigzag encoding applied,
2182f90764cSRiver Riddle   /// i.e. the low bit of the value is used to indicate the sign.
2192f90764cSRiver Riddle   LogicalResult parseSignedVarInt(uint64_t &result) {
2202f90764cSRiver Riddle     if (failed(parseVarInt(result)))
2212f90764cSRiver Riddle       return failure();
2222f90764cSRiver Riddle     // Essentially (but using unsigned): (x >> 1) ^ -(x & 1)
2232f90764cSRiver Riddle     result = (result >> 1) ^ (~(result & 1) + 1);
2242f90764cSRiver Riddle     return success();
2252f90764cSRiver Riddle   }
2262f90764cSRiver Riddle 
227f3acb54cSRiver Riddle   /// Parse a variable length encoded integer whose low bit is used to encode an
228f3acb54cSRiver Riddle   /// unrelated flag, i.e: `(integerValue << 1) | (flag ? 1 : 0)`.
229f3acb54cSRiver Riddle   LogicalResult parseVarIntWithFlag(uint64_t &result, bool &flag) {
230f3acb54cSRiver Riddle     if (failed(parseVarInt(result)))
231f3acb54cSRiver Riddle       return failure();
232f3acb54cSRiver Riddle     flag = result & 1;
233f3acb54cSRiver Riddle     result >>= 1;
234f3acb54cSRiver Riddle     return success();
235f3acb54cSRiver Riddle   }
236f3acb54cSRiver Riddle 
237f3acb54cSRiver Riddle   /// Skip the first `length` bytes within the reader.
238f3acb54cSRiver Riddle   LogicalResult skipBytes(size_t length) {
239f3acb54cSRiver Riddle     if (length > size()) {
240f3acb54cSRiver Riddle       return emitError("attempting to skip ", length, " bytes when only ",
241f3acb54cSRiver Riddle                        size(), " remain");
242f3acb54cSRiver Riddle     }
243f3acb54cSRiver Riddle     dataIt += length;
244f3acb54cSRiver Riddle     return success();
245f3acb54cSRiver Riddle   }
246f3acb54cSRiver Riddle 
247f3acb54cSRiver Riddle   /// Parse a null-terminated string into `result` (without including the NUL
248f3acb54cSRiver Riddle   /// terminator).
249f3acb54cSRiver Riddle   LogicalResult parseNullTerminatedString(StringRef &result) {
250f3acb54cSRiver Riddle     const char *startIt = (const char *)dataIt;
251f3acb54cSRiver Riddle     const char *nulIt = (const char *)memchr(startIt, 0, size());
252f3acb54cSRiver Riddle     if (!nulIt)
253f3acb54cSRiver Riddle       return emitError(
254f3acb54cSRiver Riddle           "malformed null-terminated string, no null character found");
255f3acb54cSRiver Riddle 
256f3acb54cSRiver Riddle     result = StringRef(startIt, nulIt - startIt);
257f3acb54cSRiver Riddle     dataIt = (const uint8_t *)nulIt + 1;
258f3acb54cSRiver Riddle     return success();
259f3acb54cSRiver Riddle   }
260f3acb54cSRiver Riddle 
261f3acb54cSRiver Riddle   /// Parse a section header, placing the kind of section in `sectionID` and the
262f3acb54cSRiver Riddle   /// contents of the section in `sectionData`.
263f3acb54cSRiver Riddle   LogicalResult parseSection(bytecode::Section::ID &sectionID,
264f3acb54cSRiver Riddle                              ArrayRef<uint8_t> &sectionData) {
2656ab2bcffSRiver Riddle     uint8_t sectionIDAndHasAlignment;
26659548fe8SGoran Flegar     uint64_t length;
2676ab2bcffSRiver Riddle     if (failed(parseByte(sectionIDAndHasAlignment)) ||
2686ab2bcffSRiver Riddle         failed(parseVarInt(length)))
269f3acb54cSRiver Riddle       return failure();
2706ab2bcffSRiver Riddle 
2716ab2bcffSRiver Riddle     // Extract the section ID and whether the section is aligned. The high bit
2726ab2bcffSRiver Riddle     // of the ID is the alignment flag.
2736ab2bcffSRiver Riddle     sectionID = static_cast<bytecode::Section::ID>(sectionIDAndHasAlignment &
2746ab2bcffSRiver Riddle                                                    0b01111111);
2756ab2bcffSRiver Riddle     bool hasAlignment = sectionIDAndHasAlignment & 0b10000000;
2766ab2bcffSRiver Riddle 
2776ab2bcffSRiver Riddle     // Check that the section is actually valid before trying to process its
2786ab2bcffSRiver Riddle     // data.
279f3acb54cSRiver Riddle     if (sectionID >= bytecode::Section::kNumSections)
280f3acb54cSRiver Riddle       return emitError("invalid section ID: ", unsigned(sectionID));
281f3acb54cSRiver Riddle 
2826ab2bcffSRiver Riddle     // Process the section alignment if present.
2836ab2bcffSRiver Riddle     if (hasAlignment) {
2846ab2bcffSRiver Riddle       uint64_t alignment;
2856ab2bcffSRiver Riddle       if (failed(parseVarInt(alignment)) || failed(alignTo(alignment)))
2866ab2bcffSRiver Riddle         return failure();
2876ab2bcffSRiver Riddle     }
2886ab2bcffSRiver Riddle 
2896ab2bcffSRiver Riddle     // Parse the actual section data.
29059548fe8SGoran Flegar     return parseBytes(static_cast<size_t>(length), sectionData);
291f3acb54cSRiver Riddle   }
292f3acb54cSRiver Riddle 
2933449e7a8SJacques Pienaar   Location getLoc() const { return fileLoc; }
2943449e7a8SJacques Pienaar 
295f3acb54cSRiver Riddle private:
296f3acb54cSRiver Riddle   /// Parse a variable length encoded integer from the byte stream. This method
297f3acb54cSRiver Riddle   /// is a fallback when the number of bytes used to encode the value is greater
298f3acb54cSRiver Riddle   /// than 1, but less than the max (9). The provided `result` value can be
299f3acb54cSRiver Riddle   /// assumed to already contain the first byte of the value.
300f3acb54cSRiver Riddle   /// NOTE: This method is marked noinline to avoid pessimizing the common case
301f3acb54cSRiver Riddle   /// of single byte encoding.
302f3acb54cSRiver Riddle   LLVM_ATTRIBUTE_NOINLINE LogicalResult parseMultiByteVarInt(uint64_t &result) {
303f3acb54cSRiver Riddle     // Count the number of trailing zeros in the marker byte, this indicates the
304f3acb54cSRiver Riddle     // number of trailing bytes that are part of the value. We use `uint32_t`
305f3acb54cSRiver Riddle     // here because we only care about the first byte, and so that be actually
306f3acb54cSRiver Riddle     // get ctz intrinsic calls when possible (the `uint8_t` overload uses a loop
307f3acb54cSRiver Riddle     // implementation).
30855e2cd16SKazu Hirata     uint32_t numBytes = llvm::countr_zero<uint32_t>(result);
309f3acb54cSRiver Riddle     assert(numBytes > 0 && numBytes <= 7 &&
310f3acb54cSRiver Riddle            "unexpected number of trailing zeros in varint encoding");
311f3acb54cSRiver Riddle 
312f3acb54cSRiver Riddle     // Parse in the remaining bytes of the value.
313bb0bbed6SUlrich Weigand     llvm::support::ulittle64_t resultLE(result);
3142b5134f1SMogball     if (failed(
3152b5134f1SMogball             parseBytes(numBytes, reinterpret_cast<uint8_t *>(&resultLE) + 1)))
316f3acb54cSRiver Riddle       return failure();
317f3acb54cSRiver Riddle 
318f3acb54cSRiver Riddle     // Shift out the low-order bits that were used to mark how the value was
319f3acb54cSRiver Riddle     // encoded.
320bb0bbed6SUlrich Weigand     result = resultLE >> (numBytes + 1);
321f3acb54cSRiver Riddle     return success();
322f3acb54cSRiver Riddle   }
323f3acb54cSRiver Riddle 
3241c8c365dSChristian Sigg   /// The bytecode buffer.
3251c8c365dSChristian Sigg   ArrayRef<uint8_t> buffer;
3261c8c365dSChristian Sigg 
3271c8c365dSChristian Sigg   /// The current iterator within the 'buffer'.
3281c8c365dSChristian Sigg   const uint8_t *dataIt;
329f3acb54cSRiver Riddle 
330f3acb54cSRiver Riddle   /// A location for the bytecode used to report errors.
331f3acb54cSRiver Riddle   Location fileLoc;
332f3acb54cSRiver Riddle };
333f3acb54cSRiver Riddle } // namespace
334f3acb54cSRiver Riddle 
335f3acb54cSRiver Riddle /// Resolve an index into the given entry list. `entry` may either be a
336f3acb54cSRiver Riddle /// reference, in which case it is assigned to the corresponding value in
337f3acb54cSRiver Riddle /// `entries`, or a pointer, in which case it is assigned to the address of the
338f3acb54cSRiver Riddle /// element in `entries`.
339f3acb54cSRiver Riddle template <typename RangeT, typename T>
340f3acb54cSRiver Riddle static LogicalResult resolveEntry(EncodingReader &reader, RangeT &entries,
341f3acb54cSRiver Riddle                                   uint64_t index, T &entry,
342f3acb54cSRiver Riddle                                   StringRef entryStr) {
343f3acb54cSRiver Riddle   if (index >= entries.size())
344f3acb54cSRiver Riddle     return reader.emitError("invalid ", entryStr, " index: ", index);
345f3acb54cSRiver Riddle 
346f3acb54cSRiver Riddle   // If the provided entry is a pointer, resolve to the address of the entry.
347f3acb54cSRiver Riddle   if constexpr (std::is_convertible_v<llvm::detail::ValueOfRange<RangeT>, T>)
348f3acb54cSRiver Riddle     entry = entries[index];
349f3acb54cSRiver Riddle   else
350f3acb54cSRiver Riddle     entry = &entries[index];
351f3acb54cSRiver Riddle   return success();
352f3acb54cSRiver Riddle }
353f3acb54cSRiver Riddle 
354f3acb54cSRiver Riddle /// Parse and resolve an index into the given entry list.
355f3acb54cSRiver Riddle template <typename RangeT, typename T>
356f3acb54cSRiver Riddle static LogicalResult parseEntry(EncodingReader &reader, RangeT &entries,
357f3acb54cSRiver Riddle                                 T &entry, StringRef entryStr) {
358f3acb54cSRiver Riddle   uint64_t entryIdx;
359f3acb54cSRiver Riddle   if (failed(reader.parseVarInt(entryIdx)))
360f3acb54cSRiver Riddle     return failure();
361f3acb54cSRiver Riddle   return resolveEntry(reader, entries, entryIdx, entry, entryStr);
362f3acb54cSRiver Riddle }
363f3acb54cSRiver Riddle 
364f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
36583dc9999SRiver Riddle // StringSectionReader
36683dc9999SRiver Riddle //===----------------------------------------------------------------------===//
36783dc9999SRiver Riddle 
36883dc9999SRiver Riddle namespace {
36983dc9999SRiver Riddle /// This class is used to read references to the string section from the
37083dc9999SRiver Riddle /// bytecode.
37183dc9999SRiver Riddle class StringSectionReader {
37283dc9999SRiver Riddle public:
37383dc9999SRiver Riddle   /// Initialize the string section reader with the given section data.
37483dc9999SRiver Riddle   LogicalResult initialize(Location fileLoc, ArrayRef<uint8_t> sectionData);
37583dc9999SRiver Riddle 
37683dc9999SRiver Riddle   /// Parse a shared string from the string section. The shared string is
37783dc9999SRiver Riddle   /// encoded using an index to a corresponding string in the string section.
378c0084c36SHideto Ueno   LogicalResult parseString(EncodingReader &reader, StringRef &result) const {
37983dc9999SRiver Riddle     return parseEntry(reader, strings, result, "string");
38083dc9999SRiver Riddle   }
38183dc9999SRiver Riddle 
3820e0b6070SMatteo Franciolini   /// Parse a shared string from the string section. The shared string is
3830e0b6070SMatteo Franciolini   /// encoded using an index to a corresponding string in the string section.
384660f714eSMehdi Amini   /// This variant parses a flag compressed with the index.
385660f714eSMehdi Amini   LogicalResult parseStringWithFlag(EncodingReader &reader, StringRef &result,
386c0084c36SHideto Ueno                                     bool &flag) const {
387660f714eSMehdi Amini     uint64_t entryIdx;
388660f714eSMehdi Amini     if (failed(reader.parseVarIntWithFlag(entryIdx, flag)))
389660f714eSMehdi Amini       return failure();
390660f714eSMehdi Amini     return parseStringAtIndex(reader, entryIdx, result);
391660f714eSMehdi Amini   }
392660f714eSMehdi Amini 
393660f714eSMehdi Amini   /// Parse a shared string from the string section. The shared string is
394660f714eSMehdi Amini   /// encoded using an index to a corresponding string in the string section.
3950e0b6070SMatteo Franciolini   LogicalResult parseStringAtIndex(EncodingReader &reader, uint64_t index,
396c0084c36SHideto Ueno                                    StringRef &result) const {
3970e0b6070SMatteo Franciolini     return resolveEntry(reader, strings, index, result, "string");
3980e0b6070SMatteo Franciolini   }
3990e0b6070SMatteo Franciolini 
40083dc9999SRiver Riddle private:
40183dc9999SRiver Riddle   /// The table of strings referenced within the bytecode file.
40283dc9999SRiver Riddle   SmallVector<StringRef> strings;
40383dc9999SRiver Riddle };
40483dc9999SRiver Riddle } // namespace
40583dc9999SRiver Riddle 
40683dc9999SRiver Riddle LogicalResult StringSectionReader::initialize(Location fileLoc,
40783dc9999SRiver Riddle                                               ArrayRef<uint8_t> sectionData) {
40883dc9999SRiver Riddle   EncodingReader stringReader(sectionData, fileLoc);
40983dc9999SRiver Riddle 
41083dc9999SRiver Riddle   // Parse the number of strings in the section.
41183dc9999SRiver Riddle   uint64_t numStrings;
41283dc9999SRiver Riddle   if (failed(stringReader.parseVarInt(numStrings)))
41383dc9999SRiver Riddle     return failure();
41483dc9999SRiver Riddle   strings.resize(numStrings);
41583dc9999SRiver Riddle 
41683dc9999SRiver Riddle   // Parse each of the strings. The sizes of the strings are encoded in reverse
41783dc9999SRiver Riddle   // order, so that's the order we populate the table.
41883dc9999SRiver Riddle   size_t stringDataEndOffset = sectionData.size();
41983dc9999SRiver Riddle   for (StringRef &string : llvm::reverse(strings)) {
42083dc9999SRiver Riddle     uint64_t stringSize;
42183dc9999SRiver Riddle     if (failed(stringReader.parseVarInt(stringSize)))
42283dc9999SRiver Riddle       return failure();
42383dc9999SRiver Riddle     if (stringDataEndOffset < stringSize) {
42483dc9999SRiver Riddle       return stringReader.emitError(
42583dc9999SRiver Riddle           "string size exceeds the available data size");
42683dc9999SRiver Riddle     }
42783dc9999SRiver Riddle 
42883dc9999SRiver Riddle     // Extract the string from the data, dropping the null character.
42983dc9999SRiver Riddle     size_t stringOffset = stringDataEndOffset - stringSize;
43083dc9999SRiver Riddle     string = StringRef(
43183dc9999SRiver Riddle         reinterpret_cast<const char *>(sectionData.data() + stringOffset),
43283dc9999SRiver Riddle         stringSize - 1);
43383dc9999SRiver Riddle     stringDataEndOffset = stringOffset;
43483dc9999SRiver Riddle   }
43583dc9999SRiver Riddle 
43683dc9999SRiver Riddle   // Check that the only remaining data was for the strings, i.e. the reader
43783dc9999SRiver Riddle   // should be at the same offset as the first string.
43883dc9999SRiver Riddle   if ((sectionData.size() - stringReader.size()) != stringDataEndOffset) {
43983dc9999SRiver Riddle     return stringReader.emitError("unexpected trailing data between the "
44083dc9999SRiver Riddle                                   "offsets for strings and their data");
44183dc9999SRiver Riddle   }
44283dc9999SRiver Riddle   return success();
44383dc9999SRiver Riddle }
44483dc9999SRiver Riddle 
44583dc9999SRiver Riddle //===----------------------------------------------------------------------===//
446f3acb54cSRiver Riddle // BytecodeDialect
447f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
448f3acb54cSRiver Riddle 
449f3acb54cSRiver Riddle namespace {
4500e0b6070SMatteo Franciolini class DialectReader;
4510e0b6070SMatteo Franciolini 
452f3acb54cSRiver Riddle /// This struct represents a dialect entry within the bytecode.
453f3acb54cSRiver Riddle struct BytecodeDialect {
454f3acb54cSRiver Riddle   /// Load the dialect into the provided context if it hasn't been loaded yet.
455f3acb54cSRiver Riddle   /// Returns failure if the dialect couldn't be loaded *and* the provided
456f3acb54cSRiver Riddle   /// context does not allow unregistered dialects. The provided reader is used
457f3acb54cSRiver Riddle   /// for error emission if necessary.
458bff6a429SMatteo Franciolini   LogicalResult load(const DialectReader &reader, MLIRContext *ctx);
459f3acb54cSRiver Riddle 
4606ab2bcffSRiver Riddle   /// Return the loaded dialect, or nullptr if the dialect is unknown. This can
4616ab2bcffSRiver Riddle   /// only be called after `load`.
4626ab2bcffSRiver Riddle   Dialect *getLoadedDialect() const {
4636ab2bcffSRiver Riddle     assert(dialect &&
4646ab2bcffSRiver Riddle            "expected `load` to be invoked before `getLoadedDialect`");
4656ab2bcffSRiver Riddle     return *dialect;
4666ab2bcffSRiver Riddle   }
4676ab2bcffSRiver Riddle 
4684f81805aSKazu Hirata   /// The loaded dialect entry. This field is std::nullopt if we haven't
4694f81805aSKazu Hirata   /// attempted to load, nullptr if we failed to load, otherwise the loaded
4704f81805aSKazu Hirata   /// dialect.
471b2379415SKazu Hirata   std::optional<Dialect *> dialect;
472f3acb54cSRiver Riddle 
47302c2ecb9SRiver Riddle   /// The bytecode interface of the dialect, or nullptr if the dialect does not
47402c2ecb9SRiver Riddle   /// implement the bytecode interface. This field should only be checked if the
475b2379415SKazu Hirata   /// `dialect` field is not std::nullopt.
47602c2ecb9SRiver Riddle   const BytecodeDialectInterface *interface = nullptr;
47702c2ecb9SRiver Riddle 
478f3acb54cSRiver Riddle   /// The name of the dialect.
479f3acb54cSRiver Riddle   StringRef name;
4800e0b6070SMatteo Franciolini 
4810e0b6070SMatteo Franciolini   /// A buffer containing the encoding of the dialect version parsed.
4820e0b6070SMatteo Franciolini   ArrayRef<uint8_t> versionBuffer;
4830e0b6070SMatteo Franciolini 
4840e0b6070SMatteo Franciolini   /// Lazy loaded dialect version from the handle above.
4850e0b6070SMatteo Franciolini   std::unique_ptr<DialectVersion> loadedVersion;
486f3acb54cSRiver Riddle };
487f3acb54cSRiver Riddle 
488f3acb54cSRiver Riddle /// This struct represents an operation name entry within the bytecode.
489f3acb54cSRiver Riddle struct BytecodeOperationName {
490660f714eSMehdi Amini   BytecodeOperationName(BytecodeDialect *dialect, StringRef name,
491660f714eSMehdi Amini                         std::optional<bool> wasRegistered)
492660f714eSMehdi Amini       : dialect(dialect), name(name), wasRegistered(wasRegistered) {}
493f3acb54cSRiver Riddle 
494192d9dd7SKazu Hirata   /// The loaded operation name, or std::nullopt if it hasn't been processed
495192d9dd7SKazu Hirata   /// yet.
496b2379415SKazu Hirata   std::optional<OperationName> opName;
497f3acb54cSRiver Riddle 
498f3acb54cSRiver Riddle   /// The dialect that owns this operation name.
499f3acb54cSRiver Riddle   BytecodeDialect *dialect;
500f3acb54cSRiver Riddle 
501f3acb54cSRiver Riddle   /// The name of the operation, without the dialect prefix.
502f3acb54cSRiver Riddle   StringRef name;
503660f714eSMehdi Amini 
504660f714eSMehdi Amini   /// Whether this operation was registered when the bytecode was produced.
5059c1e5587SMehdi Amini   /// This flag is populated when bytecode version >=kNativePropertiesEncoding.
506660f714eSMehdi Amini   std::optional<bool> wasRegistered;
507f3acb54cSRiver Riddle };
508f3acb54cSRiver Riddle } // namespace
509f3acb54cSRiver Riddle 
510f3acb54cSRiver Riddle /// Parse a single dialect group encoded in the byte stream.
511f3acb54cSRiver Riddle static LogicalResult parseDialectGrouping(
512bff6a429SMatteo Franciolini     EncodingReader &reader,
513bff6a429SMatteo Franciolini     MutableArrayRef<std::unique_ptr<BytecodeDialect>> dialects,
514f3acb54cSRiver Riddle     function_ref<LogicalResult(BytecodeDialect *)> entryCallback) {
515f3acb54cSRiver Riddle   // Parse the dialect and the number of entries in the group.
516bff6a429SMatteo Franciolini   std::unique_ptr<BytecodeDialect> *dialect;
517f3acb54cSRiver Riddle   if (failed(parseEntry(reader, dialects, dialect, "dialect")))
518f3acb54cSRiver Riddle     return failure();
519f3acb54cSRiver Riddle   uint64_t numEntries;
520f3acb54cSRiver Riddle   if (failed(reader.parseVarInt(numEntries)))
521f3acb54cSRiver Riddle     return failure();
522f3acb54cSRiver Riddle 
523f3acb54cSRiver Riddle   for (uint64_t i = 0; i < numEntries; ++i)
524bff6a429SMatteo Franciolini     if (failed(entryCallback(dialect->get())))
525f3acb54cSRiver Riddle       return failure();
526f3acb54cSRiver Riddle   return success();
527f3acb54cSRiver Riddle }
528f3acb54cSRiver Riddle 
529f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
5306ab2bcffSRiver Riddle // ResourceSectionReader
5316ab2bcffSRiver Riddle //===----------------------------------------------------------------------===//
5326ab2bcffSRiver Riddle 
5336ab2bcffSRiver Riddle namespace {
5346ab2bcffSRiver Riddle /// This class is used to read the resource section from the bytecode.
5356ab2bcffSRiver Riddle class ResourceSectionReader {
5366ab2bcffSRiver Riddle public:
5376ab2bcffSRiver Riddle   /// Initialize the resource section reader with the given section data.
53818546ff8SRiver Riddle   LogicalResult
53918546ff8SRiver Riddle   initialize(Location fileLoc, const ParserConfig &config,
540bff6a429SMatteo Franciolini              MutableArrayRef<std::unique_ptr<BytecodeDialect>> dialects,
54118546ff8SRiver Riddle              StringSectionReader &stringReader, ArrayRef<uint8_t> sectionData,
5420e0b6070SMatteo Franciolini              ArrayRef<uint8_t> offsetSectionData, DialectReader &dialectReader,
54318546ff8SRiver Riddle              const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef);
5446ab2bcffSRiver Riddle 
5456ab2bcffSRiver Riddle   /// Parse a dialect resource handle from the resource section.
5466ab2bcffSRiver Riddle   LogicalResult parseResourceHandle(EncodingReader &reader,
547c0084c36SHideto Ueno                                     AsmDialectResourceHandle &result) const {
5486ab2bcffSRiver Riddle     return parseEntry(reader, dialectResources, result, "resource handle");
5496ab2bcffSRiver Riddle   }
5506ab2bcffSRiver Riddle 
5516ab2bcffSRiver Riddle private:
5526ab2bcffSRiver Riddle   /// The table of dialect resources within the bytecode file.
5536ab2bcffSRiver Riddle   SmallVector<AsmDialectResourceHandle> dialectResources;
554cfd90939SMehdi Amini   llvm::StringMap<std::string> dialectResourceHandleRenamingMap;
5556ab2bcffSRiver Riddle };
5566ab2bcffSRiver Riddle 
5576ab2bcffSRiver Riddle class ParsedResourceEntry : public AsmParsedResourceEntry {
5586ab2bcffSRiver Riddle public:
5596ab2bcffSRiver Riddle   ParsedResourceEntry(StringRef key, AsmResourceEntryKind kind,
56018546ff8SRiver Riddle                       EncodingReader &reader, StringSectionReader &stringReader,
56118546ff8SRiver Riddle                       const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
56218546ff8SRiver Riddle       : key(key), kind(kind), reader(reader), stringReader(stringReader),
56318546ff8SRiver Riddle         bufferOwnerRef(bufferOwnerRef) {}
5646ab2bcffSRiver Riddle   ~ParsedResourceEntry() override = default;
5656ab2bcffSRiver Riddle 
5666ab2bcffSRiver Riddle   StringRef getKey() const final { return key; }
5676ab2bcffSRiver Riddle 
5686ab2bcffSRiver Riddle   InFlightDiagnostic emitError() const final { return reader.emitError(); }
5696ab2bcffSRiver Riddle 
5706ab2bcffSRiver Riddle   AsmResourceEntryKind getKind() const final { return kind; }
5716ab2bcffSRiver Riddle 
5726ab2bcffSRiver Riddle   FailureOr<bool> parseAsBool() const final {
5736ab2bcffSRiver Riddle     if (kind != AsmResourceEntryKind::Bool)
5746ab2bcffSRiver Riddle       return emitError() << "expected a bool resource entry, but found a "
5756ab2bcffSRiver Riddle                          << toString(kind) << " entry instead";
5766ab2bcffSRiver Riddle 
5776ab2bcffSRiver Riddle     bool value;
5786ab2bcffSRiver Riddle     if (failed(reader.parseByte(value)))
5796ab2bcffSRiver Riddle       return failure();
5806ab2bcffSRiver Riddle     return value;
5816ab2bcffSRiver Riddle   }
5826ab2bcffSRiver Riddle   FailureOr<std::string> parseAsString() const final {
5836ab2bcffSRiver Riddle     if (kind != AsmResourceEntryKind::String)
5846ab2bcffSRiver Riddle       return emitError() << "expected a string resource entry, but found a "
5856ab2bcffSRiver Riddle                          << toString(kind) << " entry instead";
5866ab2bcffSRiver Riddle 
5876ab2bcffSRiver Riddle     StringRef string;
5886ab2bcffSRiver Riddle     if (failed(stringReader.parseString(reader, string)))
5896ab2bcffSRiver Riddle       return failure();
5906ab2bcffSRiver Riddle     return string.str();
5916ab2bcffSRiver Riddle   }
5926ab2bcffSRiver Riddle 
5936ab2bcffSRiver Riddle   FailureOr<AsmResourceBlob>
5946ab2bcffSRiver Riddle   parseAsBlob(BlobAllocatorFn allocator) const final {
5956ab2bcffSRiver Riddle     if (kind != AsmResourceEntryKind::Blob)
5966ab2bcffSRiver Riddle       return emitError() << "expected a blob resource entry, but found a "
5976ab2bcffSRiver Riddle                          << toString(kind) << " entry instead";
5986ab2bcffSRiver Riddle 
5996ab2bcffSRiver Riddle     ArrayRef<uint8_t> data;
6006ab2bcffSRiver Riddle     uint64_t alignment;
6016ab2bcffSRiver Riddle     if (failed(reader.parseBlobAndAlignment(data, alignment)))
6026ab2bcffSRiver Riddle       return failure();
6036ab2bcffSRiver Riddle 
60418546ff8SRiver Riddle     // If we have an extendable reference to the buffer owner, we don't need to
60518546ff8SRiver Riddle     // allocate a new buffer for the data, and can use the data directly.
60618546ff8SRiver Riddle     if (bufferOwnerRef) {
60718546ff8SRiver Riddle       ArrayRef<char> charData(reinterpret_cast<const char *>(data.data()),
60818546ff8SRiver Riddle                               data.size());
60918546ff8SRiver Riddle 
61018546ff8SRiver Riddle       // Allocate an unmanager buffer which captures a reference to the owner.
61118546ff8SRiver Riddle       // For now we just mark this as immutable, but in the future we should
61218546ff8SRiver Riddle       // explore marking this as mutable when desired.
61318546ff8SRiver Riddle       return UnmanagedAsmResourceBlob::allocateWithAlign(
61418546ff8SRiver Riddle           charData, alignment,
61518546ff8SRiver Riddle           [bufferOwnerRef = bufferOwnerRef](void *, size_t, size_t) {});
61618546ff8SRiver Riddle     }
61718546ff8SRiver Riddle 
6186ab2bcffSRiver Riddle     // Allocate memory for the blob using the provided allocator and copy the
6196ab2bcffSRiver Riddle     // data into it.
6206ab2bcffSRiver Riddle     AsmResourceBlob blob = allocator(data.size(), alignment);
6216ab2bcffSRiver Riddle     assert(llvm::isAddrAligned(llvm::Align(alignment), blob.getData().data()) &&
6226ab2bcffSRiver Riddle            blob.isMutable() &&
6236ab2bcffSRiver Riddle            "blob allocator did not return a properly aligned address");
6246ab2bcffSRiver Riddle     memcpy(blob.getMutableData().data(), data.data(), data.size());
6256ab2bcffSRiver Riddle     return blob;
6266ab2bcffSRiver Riddle   }
6276ab2bcffSRiver Riddle 
6286ab2bcffSRiver Riddle private:
6296ab2bcffSRiver Riddle   StringRef key;
6306ab2bcffSRiver Riddle   AsmResourceEntryKind kind;
6316ab2bcffSRiver Riddle   EncodingReader &reader;
6326ab2bcffSRiver Riddle   StringSectionReader &stringReader;
63318546ff8SRiver Riddle   const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
6346ab2bcffSRiver Riddle };
6356ab2bcffSRiver Riddle } // namespace
6366ab2bcffSRiver Riddle 
6376ab2bcffSRiver Riddle template <typename T>
6386ab2bcffSRiver Riddle static LogicalResult
6396ab2bcffSRiver Riddle parseResourceGroup(Location fileLoc, bool allowEmpty,
6406ab2bcffSRiver Riddle                    EncodingReader &offsetReader, EncodingReader &resourceReader,
6416ab2bcffSRiver Riddle                    StringSectionReader &stringReader, T *handler,
64218546ff8SRiver Riddle                    const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef,
643cfd90939SMehdi Amini                    function_ref<StringRef(StringRef)> remapKey = {},
6446ab2bcffSRiver Riddle                    function_ref<LogicalResult(StringRef)> processKeyFn = {}) {
6456ab2bcffSRiver Riddle   uint64_t numResources;
6466ab2bcffSRiver Riddle   if (failed(offsetReader.parseVarInt(numResources)))
6476ab2bcffSRiver Riddle     return failure();
6486ab2bcffSRiver Riddle 
6496ab2bcffSRiver Riddle   for (uint64_t i = 0; i < numResources; ++i) {
6506ab2bcffSRiver Riddle     StringRef key;
6516ab2bcffSRiver Riddle     AsmResourceEntryKind kind;
6526ab2bcffSRiver Riddle     uint64_t resourceOffset;
6536ab2bcffSRiver Riddle     ArrayRef<uint8_t> data;
6546ab2bcffSRiver Riddle     if (failed(stringReader.parseString(offsetReader, key)) ||
6556ab2bcffSRiver Riddle         failed(offsetReader.parseVarInt(resourceOffset)) ||
6566ab2bcffSRiver Riddle         failed(offsetReader.parseByte(kind)) ||
6576ab2bcffSRiver Riddle         failed(resourceReader.parseBytes(resourceOffset, data)))
6586ab2bcffSRiver Riddle       return failure();
6596ab2bcffSRiver Riddle 
6606ab2bcffSRiver Riddle     // Process the resource key.
6616ab2bcffSRiver Riddle     if ((processKeyFn && failed(processKeyFn(key))))
6626ab2bcffSRiver Riddle       return failure();
6636ab2bcffSRiver Riddle 
6646ab2bcffSRiver Riddle     // If the resource data is empty and we allow it, don't error out when
6656ab2bcffSRiver Riddle     // parsing below, just skip it.
6666ab2bcffSRiver Riddle     if (allowEmpty && data.empty())
6676ab2bcffSRiver Riddle       continue;
6686ab2bcffSRiver Riddle 
6696ab2bcffSRiver Riddle     // Ignore the entry if we don't have a valid handler.
6706ab2bcffSRiver Riddle     if (!handler)
6716ab2bcffSRiver Riddle       continue;
6726ab2bcffSRiver Riddle 
6736ab2bcffSRiver Riddle     // Otherwise, parse the resource value.
6746ab2bcffSRiver Riddle     EncodingReader entryReader(data, fileLoc);
675cfd90939SMehdi Amini     key = remapKey(key);
67618546ff8SRiver Riddle     ParsedResourceEntry entry(key, kind, entryReader, stringReader,
67718546ff8SRiver Riddle                               bufferOwnerRef);
6786ab2bcffSRiver Riddle     if (failed(handler->parseResource(entry)))
6796ab2bcffSRiver Riddle       return failure();
6806ab2bcffSRiver Riddle     if (!entryReader.empty()) {
6816ab2bcffSRiver Riddle       return entryReader.emitError(
6826ab2bcffSRiver Riddle           "unexpected trailing bytes in resource entry '", key, "'");
6836ab2bcffSRiver Riddle     }
6846ab2bcffSRiver Riddle   }
6856ab2bcffSRiver Riddle   return success();
6866ab2bcffSRiver Riddle }
6876ab2bcffSRiver Riddle 
68818546ff8SRiver Riddle LogicalResult ResourceSectionReader::initialize(
68918546ff8SRiver Riddle     Location fileLoc, const ParserConfig &config,
690bff6a429SMatteo Franciolini     MutableArrayRef<std::unique_ptr<BytecodeDialect>> dialects,
69118546ff8SRiver Riddle     StringSectionReader &stringReader, ArrayRef<uint8_t> sectionData,
6920e0b6070SMatteo Franciolini     ArrayRef<uint8_t> offsetSectionData, DialectReader &dialectReader,
69318546ff8SRiver Riddle     const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
6946ab2bcffSRiver Riddle   EncodingReader resourceReader(sectionData, fileLoc);
6956ab2bcffSRiver Riddle   EncodingReader offsetReader(offsetSectionData, fileLoc);
6966ab2bcffSRiver Riddle 
6976ab2bcffSRiver Riddle   // Read the number of external resource providers.
6986ab2bcffSRiver Riddle   uint64_t numExternalResourceGroups;
6996ab2bcffSRiver Riddle   if (failed(offsetReader.parseVarInt(numExternalResourceGroups)))
7006ab2bcffSRiver Riddle     return failure();
7016ab2bcffSRiver Riddle 
7026ab2bcffSRiver Riddle   // Utility functor that dispatches to `parseResourceGroup`, but implicitly
7036ab2bcffSRiver Riddle   // provides most of the arguments.
7046ab2bcffSRiver Riddle   auto parseGroup = [&](auto *handler, bool allowEmpty = false,
7056ab2bcffSRiver Riddle                         function_ref<LogicalResult(StringRef)> keyFn = {}) {
706cfd90939SMehdi Amini     auto resolveKey = [&](StringRef key) -> StringRef {
707cfd90939SMehdi Amini       auto it = dialectResourceHandleRenamingMap.find(key);
708cfd90939SMehdi Amini       if (it == dialectResourceHandleRenamingMap.end())
709af7ee51aSJeff Niu         return key;
710cfd90939SMehdi Amini       return it->second;
711cfd90939SMehdi Amini     };
712cfd90939SMehdi Amini 
7136ab2bcffSRiver Riddle     return parseResourceGroup(fileLoc, allowEmpty, offsetReader, resourceReader,
714cfd90939SMehdi Amini                               stringReader, handler, bufferOwnerRef, resolveKey,
715cfd90939SMehdi Amini                               keyFn);
7166ab2bcffSRiver Riddle   };
7176ab2bcffSRiver Riddle 
7186ab2bcffSRiver Riddle   // Read the external resources from the bytecode.
7196ab2bcffSRiver Riddle   for (uint64_t i = 0; i < numExternalResourceGroups; ++i) {
7206ab2bcffSRiver Riddle     StringRef key;
7216ab2bcffSRiver Riddle     if (failed(stringReader.parseString(offsetReader, key)))
7226ab2bcffSRiver Riddle       return failure();
7236ab2bcffSRiver Riddle 
7246ab2bcffSRiver Riddle     // Get the handler for these resources.
7256ab2bcffSRiver Riddle     // TODO: Should we require handling external resources in some scenarios?
7266ab2bcffSRiver Riddle     AsmResourceParser *handler = config.getResourceParser(key);
7276ab2bcffSRiver Riddle     if (!handler) {
7286ab2bcffSRiver Riddle       emitWarning(fileLoc) << "ignoring unknown external resources for '" << key
7296ab2bcffSRiver Riddle                            << "'";
7306ab2bcffSRiver Riddle     }
7316ab2bcffSRiver Riddle 
7326ab2bcffSRiver Riddle     if (failed(parseGroup(handler)))
7336ab2bcffSRiver Riddle       return failure();
7346ab2bcffSRiver Riddle   }
7356ab2bcffSRiver Riddle 
7366ab2bcffSRiver Riddle   // Read the dialect resources from the bytecode.
7376ab2bcffSRiver Riddle   MLIRContext *ctx = fileLoc->getContext();
7386ab2bcffSRiver Riddle   while (!offsetReader.empty()) {
739bff6a429SMatteo Franciolini     std::unique_ptr<BytecodeDialect> *dialect;
7406ab2bcffSRiver Riddle     if (failed(parseEntry(offsetReader, dialects, dialect, "dialect")) ||
741bff6a429SMatteo Franciolini         failed((*dialect)->load(dialectReader, ctx)))
7426ab2bcffSRiver Riddle       return failure();
743bff6a429SMatteo Franciolini     Dialect *loadedDialect = (*dialect)->getLoadedDialect();
7446ab2bcffSRiver Riddle     if (!loadedDialect) {
7456ab2bcffSRiver Riddle       return resourceReader.emitError()
746bff6a429SMatteo Franciolini              << "dialect '" << (*dialect)->name << "' is unknown";
7476ab2bcffSRiver Riddle     }
7486ab2bcffSRiver Riddle     const auto *handler = dyn_cast<OpAsmDialectInterface>(loadedDialect);
7496ab2bcffSRiver Riddle     if (!handler) {
7506ab2bcffSRiver Riddle       return resourceReader.emitError()
751bff6a429SMatteo Franciolini              << "unexpected resources for dialect '" << (*dialect)->name << "'";
7526ab2bcffSRiver Riddle     }
7536ab2bcffSRiver Riddle 
7546ab2bcffSRiver Riddle     // Ensure that each resource is declared before being processed.
7556ab2bcffSRiver Riddle     auto processResourceKeyFn = [&](StringRef key) -> LogicalResult {
7566ab2bcffSRiver Riddle       FailureOr<AsmDialectResourceHandle> handle =
7576ab2bcffSRiver Riddle           handler->declareResource(key);
7586ab2bcffSRiver Riddle       if (failed(handle)) {
7596ab2bcffSRiver Riddle         return resourceReader.emitError()
7606ab2bcffSRiver Riddle                << "unknown 'resource' key '" << key << "' for dialect '"
761bff6a429SMatteo Franciolini                << (*dialect)->name << "'";
7626ab2bcffSRiver Riddle       }
763cfd90939SMehdi Amini       dialectResourceHandleRenamingMap[key] = handler->getResourceKey(*handle);
7646ab2bcffSRiver Riddle       dialectResources.push_back(*handle);
7656ab2bcffSRiver Riddle       return success();
7666ab2bcffSRiver Riddle     };
7676ab2bcffSRiver Riddle 
7686ab2bcffSRiver Riddle     // Parse the resources for this dialect. We allow empty resources because we
7696ab2bcffSRiver Riddle     // just treat these as declarations.
7706ab2bcffSRiver Riddle     if (failed(parseGroup(handler, /*allowEmpty=*/true, processResourceKeyFn)))
7716ab2bcffSRiver Riddle       return failure();
7726ab2bcffSRiver Riddle   }
7736ab2bcffSRiver Riddle 
7746ab2bcffSRiver Riddle   return success();
7756ab2bcffSRiver Riddle }
7766ab2bcffSRiver Riddle 
7776ab2bcffSRiver Riddle //===----------------------------------------------------------------------===//
778f3acb54cSRiver Riddle // Attribute/Type Reader
779f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
780f3acb54cSRiver Riddle 
781f3acb54cSRiver Riddle namespace {
782f3acb54cSRiver Riddle /// This class provides support for reading attribute and type entries from the
783f3acb54cSRiver Riddle /// bytecode. Attribute and Type entries are read lazily on demand, so we use
784f3acb54cSRiver Riddle /// this reader to manage when to actually parse them from the bytecode.
785f3acb54cSRiver Riddle class AttrTypeReader {
786f3acb54cSRiver Riddle   /// This class represents a single attribute or type entry.
787f3acb54cSRiver Riddle   template <typename T>
788f3acb54cSRiver Riddle   struct Entry {
789f3acb54cSRiver Riddle     /// The entry, or null if it hasn't been resolved yet.
790f3acb54cSRiver Riddle     T entry = {};
791f3acb54cSRiver Riddle     /// The parent dialect of this entry.
792f3acb54cSRiver Riddle     BytecodeDialect *dialect = nullptr;
793f3acb54cSRiver Riddle     /// A flag indicating if the entry was encoded using a custom encoding,
794f3acb54cSRiver Riddle     /// instead of using the textual assembly format.
795f3acb54cSRiver Riddle     bool hasCustomEncoding = false;
796f3acb54cSRiver Riddle     /// The raw data of this entry in the bytecode.
797f3acb54cSRiver Riddle     ArrayRef<uint8_t> data;
798f3acb54cSRiver Riddle   };
799f3acb54cSRiver Riddle   using AttrEntry = Entry<Attribute>;
800f3acb54cSRiver Riddle   using TypeEntry = Entry<Type>;
801f3acb54cSRiver Riddle 
802f3acb54cSRiver Riddle public:
803c0084c36SHideto Ueno   AttrTypeReader(const StringSectionReader &stringReader,
804c0084c36SHideto Ueno                  const ResourceSectionReader &resourceReader,
805bff6a429SMatteo Franciolini                  const llvm::StringMap<BytecodeDialect *> &dialectsMap,
806bff6a429SMatteo Franciolini                  uint64_t &bytecodeVersion, Location fileLoc,
807bff6a429SMatteo Franciolini                  const ParserConfig &config)
8086ab2bcffSRiver Riddle       : stringReader(stringReader), resourceReader(resourceReader),
809bff6a429SMatteo Franciolini         dialectsMap(dialectsMap), fileLoc(fileLoc),
810bff6a429SMatteo Franciolini         bytecodeVersion(bytecodeVersion), parserConfig(config) {}
811f3acb54cSRiver Riddle 
812f3acb54cSRiver Riddle   /// Initialize the attribute and type information within the reader.
813bff6a429SMatteo Franciolini   LogicalResult
814bff6a429SMatteo Franciolini   initialize(MutableArrayRef<std::unique_ptr<BytecodeDialect>> dialects,
815f3acb54cSRiver Riddle              ArrayRef<uint8_t> sectionData,
816f3acb54cSRiver Riddle              ArrayRef<uint8_t> offsetSectionData);
817f3acb54cSRiver Riddle 
818f3acb54cSRiver Riddle   /// Resolve the attribute or type at the given index. Returns nullptr on
819f3acb54cSRiver Riddle   /// failure.
820f3acb54cSRiver Riddle   Attribute resolveAttribute(size_t index) {
821f3acb54cSRiver Riddle     return resolveEntry(attributes, index, "Attribute");
822f3acb54cSRiver Riddle   }
823f3acb54cSRiver Riddle   Type resolveType(size_t index) { return resolveEntry(types, index, "Type"); }
824f3acb54cSRiver Riddle 
825b3449392SRiver Riddle   /// Parse a reference to an attribute or type using the given reader.
826b3449392SRiver Riddle   LogicalResult parseAttribute(EncodingReader &reader, Attribute &result) {
827b3449392SRiver Riddle     uint64_t attrIdx;
828b3449392SRiver Riddle     if (failed(reader.parseVarInt(attrIdx)))
829b3449392SRiver Riddle       return failure();
830b3449392SRiver Riddle     result = resolveAttribute(attrIdx);
831b3449392SRiver Riddle     return success(!!result);
832b3449392SRiver Riddle   }
833660f714eSMehdi Amini   LogicalResult parseOptionalAttribute(EncodingReader &reader,
834660f714eSMehdi Amini                                        Attribute &result) {
835660f714eSMehdi Amini     uint64_t attrIdx;
836660f714eSMehdi Amini     bool flag;
837660f714eSMehdi Amini     if (failed(reader.parseVarIntWithFlag(attrIdx, flag)))
838660f714eSMehdi Amini       return failure();
839660f714eSMehdi Amini     if (!flag)
840660f714eSMehdi Amini       return success();
841660f714eSMehdi Amini     result = resolveAttribute(attrIdx);
842660f714eSMehdi Amini     return success(!!result);
843660f714eSMehdi Amini   }
844660f714eSMehdi Amini 
845b3449392SRiver Riddle   LogicalResult parseType(EncodingReader &reader, Type &result) {
846b3449392SRiver Riddle     uint64_t typeIdx;
847b3449392SRiver Riddle     if (failed(reader.parseVarInt(typeIdx)))
848b3449392SRiver Riddle       return failure();
849b3449392SRiver Riddle     result = resolveType(typeIdx);
850b3449392SRiver Riddle     return success(!!result);
851b3449392SRiver Riddle   }
852b3449392SRiver Riddle 
853b3449392SRiver Riddle   template <typename T>
854b3449392SRiver Riddle   LogicalResult parseAttribute(EncodingReader &reader, T &result) {
855b3449392SRiver Riddle     Attribute baseResult;
856b3449392SRiver Riddle     if (failed(parseAttribute(reader, baseResult)))
857b3449392SRiver Riddle       return failure();
8585550c821STres Popp     if ((result = dyn_cast<T>(baseResult)))
859b3449392SRiver Riddle       return success();
860b3449392SRiver Riddle     return reader.emitError("expected attribute of type: ",
861b3449392SRiver Riddle                             llvm::getTypeName<T>(), ", but got: ", baseResult);
862b3449392SRiver Riddle   }
863b3449392SRiver Riddle 
864f3acb54cSRiver Riddle private:
865f3acb54cSRiver Riddle   /// Resolve the given entry at `index`.
866f3acb54cSRiver Riddle   template <typename T>
867f3acb54cSRiver Riddle   T resolveEntry(SmallVectorImpl<Entry<T>> &entries, size_t index,
868f3acb54cSRiver Riddle                  StringRef entryType);
869f3acb54cSRiver Riddle 
870b3449392SRiver Riddle   /// Parse an entry using the given reader that was encoded using the textual
871b3449392SRiver Riddle   /// assembly format.
872b3449392SRiver Riddle   template <typename T>
873b3449392SRiver Riddle   LogicalResult parseAsmEntry(T &result, EncodingReader &reader,
874b3449392SRiver Riddle                               StringRef entryType);
875b3449392SRiver Riddle 
876b3449392SRiver Riddle   /// Parse an entry using the given reader that was encoded using a custom
877b3449392SRiver Riddle   /// bytecode format.
878b3449392SRiver Riddle   template <typename T>
879b3449392SRiver Riddle   LogicalResult parseCustomEntry(Entry<T> &entry, EncodingReader &reader,
880b3449392SRiver Riddle                                  StringRef entryType);
881f3acb54cSRiver Riddle 
88202c2ecb9SRiver Riddle   /// The string section reader used to resolve string references when parsing
88302c2ecb9SRiver Riddle   /// custom encoded attribute/type entries.
884c0084c36SHideto Ueno   const StringSectionReader &stringReader;
88502c2ecb9SRiver Riddle 
8866ab2bcffSRiver Riddle   /// The resource section reader used to resolve resource references when
8876ab2bcffSRiver Riddle   /// parsing custom encoded attribute/type entries.
888c0084c36SHideto Ueno   const ResourceSectionReader &resourceReader;
8896ab2bcffSRiver Riddle 
890bff6a429SMatteo Franciolini   /// The map of the loaded dialects used to retrieve dialect information, such
891bff6a429SMatteo Franciolini   /// as the dialect version.
892bff6a429SMatteo Franciolini   const llvm::StringMap<BytecodeDialect *> &dialectsMap;
893bff6a429SMatteo Franciolini 
894f3acb54cSRiver Riddle   /// The set of attribute and type entries.
895f3acb54cSRiver Riddle   SmallVector<AttrEntry> attributes;
896f3acb54cSRiver Riddle   SmallVector<TypeEntry> types;
897f3acb54cSRiver Riddle 
898f3acb54cSRiver Riddle   /// A location used for error emission.
899f3acb54cSRiver Riddle   Location fileLoc;
9009ea6b30aSMehdi Amini 
9019ea6b30aSMehdi Amini   /// Current bytecode version being used.
9029ea6b30aSMehdi Amini   uint64_t &bytecodeVersion;
903bff6a429SMatteo Franciolini 
904bff6a429SMatteo Franciolini   /// Reference to the parser configuration.
905bff6a429SMatteo Franciolini   const ParserConfig &parserConfig;
906f3acb54cSRiver Riddle };
90702c2ecb9SRiver Riddle 
90802c2ecb9SRiver Riddle class DialectReader : public DialectBytecodeReader {
90902c2ecb9SRiver Riddle public:
91002c2ecb9SRiver Riddle   DialectReader(AttrTypeReader &attrTypeReader,
911c0084c36SHideto Ueno                 const StringSectionReader &stringReader,
912c0084c36SHideto Ueno                 const ResourceSectionReader &resourceReader,
913bff6a429SMatteo Franciolini                 const llvm::StringMap<BytecodeDialect *> &dialectsMap,
914bff6a429SMatteo Franciolini                 EncodingReader &reader, uint64_t &bytecodeVersion)
91502c2ecb9SRiver Riddle       : attrTypeReader(attrTypeReader), stringReader(stringReader),
916bff6a429SMatteo Franciolini         resourceReader(resourceReader), dialectsMap(dialectsMap),
917bff6a429SMatteo Franciolini         reader(reader), bytecodeVersion(bytecodeVersion) {}
91802c2ecb9SRiver Riddle 
919bff6a429SMatteo Franciolini   InFlightDiagnostic emitError(const Twine &msg) const override {
92002c2ecb9SRiver Riddle     return reader.emitError(msg);
92102c2ecb9SRiver Riddle   }
92202c2ecb9SRiver Riddle 
923bff6a429SMatteo Franciolini   FailureOr<const DialectVersion *>
924bff6a429SMatteo Franciolini   getDialectVersion(StringRef dialectName) const override {
925bff6a429SMatteo Franciolini     // First check if the dialect is available in the map.
926bff6a429SMatteo Franciolini     auto dialectEntry = dialectsMap.find(dialectName);
927bff6a429SMatteo Franciolini     if (dialectEntry == dialectsMap.end())
928bff6a429SMatteo Franciolini       return failure();
929bff6a429SMatteo Franciolini     // If the dialect was found, try to load it. This will trigger reading the
930bff6a429SMatteo Franciolini     // bytecode version from the version buffer if it wasn't already processed.
931bff6a429SMatteo Franciolini     // Return failure if either of those two actions could not be completed.
932bff6a429SMatteo Franciolini     if (failed(dialectEntry->getValue()->load(*this, getLoc().getContext())) ||
9337d6fb140SAdrian Kuegel         dialectEntry->getValue()->loadedVersion == nullptr)
934bff6a429SMatteo Franciolini       return failure();
935bff6a429SMatteo Franciolini     return dialectEntry->getValue()->loadedVersion.get();
936bff6a429SMatteo Franciolini   }
937bff6a429SMatteo Franciolini 
938bff6a429SMatteo Franciolini   MLIRContext *getContext() const override { return getLoc().getContext(); }
939bff6a429SMatteo Franciolini 
9409ea6b30aSMehdi Amini   uint64_t getBytecodeVersion() const override { return bytecodeVersion; }
9419ea6b30aSMehdi Amini 
942bff6a429SMatteo Franciolini   DialectReader withEncodingReader(EncodingReader &encReader) const {
9433449e7a8SJacques Pienaar     return DialectReader(attrTypeReader, stringReader, resourceReader,
944bff6a429SMatteo Franciolini                          dialectsMap, encReader, bytecodeVersion);
9453449e7a8SJacques Pienaar   }
9463449e7a8SJacques Pienaar 
9473449e7a8SJacques Pienaar   Location getLoc() const { return reader.getLoc(); }
9483449e7a8SJacques Pienaar 
94902c2ecb9SRiver Riddle   //===--------------------------------------------------------------------===//
95002c2ecb9SRiver Riddle   // IR
95102c2ecb9SRiver Riddle   //===--------------------------------------------------------------------===//
95202c2ecb9SRiver Riddle 
95302c2ecb9SRiver Riddle   LogicalResult readAttribute(Attribute &result) override {
95402c2ecb9SRiver Riddle     return attrTypeReader.parseAttribute(reader, result);
95502c2ecb9SRiver Riddle   }
956660f714eSMehdi Amini   LogicalResult readOptionalAttribute(Attribute &result) override {
957660f714eSMehdi Amini     return attrTypeReader.parseOptionalAttribute(reader, result);
958660f714eSMehdi Amini   }
95902c2ecb9SRiver Riddle   LogicalResult readType(Type &result) override {
96002c2ecb9SRiver Riddle     return attrTypeReader.parseType(reader, result);
96102c2ecb9SRiver Riddle   }
96202c2ecb9SRiver Riddle 
9636ab2bcffSRiver Riddle   FailureOr<AsmDialectResourceHandle> readResourceHandle() override {
9646ab2bcffSRiver Riddle     AsmDialectResourceHandle handle;
9656ab2bcffSRiver Riddle     if (failed(resourceReader.parseResourceHandle(reader, handle)))
9666ab2bcffSRiver Riddle       return failure();
9676ab2bcffSRiver Riddle     return handle;
9686ab2bcffSRiver Riddle   }
9696ab2bcffSRiver Riddle 
97002c2ecb9SRiver Riddle   //===--------------------------------------------------------------------===//
97102c2ecb9SRiver Riddle   // Primitives
97202c2ecb9SRiver Riddle   //===--------------------------------------------------------------------===//
97302c2ecb9SRiver Riddle 
97402c2ecb9SRiver Riddle   LogicalResult readVarInt(uint64_t &result) override {
97502c2ecb9SRiver Riddle     return reader.parseVarInt(result);
97602c2ecb9SRiver Riddle   }
97702c2ecb9SRiver Riddle 
9782f90764cSRiver Riddle   LogicalResult readSignedVarInt(int64_t &result) override {
9792f90764cSRiver Riddle     uint64_t unsignedResult;
9802f90764cSRiver Riddle     if (failed(reader.parseSignedVarInt(unsignedResult)))
9812f90764cSRiver Riddle       return failure();
9822f90764cSRiver Riddle     result = static_cast<int64_t>(unsignedResult);
9832f90764cSRiver Riddle     return success();
9842f90764cSRiver Riddle   }
9852f90764cSRiver Riddle 
9862f90764cSRiver Riddle   FailureOr<APInt> readAPIntWithKnownWidth(unsigned bitWidth) override {
9872f90764cSRiver Riddle     // Small values are encoded using a single byte.
9882f90764cSRiver Riddle     if (bitWidth <= 8) {
9892f90764cSRiver Riddle       uint8_t value;
9902f90764cSRiver Riddle       if (failed(reader.parseByte(value)))
9912f90764cSRiver Riddle         return failure();
9922f90764cSRiver Riddle       return APInt(bitWidth, value);
9932f90764cSRiver Riddle     }
9942f90764cSRiver Riddle 
9952f90764cSRiver Riddle     // Large values up to 64 bits are encoded using a single varint.
9962f90764cSRiver Riddle     if (bitWidth <= 64) {
9972f90764cSRiver Riddle       uint64_t value;
9982f90764cSRiver Riddle       if (failed(reader.parseSignedVarInt(value)))
9992f90764cSRiver Riddle         return failure();
10002f90764cSRiver Riddle       return APInt(bitWidth, value);
10012f90764cSRiver Riddle     }
10022f90764cSRiver Riddle 
10032f90764cSRiver Riddle     // Otherwise, for really big values we encode the array of active words in
10042f90764cSRiver Riddle     // the value.
10052f90764cSRiver Riddle     uint64_t numActiveWords;
10062f90764cSRiver Riddle     if (failed(reader.parseVarInt(numActiveWords)))
10072f90764cSRiver Riddle       return failure();
10082f90764cSRiver Riddle     SmallVector<uint64_t, 4> words(numActiveWords);
10092f90764cSRiver Riddle     for (uint64_t i = 0; i < numActiveWords; ++i)
10102f90764cSRiver Riddle       if (failed(reader.parseSignedVarInt(words[i])))
10112f90764cSRiver Riddle         return failure();
10122f90764cSRiver Riddle     return APInt(bitWidth, words);
10132f90764cSRiver Riddle   }
10142f90764cSRiver Riddle 
10152f90764cSRiver Riddle   FailureOr<APFloat>
10162f90764cSRiver Riddle   readAPFloatWithKnownSemantics(const llvm::fltSemantics &semantics) override {
10172f90764cSRiver Riddle     FailureOr<APInt> intVal =
10182f90764cSRiver Riddle         readAPIntWithKnownWidth(APFloat::getSizeInBits(semantics));
10192f90764cSRiver Riddle     if (failed(intVal))
10202f90764cSRiver Riddle       return failure();
10212f90764cSRiver Riddle     return APFloat(semantics, *intVal);
10222f90764cSRiver Riddle   }
10232f90764cSRiver Riddle 
102402c2ecb9SRiver Riddle   LogicalResult readString(StringRef &result) override {
102502c2ecb9SRiver Riddle     return stringReader.parseString(reader, result);
102602c2ecb9SRiver Riddle   }
102702c2ecb9SRiver Riddle 
10285fb1bbe6SRiver Riddle   LogicalResult readBlob(ArrayRef<char> &result) override {
10295fb1bbe6SRiver Riddle     uint64_t dataSize;
10305fb1bbe6SRiver Riddle     ArrayRef<uint8_t> data;
10315fb1bbe6SRiver Riddle     if (failed(reader.parseVarInt(dataSize)) ||
10325fb1bbe6SRiver Riddle         failed(reader.parseBytes(dataSize, data)))
10335fb1bbe6SRiver Riddle       return failure();
1034984b800aSserge-sans-paille     result = llvm::ArrayRef(reinterpret_cast<const char *>(data.data()),
10355fb1bbe6SRiver Riddle                             data.size());
10365fb1bbe6SRiver Riddle     return success();
10375fb1bbe6SRiver Riddle   }
10385fb1bbe6SRiver Riddle 
103979c83e12SAndrzej Warzynski   LogicalResult readBool(bool &result) override {
104079c83e12SAndrzej Warzynski     return reader.parseByte(result);
104179c83e12SAndrzej Warzynski   }
104279c83e12SAndrzej Warzynski 
104302c2ecb9SRiver Riddle private:
104402c2ecb9SRiver Riddle   AttrTypeReader &attrTypeReader;
1045c0084c36SHideto Ueno   const StringSectionReader &stringReader;
1046c0084c36SHideto Ueno   const ResourceSectionReader &resourceReader;
1047bff6a429SMatteo Franciolini   const llvm::StringMap<BytecodeDialect *> &dialectsMap;
104802c2ecb9SRiver Riddle   EncodingReader &reader;
10499ea6b30aSMehdi Amini   uint64_t &bytecodeVersion;
105002c2ecb9SRiver Riddle };
1051660f714eSMehdi Amini 
1052660f714eSMehdi Amini /// Wraps the properties section and handles reading properties out of it.
1053660f714eSMehdi Amini class PropertiesSectionReader {
1054660f714eSMehdi Amini public:
1055660f714eSMehdi Amini   /// Initialize the properties section reader with the given section data.
1056660f714eSMehdi Amini   LogicalResult initialize(Location fileLoc, ArrayRef<uint8_t> sectionData) {
1057660f714eSMehdi Amini     if (sectionData.empty())
1058660f714eSMehdi Amini       return success();
1059660f714eSMehdi Amini     EncodingReader propReader(sectionData, fileLoc);
10605e8ed850SJie Fu     uint64_t count;
1061660f714eSMehdi Amini     if (failed(propReader.parseVarInt(count)))
1062660f714eSMehdi Amini       return failure();
1063660f714eSMehdi Amini     // Parse the raw properties buffer.
1064660f714eSMehdi Amini     if (failed(propReader.parseBytes(propReader.size(), propertiesBuffers)))
1065660f714eSMehdi Amini       return failure();
1066660f714eSMehdi Amini 
1067660f714eSMehdi Amini     EncodingReader offsetsReader(propertiesBuffers, fileLoc);
1068660f714eSMehdi Amini     offsetTable.reserve(count);
1069660f714eSMehdi Amini     for (auto idx : llvm::seq<int64_t>(0, count)) {
1070660f714eSMehdi Amini       (void)idx;
1071660f714eSMehdi Amini       offsetTable.push_back(propertiesBuffers.size() - offsetsReader.size());
1072660f714eSMehdi Amini       ArrayRef<uint8_t> rawProperties;
10735e8ed850SJie Fu       uint64_t dataSize;
1074660f714eSMehdi Amini       if (failed(offsetsReader.parseVarInt(dataSize)) ||
1075660f714eSMehdi Amini           failed(offsetsReader.parseBytes(dataSize, rawProperties)))
1076660f714eSMehdi Amini         return failure();
1077660f714eSMehdi Amini     }
1078660f714eSMehdi Amini     if (!offsetsReader.empty())
1079660f714eSMehdi Amini       return offsetsReader.emitError()
1080660f714eSMehdi Amini              << "Broken properties section: didn't exhaust the offsets table";
1081660f714eSMehdi Amini     return success();
1082660f714eSMehdi Amini   }
1083660f714eSMehdi Amini 
1084660f714eSMehdi Amini   LogicalResult read(Location fileLoc, DialectReader &dialectReader,
1085c0084c36SHideto Ueno                      OperationName *opName, OperationState &opState) const {
1086660f714eSMehdi Amini     uint64_t propertiesIdx;
1087660f714eSMehdi Amini     if (failed(dialectReader.readVarInt(propertiesIdx)))
1088660f714eSMehdi Amini       return failure();
1089660f714eSMehdi Amini     if (propertiesIdx >= offsetTable.size())
1090660f714eSMehdi Amini       return dialectReader.emitError("Properties idx out-of-bound for ")
1091660f714eSMehdi Amini              << opName->getStringRef();
1092660f714eSMehdi Amini     size_t propertiesOffset = offsetTable[propertiesIdx];
1093660f714eSMehdi Amini     if (propertiesIdx >= propertiesBuffers.size())
1094660f714eSMehdi Amini       return dialectReader.emitError("Properties offset out-of-bound for ")
1095660f714eSMehdi Amini              << opName->getStringRef();
1096660f714eSMehdi Amini 
1097660f714eSMehdi Amini     // Acquire the sub-buffer that represent the requested properties.
1098660f714eSMehdi Amini     ArrayRef<char> rawProperties;
1099660f714eSMehdi Amini     {
1100660f714eSMehdi Amini       // "Seek" to the requested offset by getting a new reader with the right
1101660f714eSMehdi Amini       // sub-buffer.
1102660f714eSMehdi Amini       EncodingReader reader(propertiesBuffers.drop_front(propertiesOffset),
1103660f714eSMehdi Amini                             fileLoc);
1104660f714eSMehdi Amini       // Properties are stored as a sequence of {size + raw_data}.
1105660f714eSMehdi Amini       if (failed(
1106660f714eSMehdi Amini               dialectReader.withEncodingReader(reader).readBlob(rawProperties)))
1107660f714eSMehdi Amini         return failure();
1108660f714eSMehdi Amini     }
1109660f714eSMehdi Amini     // Setup a new reader to read from the `rawProperties` sub-buffer.
1110660f714eSMehdi Amini     EncodingReader reader(
1111660f714eSMehdi Amini         StringRef(rawProperties.begin(), rawProperties.size()), fileLoc);
1112660f714eSMehdi Amini     DialectReader propReader = dialectReader.withEncodingReader(reader);
1113660f714eSMehdi Amini 
1114660f714eSMehdi Amini     auto *iface = opName->getInterface<BytecodeOpInterface>();
1115660f714eSMehdi Amini     if (iface)
1116660f714eSMehdi Amini       return iface->readProperties(propReader, opState);
1117660f714eSMehdi Amini     if (opName->isRegistered())
1118660f714eSMehdi Amini       return propReader.emitError(
1119660f714eSMehdi Amini                  "has properties but missing BytecodeOpInterface for ")
1120660f714eSMehdi Amini              << opName->getStringRef();
1121660f714eSMehdi Amini     // Unregistered op are storing properties as an attribute.
1122660f714eSMehdi Amini     return propReader.readAttribute(opState.propertiesAttr);
1123660f714eSMehdi Amini   }
1124660f714eSMehdi Amini 
1125660f714eSMehdi Amini private:
1126660f714eSMehdi Amini   /// The properties buffer referenced within the bytecode file.
1127660f714eSMehdi Amini   ArrayRef<uint8_t> propertiesBuffers;
1128660f714eSMehdi Amini 
1129660f714eSMehdi Amini   /// Table of offset in the buffer above.
1130660f714eSMehdi Amini   SmallVector<int64_t> offsetTable;
1131660f714eSMehdi Amini };
1132f3acb54cSRiver Riddle } // namespace
1133f3acb54cSRiver Riddle 
1134bff6a429SMatteo Franciolini LogicalResult AttrTypeReader::initialize(
1135bff6a429SMatteo Franciolini     MutableArrayRef<std::unique_ptr<BytecodeDialect>> dialects,
1136bff6a429SMatteo Franciolini     ArrayRef<uint8_t> sectionData, ArrayRef<uint8_t> offsetSectionData) {
1137f3acb54cSRiver Riddle   EncodingReader offsetReader(offsetSectionData, fileLoc);
1138f3acb54cSRiver Riddle 
1139f3acb54cSRiver Riddle   // Parse the number of attribute and type entries.
1140f3acb54cSRiver Riddle   uint64_t numAttributes, numTypes;
1141f3acb54cSRiver Riddle   if (failed(offsetReader.parseVarInt(numAttributes)) ||
1142f3acb54cSRiver Riddle       failed(offsetReader.parseVarInt(numTypes)))
1143f3acb54cSRiver Riddle     return failure();
1144f3acb54cSRiver Riddle   attributes.resize(numAttributes);
1145f3acb54cSRiver Riddle   types.resize(numTypes);
1146f3acb54cSRiver Riddle 
1147f3acb54cSRiver Riddle   // A functor used to accumulate the offsets for the entries in the given
1148f3acb54cSRiver Riddle   // range.
1149f3acb54cSRiver Riddle   uint64_t currentOffset = 0;
1150f3acb54cSRiver Riddle   auto parseEntries = [&](auto &&range) {
1151f3acb54cSRiver Riddle     size_t currentIndex = 0, endIndex = range.size();
1152f3acb54cSRiver Riddle 
1153f3acb54cSRiver Riddle     // Parse an individual entry.
115402c2ecb9SRiver Riddle     auto parseEntryFn = [&](BytecodeDialect *dialect) -> LogicalResult {
1155f3acb54cSRiver Riddle       auto &entry = range[currentIndex++];
1156f3acb54cSRiver Riddle 
1157f3acb54cSRiver Riddle       uint64_t entrySize;
1158f3acb54cSRiver Riddle       if (failed(offsetReader.parseVarIntWithFlag(entrySize,
1159f3acb54cSRiver Riddle                                                   entry.hasCustomEncoding)))
1160f3acb54cSRiver Riddle         return failure();
1161f3acb54cSRiver Riddle 
1162f3acb54cSRiver Riddle       // Verify that the offset is actually valid.
1163f3acb54cSRiver Riddle       if (currentOffset + entrySize > sectionData.size()) {
1164f3acb54cSRiver Riddle         return offsetReader.emitError(
1165f3acb54cSRiver Riddle             "Attribute or Type entry offset points past the end of section");
1166f3acb54cSRiver Riddle       }
1167f3acb54cSRiver Riddle 
1168f3acb54cSRiver Riddle       entry.data = sectionData.slice(currentOffset, entrySize);
1169f3acb54cSRiver Riddle       entry.dialect = dialect;
1170f3acb54cSRiver Riddle       currentOffset += entrySize;
1171f3acb54cSRiver Riddle       return success();
1172f3acb54cSRiver Riddle     };
1173f3acb54cSRiver Riddle     while (currentIndex != endIndex)
1174f3acb54cSRiver Riddle       if (failed(parseDialectGrouping(offsetReader, dialects, parseEntryFn)))
1175f3acb54cSRiver Riddle         return failure();
1176f3acb54cSRiver Riddle     return success();
1177f3acb54cSRiver Riddle   };
1178f3acb54cSRiver Riddle 
1179f3acb54cSRiver Riddle   // Process each of the attributes, and then the types.
1180f3acb54cSRiver Riddle   if (failed(parseEntries(attributes)) || failed(parseEntries(types)))
1181f3acb54cSRiver Riddle     return failure();
1182f3acb54cSRiver Riddle 
1183f3acb54cSRiver Riddle   // Ensure that we read everything from the section.
1184f3acb54cSRiver Riddle   if (!offsetReader.empty()) {
1185f3acb54cSRiver Riddle     return offsetReader.emitError(
1186f3acb54cSRiver Riddle         "unexpected trailing data in the Attribute/Type offset section");
1187f3acb54cSRiver Riddle   }
1188bff6a429SMatteo Franciolini 
1189f3acb54cSRiver Riddle   return success();
1190f3acb54cSRiver Riddle }
1191f3acb54cSRiver Riddle 
1192f3acb54cSRiver Riddle template <typename T>
1193f3acb54cSRiver Riddle T AttrTypeReader::resolveEntry(SmallVectorImpl<Entry<T>> &entries, size_t index,
1194f3acb54cSRiver Riddle                                StringRef entryType) {
1195f3acb54cSRiver Riddle   if (index >= entries.size()) {
1196f3acb54cSRiver Riddle     emitError(fileLoc) << "invalid " << entryType << " index: " << index;
1197f3acb54cSRiver Riddle     return {};
1198f3acb54cSRiver Riddle   }
1199f3acb54cSRiver Riddle 
1200f3acb54cSRiver Riddle   // If the entry has already been resolved, there is nothing left to do.
1201f3acb54cSRiver Riddle   Entry<T> &entry = entries[index];
1202f3acb54cSRiver Riddle   if (entry.entry)
1203f3acb54cSRiver Riddle     return entry.entry;
1204f3acb54cSRiver Riddle 
1205f3acb54cSRiver Riddle   // Parse the entry.
1206f3acb54cSRiver Riddle   EncodingReader reader(entry.data, fileLoc);
1207b3449392SRiver Riddle 
1208b3449392SRiver Riddle   // Parse based on how the entry was encoded.
1209b3449392SRiver Riddle   if (entry.hasCustomEncoding) {
1210b3449392SRiver Riddle     if (failed(parseCustomEntry(entry, reader, entryType)))
1211f3acb54cSRiver Riddle       return T();
1212b3449392SRiver Riddle   } else if (failed(parseAsmEntry(entry.entry, reader, entryType))) {
1213b3449392SRiver Riddle     return T();
1214b3449392SRiver Riddle   }
1215b3449392SRiver Riddle 
1216f3acb54cSRiver Riddle   if (!reader.empty()) {
121702c2ecb9SRiver Riddle     reader.emitError("unexpected trailing bytes after " + entryType + " entry");
1218f3acb54cSRiver Riddle     return T();
1219f3acb54cSRiver Riddle   }
1220f3acb54cSRiver Riddle   return entry.entry;
1221f3acb54cSRiver Riddle }
1222f3acb54cSRiver Riddle 
1223b3449392SRiver Riddle template <typename T>
1224b3449392SRiver Riddle LogicalResult AttrTypeReader::parseAsmEntry(T &result, EncodingReader &reader,
1225b3449392SRiver Riddle                                             StringRef entryType) {
1226b3449392SRiver Riddle   StringRef asmStr;
1227b3449392SRiver Riddle   if (failed(reader.parseNullTerminatedString(asmStr)))
1228f3acb54cSRiver Riddle     return failure();
1229f3acb54cSRiver Riddle 
1230b3449392SRiver Riddle   // Invoke the MLIR assembly parser to parse the entry text.
1231f3acb54cSRiver Riddle   size_t numRead = 0;
1232b3449392SRiver Riddle   MLIRContext *context = fileLoc->getContext();
1233b3449392SRiver Riddle   if constexpr (std::is_same_v<T, Type>)
123455cf53fdSRahul Kayaith     result =
123555cf53fdSRahul Kayaith         ::parseType(asmStr, context, &numRead, /*isKnownNullTerminated=*/true);
1236b3449392SRiver Riddle   else
123755cf53fdSRahul Kayaith     result = ::parseAttribute(asmStr, context, Type(), &numRead,
123855cf53fdSRahul Kayaith                               /*isKnownNullTerminated=*/true);
1239b3449392SRiver Riddle   if (!result)
1240f3acb54cSRiver Riddle     return failure();
1241b3449392SRiver Riddle 
1242b3449392SRiver Riddle   // Ensure there weren't dangling characters after the entry.
1243b3449392SRiver Riddle   if (numRead != asmStr.size()) {
1244b3449392SRiver Riddle     return reader.emitError("trailing characters found after ", entryType,
1245b3449392SRiver Riddle                             " assembly format: ", asmStr.drop_front(numRead));
1246f3acb54cSRiver Riddle   }
1247f3acb54cSRiver Riddle   return success();
1248f3acb54cSRiver Riddle }
1249f3acb54cSRiver Riddle 
1250b3449392SRiver Riddle template <typename T>
1251b3449392SRiver Riddle LogicalResult AttrTypeReader::parseCustomEntry(Entry<T> &entry,
1252b3449392SRiver Riddle                                                EncodingReader &reader,
1253b3449392SRiver Riddle                                                StringRef entryType) {
1254bff6a429SMatteo Franciolini   DialectReader dialectReader(*this, stringReader, resourceReader, dialectsMap,
1255bff6a429SMatteo Franciolini                               reader, bytecodeVersion);
12560e0b6070SMatteo Franciolini   if (failed(entry.dialect->load(dialectReader, fileLoc.getContext())))
125702c2ecb9SRiver Riddle     return failure();
1258bff6a429SMatteo Franciolini 
1259bff6a429SMatteo Franciolini   if constexpr (std::is_same_v<T, Type>) {
1260bff6a429SMatteo Franciolini     // Try parsing with callbacks first if available.
1261bff6a429SMatteo Franciolini     for (const auto &callback :
1262bff6a429SMatteo Franciolini          parserConfig.getBytecodeReaderConfig().getTypeCallbacks()) {
1263bff6a429SMatteo Franciolini       if (failed(
1264bff6a429SMatteo Franciolini               callback->read(dialectReader, entry.dialect->name, entry.entry)))
1265bff6a429SMatteo Franciolini         return failure();
1266bff6a429SMatteo Franciolini       // Early return if parsing was successful.
1267bff6a429SMatteo Franciolini       if (!!entry.entry)
1268bff6a429SMatteo Franciolini         return success();
1269bff6a429SMatteo Franciolini 
1270bff6a429SMatteo Franciolini       // Reset the reader if we failed to parse, so we can fall through the
1271bff6a429SMatteo Franciolini       // other parsing functions.
1272bff6a429SMatteo Franciolini       reader = EncodingReader(entry.data, reader.getLoc());
1273bff6a429SMatteo Franciolini     }
1274bff6a429SMatteo Franciolini   } else {
1275bff6a429SMatteo Franciolini     // Try parsing with callbacks first if available.
1276bff6a429SMatteo Franciolini     for (const auto &callback :
1277bff6a429SMatteo Franciolini          parserConfig.getBytecodeReaderConfig().getAttributeCallbacks()) {
1278bff6a429SMatteo Franciolini       if (failed(
1279bff6a429SMatteo Franciolini               callback->read(dialectReader, entry.dialect->name, entry.entry)))
1280bff6a429SMatteo Franciolini         return failure();
1281bff6a429SMatteo Franciolini       // Early return if parsing was successful.
1282bff6a429SMatteo Franciolini       if (!!entry.entry)
1283bff6a429SMatteo Franciolini         return success();
1284bff6a429SMatteo Franciolini 
1285bff6a429SMatteo Franciolini       // Reset the reader if we failed to parse, so we can fall through the
1286bff6a429SMatteo Franciolini       // other parsing functions.
1287bff6a429SMatteo Franciolini       reader = EncodingReader(entry.data, reader.getLoc());
1288bff6a429SMatteo Franciolini     }
1289bff6a429SMatteo Franciolini   }
1290bff6a429SMatteo Franciolini 
129102c2ecb9SRiver Riddle   // Ensure that the dialect implements the bytecode interface.
129202c2ecb9SRiver Riddle   if (!entry.dialect->interface) {
129302c2ecb9SRiver Riddle     return reader.emitError("dialect '", entry.dialect->name,
129402c2ecb9SRiver Riddle                             "' does not implement the bytecode interface");
129502c2ecb9SRiver Riddle   }
129602c2ecb9SRiver Riddle 
129702c2ecb9SRiver Riddle   if constexpr (std::is_same_v<T, Type>)
129802c2ecb9SRiver Riddle     entry.entry = entry.dialect->interface->readType(dialectReader);
129902c2ecb9SRiver Riddle   else
130002c2ecb9SRiver Riddle     entry.entry = entry.dialect->interface->readAttribute(dialectReader);
1301bff6a429SMatteo Franciolini 
130202c2ecb9SRiver Riddle   return success(!!entry.entry);
1303f3acb54cSRiver Riddle }
1304f3acb54cSRiver Riddle 
1305f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
1306f3acb54cSRiver Riddle // Bytecode Reader
1307f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
1308f3acb54cSRiver Riddle 
1309f3acb54cSRiver Riddle /// This class is used to read a bytecode buffer and translate it into MLIR.
13103128b310SMehdi Amini class mlir::BytecodeReader::Impl {
13113128b310SMehdi Amini   struct RegionReadState;
13123128b310SMehdi Amini   using LazyLoadableOpsInfo =
13133128b310SMehdi Amini       std::list<std::pair<Operation *, RegionReadState>>;
13143128b310SMehdi Amini   using LazyLoadableOpsMap =
13153128b310SMehdi Amini       DenseMap<Operation *, LazyLoadableOpsInfo::iterator>;
13163128b310SMehdi Amini 
1317f3acb54cSRiver Riddle public:
13183128b310SMehdi Amini   Impl(Location fileLoc, const ParserConfig &config, bool lazyLoading,
13193128b310SMehdi Amini        llvm::MemoryBufferRef buffer,
132018546ff8SRiver Riddle        const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef)
13213128b310SMehdi Amini       : config(config), fileLoc(fileLoc), lazyLoading(lazyLoading),
1322bff6a429SMatteo Franciolini         attrTypeReader(stringReader, resourceReader, dialectsMap, version,
1323bff6a429SMatteo Franciolini                        fileLoc, config),
1324f3acb54cSRiver Riddle         // Use the builtin unrealized conversion cast operation to represent
1325f3acb54cSRiver Riddle         // forward references to values that aren't yet defined.
1326f3acb54cSRiver Riddle         forwardRefOpState(UnknownLoc::get(config.getContext()),
1327f3acb54cSRiver Riddle                           "builtin.unrealized_conversion_cast", ValueRange(),
132818546ff8SRiver Riddle                           NoneType::get(config.getContext())),
13293128b310SMehdi Amini         buffer(buffer), bufferOwnerRef(bufferOwnerRef) {}
1330f3acb54cSRiver Riddle 
1331f3acb54cSRiver Riddle   /// Read the bytecode defined within `buffer` into the given block.
13323128b310SMehdi Amini   LogicalResult read(Block *block,
13333128b310SMehdi Amini                      llvm::function_ref<bool(Operation *)> lazyOps);
13343128b310SMehdi Amini 
13353128b310SMehdi Amini   /// Return the number of ops that haven't been materialized yet.
13363128b310SMehdi Amini   int64_t getNumOpsToMaterialize() const { return lazyLoadableOpsMap.size(); }
13373128b310SMehdi Amini 
13383128b310SMehdi Amini   bool isMaterializable(Operation *op) { return lazyLoadableOpsMap.count(op); }
13393128b310SMehdi Amini 
13403128b310SMehdi Amini   /// Materialize the provided operation, invoke the lazyOpsCallback on every
13413128b310SMehdi Amini   /// newly found lazy operation.
13423128b310SMehdi Amini   LogicalResult
13433128b310SMehdi Amini   materialize(Operation *op,
13443128b310SMehdi Amini               llvm::function_ref<bool(Operation *)> lazyOpsCallback) {
13453128b310SMehdi Amini     this->lazyOpsCallback = lazyOpsCallback;
13463128b310SMehdi Amini     auto resetlazyOpsCallback =
13473128b310SMehdi Amini         llvm::make_scope_exit([&] { this->lazyOpsCallback = nullptr; });
13483128b310SMehdi Amini     auto it = lazyLoadableOpsMap.find(op);
13493128b310SMehdi Amini     assert(it != lazyLoadableOpsMap.end() &&
13503128b310SMehdi Amini            "materialize called on non-materializable op");
13513128b310SMehdi Amini     return materialize(it);
13523128b310SMehdi Amini   }
13533128b310SMehdi Amini 
13543128b310SMehdi Amini   /// Materialize all operations.
13553128b310SMehdi Amini   LogicalResult materializeAll() {
13563128b310SMehdi Amini     while (!lazyLoadableOpsMap.empty()) {
13573128b310SMehdi Amini       if (failed(materialize(lazyLoadableOpsMap.begin())))
13583128b310SMehdi Amini         return failure();
13593128b310SMehdi Amini     }
13603128b310SMehdi Amini     return success();
13613128b310SMehdi Amini   }
13623128b310SMehdi Amini 
13633128b310SMehdi Amini   /// Finalize the lazy-loading by calling back with every op that hasn't been
13643128b310SMehdi Amini   /// materialized to let the client decide if the op should be deleted or
13653128b310SMehdi Amini   /// materialized. The op is materialized if the callback returns true, deleted
13663128b310SMehdi Amini   /// otherwise.
13673128b310SMehdi Amini   LogicalResult finalize(function_ref<bool(Operation *)> shouldMaterialize) {
13683128b310SMehdi Amini     while (!lazyLoadableOps.empty()) {
13693128b310SMehdi Amini       Operation *op = lazyLoadableOps.begin()->first;
13703128b310SMehdi Amini       if (shouldMaterialize(op)) {
13713128b310SMehdi Amini         if (failed(materialize(lazyLoadableOpsMap.find(op))))
13723128b310SMehdi Amini           return failure();
13733128b310SMehdi Amini         continue;
13743128b310SMehdi Amini       }
13753128b310SMehdi Amini       op->dropAllReferences();
13763128b310SMehdi Amini       op->erase();
13773128b310SMehdi Amini       lazyLoadableOps.pop_front();
13783128b310SMehdi Amini       lazyLoadableOpsMap.erase(op);
13793128b310SMehdi Amini     }
13803128b310SMehdi Amini     return success();
13813128b310SMehdi Amini   }
1382f3acb54cSRiver Riddle 
1383f3acb54cSRiver Riddle private:
13843128b310SMehdi Amini   LogicalResult materialize(LazyLoadableOpsMap::iterator it) {
13853128b310SMehdi Amini     assert(it != lazyLoadableOpsMap.end() &&
13863128b310SMehdi Amini            "materialize called on non-materializable op");
13873128b310SMehdi Amini     valueScopes.emplace_back();
13883128b310SMehdi Amini     std::vector<RegionReadState> regionStack;
13893128b310SMehdi Amini     regionStack.push_back(std::move(it->getSecond()->second));
13903128b310SMehdi Amini     lazyLoadableOps.erase(it->getSecond());
13913128b310SMehdi Amini     lazyLoadableOpsMap.erase(it);
13926ee1aba8SRiver Riddle 
13936ee1aba8SRiver Riddle     while (!regionStack.empty())
13946ee1aba8SRiver Riddle       if (failed(parseRegions(regionStack, regionStack.back())))
13956ee1aba8SRiver Riddle         return failure();
13966ee1aba8SRiver Riddle     return success();
13973128b310SMehdi Amini   }
13983128b310SMehdi Amini 
1399f3acb54cSRiver Riddle   /// Return the context for this config.
1400f3acb54cSRiver Riddle   MLIRContext *getContext() const { return config.getContext(); }
1401f3acb54cSRiver Riddle 
1402f3acb54cSRiver Riddle   /// Parse the bytecode version.
1403f3acb54cSRiver Riddle   LogicalResult parseVersion(EncodingReader &reader);
1404f3acb54cSRiver Riddle 
1405f3acb54cSRiver Riddle   //===--------------------------------------------------------------------===//
1406f3acb54cSRiver Riddle   // Dialect Section
1407f3acb54cSRiver Riddle 
1408f3acb54cSRiver Riddle   LogicalResult parseDialectSection(ArrayRef<uint8_t> sectionData);
1409f3acb54cSRiver Riddle 
1410660f714eSMehdi Amini   /// Parse an operation name reference using the given reader, and set the
1411660f714eSMehdi Amini   /// `wasRegistered` flag that indicates if the bytecode was produced by a
1412660f714eSMehdi Amini   /// context where opName was registered.
1413660f714eSMehdi Amini   FailureOr<OperationName> parseOpName(EncodingReader &reader,
1414660f714eSMehdi Amini                                        std::optional<bool> &wasRegistered);
1415f3acb54cSRiver Riddle 
1416f3acb54cSRiver Riddle   //===--------------------------------------------------------------------===//
1417f3acb54cSRiver Riddle   // Attribute/Type Section
1418f3acb54cSRiver Riddle 
1419b3449392SRiver Riddle   /// Parse an attribute or type using the given reader.
1420f3acb54cSRiver Riddle   template <typename T>
1421b3449392SRiver Riddle   LogicalResult parseAttribute(EncodingReader &reader, T &result) {
1422b3449392SRiver Riddle     return attrTypeReader.parseAttribute(reader, result);
1423f3acb54cSRiver Riddle   }
1424b3449392SRiver Riddle   LogicalResult parseType(EncodingReader &reader, Type &result) {
1425b3449392SRiver Riddle     return attrTypeReader.parseType(reader, result);
1426f3acb54cSRiver Riddle   }
1427f3acb54cSRiver Riddle 
1428f3acb54cSRiver Riddle   //===--------------------------------------------------------------------===//
14296ab2bcffSRiver Riddle   // Resource Section
14306ab2bcffSRiver Riddle 
14316ab2bcffSRiver Riddle   LogicalResult
14320e0b6070SMatteo Franciolini   parseResourceSection(EncodingReader &reader,
14330e0b6070SMatteo Franciolini                        std::optional<ArrayRef<uint8_t>> resourceData,
14340a81ace0SKazu Hirata                        std::optional<ArrayRef<uint8_t>> resourceOffsetData);
14356ab2bcffSRiver Riddle 
14366ab2bcffSRiver Riddle   //===--------------------------------------------------------------------===//
1437f3acb54cSRiver Riddle   // IR Section
1438f3acb54cSRiver Riddle 
1439f3acb54cSRiver Riddle   /// This struct represents the current read state of a range of regions. This
1440f3acb54cSRiver Riddle   /// struct is used to enable iterative parsing of regions.
1441f3acb54cSRiver Riddle   struct RegionReadState {
14423128b310SMehdi Amini     RegionReadState(Operation *op, EncodingReader *reader,
14433128b310SMehdi Amini                     bool isIsolatedFromAbove)
14443128b310SMehdi Amini         : RegionReadState(op->getRegions(), reader, isIsolatedFromAbove) {}
14453128b310SMehdi Amini     RegionReadState(MutableArrayRef<Region> regions, EncodingReader *reader,
14463128b310SMehdi Amini                     bool isIsolatedFromAbove)
14473128b310SMehdi Amini         : curRegion(regions.begin()), endRegion(regions.end()), reader(reader),
1448f3acb54cSRiver Riddle           isIsolatedFromAbove(isIsolatedFromAbove) {}
1449f3acb54cSRiver Riddle 
1450f3acb54cSRiver Riddle     /// The current regions being read.
1451f3acb54cSRiver Riddle     MutableArrayRef<Region>::iterator curRegion, endRegion;
14523128b310SMehdi Amini     /// This is the reader to use for this region, this pointer is pointing to
14533128b310SMehdi Amini     /// the parent region reader unless the current region is IsolatedFromAbove,
14543128b310SMehdi Amini     /// in which case the pointer is pointing to the `owningReader` which is a
14553128b310SMehdi Amini     /// section dedicated to the current region.
14563128b310SMehdi Amini     EncodingReader *reader;
14573128b310SMehdi Amini     std::unique_ptr<EncodingReader> owningReader;
1458f3acb54cSRiver Riddle 
1459f3acb54cSRiver Riddle     /// The number of values defined immediately within this region.
1460f3acb54cSRiver Riddle     unsigned numValues = 0;
1461f3acb54cSRiver Riddle 
1462f3acb54cSRiver Riddle     /// The current blocks of the region being read.
1463f3acb54cSRiver Riddle     SmallVector<Block *> curBlocks;
1464f3acb54cSRiver Riddle     Region::iterator curBlock = {};
1465f3acb54cSRiver Riddle 
1466f3acb54cSRiver Riddle     /// The number of operations remaining to be read from the current block
1467f3acb54cSRiver Riddle     /// being read.
1468f3acb54cSRiver Riddle     uint64_t numOpsRemaining = 0;
1469f3acb54cSRiver Riddle 
1470f3acb54cSRiver Riddle     /// A flag indicating if the regions being read are isolated from above.
1471f3acb54cSRiver Riddle     bool isIsolatedFromAbove = false;
1472f3acb54cSRiver Riddle   };
1473f3acb54cSRiver Riddle 
1474f3acb54cSRiver Riddle   LogicalResult parseIRSection(ArrayRef<uint8_t> sectionData, Block *block);
14753128b310SMehdi Amini   LogicalResult parseRegions(std::vector<RegionReadState> &regionStack,
1476f3acb54cSRiver Riddle                              RegionReadState &readState);
1477f3acb54cSRiver Riddle   FailureOr<Operation *> parseOpWithoutRegions(EncodingReader &reader,
1478f3acb54cSRiver Riddle                                                RegionReadState &readState,
1479f3acb54cSRiver Riddle                                                bool &isIsolatedFromAbove);
1480f3acb54cSRiver Riddle 
14813128b310SMehdi Amini   LogicalResult parseRegion(RegionReadState &readState);
14823128b310SMehdi Amini   LogicalResult parseBlockHeader(EncodingReader &reader,
14833128b310SMehdi Amini                                  RegionReadState &readState);
1484f3acb54cSRiver Riddle   LogicalResult parseBlockArguments(EncodingReader &reader, Block *block);
1485f3acb54cSRiver Riddle 
1486f3acb54cSRiver Riddle   //===--------------------------------------------------------------------===//
1487f3acb54cSRiver Riddle   // Value Processing
1488f3acb54cSRiver Riddle 
1489f3acb54cSRiver Riddle   /// Parse an operand reference using the given reader. Returns nullptr in the
1490f3acb54cSRiver Riddle   /// case of failure.
1491f3acb54cSRiver Riddle   Value parseOperand(EncodingReader &reader);
1492f3acb54cSRiver Riddle 
1493f3acb54cSRiver Riddle   /// Sequentially define the given value range.
1494f3acb54cSRiver Riddle   LogicalResult defineValues(EncodingReader &reader, ValueRange values);
1495f3acb54cSRiver Riddle 
1496f3acb54cSRiver Riddle   /// Create a value to use for a forward reference.
1497f3acb54cSRiver Riddle   Value createForwardRef();
1498f3acb54cSRiver Riddle 
1499f3acb54cSRiver Riddle   //===--------------------------------------------------------------------===//
150061278191SMatteo Franciolini   // Use-list order helpers
150161278191SMatteo Franciolini 
150261278191SMatteo Franciolini   /// This struct is a simple storage that contains information required to
150361278191SMatteo Franciolini   /// reorder the use-list of a value with respect to the pre-order traversal
150461278191SMatteo Franciolini   /// ordering.
150561278191SMatteo Franciolini   struct UseListOrderStorage {
150661278191SMatteo Franciolini     UseListOrderStorage(bool isIndexPairEncoding,
150761278191SMatteo Franciolini                         SmallVector<unsigned, 4> &&indices)
150861278191SMatteo Franciolini         : indices(std::move(indices)),
150961278191SMatteo Franciolini           isIndexPairEncoding(isIndexPairEncoding){};
151061278191SMatteo Franciolini     /// The vector containing the information required to reorder the
151161278191SMatteo Franciolini     /// use-list of a value.
151261278191SMatteo Franciolini     SmallVector<unsigned, 4> indices;
151361278191SMatteo Franciolini 
151461278191SMatteo Franciolini     /// Whether indices represent a pair of type `(src, dst)` or it is a direct
151561278191SMatteo Franciolini     /// indexing, such as `dst = order[src]`.
151661278191SMatteo Franciolini     bool isIndexPairEncoding;
151761278191SMatteo Franciolini   };
151861278191SMatteo Franciolini 
151961278191SMatteo Franciolini   /// Parse use-list order from bytecode for a range of values if available. The
152061278191SMatteo Franciolini   /// range is expected to be either a block argument or an op result range. On
152161278191SMatteo Franciolini   /// success, return a map of the position in the range and the use-list order
152261278191SMatteo Franciolini   /// encoding. The function assumes to know the size of the range it is
152361278191SMatteo Franciolini   /// processing.
152461278191SMatteo Franciolini   using UseListMapT = DenseMap<unsigned, UseListOrderStorage>;
152561278191SMatteo Franciolini   FailureOr<UseListMapT> parseUseListOrderForRange(EncodingReader &reader,
152661278191SMatteo Franciolini                                                    uint64_t rangeSize);
152761278191SMatteo Franciolini 
152861278191SMatteo Franciolini   /// Shuffle the use-chain according to the order parsed.
152961278191SMatteo Franciolini   LogicalResult sortUseListOrder(Value value);
153061278191SMatteo Franciolini 
153161278191SMatteo Franciolini   /// Recursively visit all the values defined within topLevelOp and sort the
153261278191SMatteo Franciolini   /// use-list orders according to the indices parsed.
153361278191SMatteo Franciolini   LogicalResult processUseLists(Operation *topLevelOp);
153461278191SMatteo Franciolini 
153561278191SMatteo Franciolini   //===--------------------------------------------------------------------===//
1536f3acb54cSRiver Riddle   // Fields
1537f3acb54cSRiver Riddle 
1538f3acb54cSRiver Riddle   /// This class represents a single value scope, in which a value scope is
1539f3acb54cSRiver Riddle   /// delimited by isolated from above regions.
1540f3acb54cSRiver Riddle   struct ValueScope {
1541f3acb54cSRiver Riddle     /// Push a new region state onto this scope, reserving enough values for
1542f3acb54cSRiver Riddle     /// those defined within the current region of the provided state.
1543f3acb54cSRiver Riddle     void push(RegionReadState &readState) {
1544f3acb54cSRiver Riddle       nextValueIDs.push_back(values.size());
1545f3acb54cSRiver Riddle       values.resize(values.size() + readState.numValues);
1546f3acb54cSRiver Riddle     }
1547f3acb54cSRiver Riddle 
1548f3acb54cSRiver Riddle     /// Pop the values defined for the current region within the provided region
1549f3acb54cSRiver Riddle     /// state.
1550f3acb54cSRiver Riddle     void pop(RegionReadState &readState) {
1551f3acb54cSRiver Riddle       values.resize(values.size() - readState.numValues);
1552f3acb54cSRiver Riddle       nextValueIDs.pop_back();
1553f3acb54cSRiver Riddle     }
1554f3acb54cSRiver Riddle 
1555f3acb54cSRiver Riddle     /// The set of values defined in this scope.
1556f3acb54cSRiver Riddle     std::vector<Value> values;
1557f3acb54cSRiver Riddle 
1558f3acb54cSRiver Riddle     /// The ID for the next defined value for each region current being
1559f3acb54cSRiver Riddle     /// processed in this scope.
1560f3acb54cSRiver Riddle     SmallVector<unsigned, 4> nextValueIDs;
1561f3acb54cSRiver Riddle   };
1562f3acb54cSRiver Riddle 
1563f3acb54cSRiver Riddle   /// The configuration of the parser.
1564f3acb54cSRiver Riddle   const ParserConfig &config;
1565f3acb54cSRiver Riddle 
1566f3acb54cSRiver Riddle   /// A location to use when emitting errors.
1567f3acb54cSRiver Riddle   Location fileLoc;
1568f3acb54cSRiver Riddle 
15693128b310SMehdi Amini   /// Flag that indicates if lazyloading is enabled.
15703128b310SMehdi Amini   bool lazyLoading;
15713128b310SMehdi Amini 
15723128b310SMehdi Amini   /// Keep track of operations that have been lazy loaded (their regions haven't
15733128b310SMehdi Amini   /// been materialized), along with the `RegionReadState` that allows to
15743128b310SMehdi Amini   /// lazy-load the regions nested under the operation.
15753128b310SMehdi Amini   LazyLoadableOpsInfo lazyLoadableOps;
15763128b310SMehdi Amini   LazyLoadableOpsMap lazyLoadableOpsMap;
15773128b310SMehdi Amini   llvm::function_ref<bool(Operation *)> lazyOpsCallback;
15783128b310SMehdi Amini 
1579f3acb54cSRiver Riddle   /// The reader used to process attribute and types within the bytecode.
1580f3acb54cSRiver Riddle   AttrTypeReader attrTypeReader;
1581f3acb54cSRiver Riddle 
1582f3acb54cSRiver Riddle   /// The version of the bytecode being read.
1583f3acb54cSRiver Riddle   uint64_t version = 0;
1584f3acb54cSRiver Riddle 
1585f3acb54cSRiver Riddle   /// The producer of the bytecode being read.
1586f3acb54cSRiver Riddle   StringRef producer;
1587f3acb54cSRiver Riddle 
1588f3acb54cSRiver Riddle   /// The table of IR units referenced within the bytecode file.
1589bff6a429SMatteo Franciolini   SmallVector<std::unique_ptr<BytecodeDialect>> dialects;
1590bff6a429SMatteo Franciolini   llvm::StringMap<BytecodeDialect *> dialectsMap;
1591f3acb54cSRiver Riddle   SmallVector<BytecodeOperationName> opNames;
1592f3acb54cSRiver Riddle 
15936ab2bcffSRiver Riddle   /// The reader used to process resources within the bytecode.
15946ab2bcffSRiver Riddle   ResourceSectionReader resourceReader;
15956ab2bcffSRiver Riddle 
159661278191SMatteo Franciolini   /// Worklist of values with custom use-list orders to process before the end
159761278191SMatteo Franciolini   /// of the parsing.
159861278191SMatteo Franciolini   DenseMap<void *, UseListOrderStorage> valueToUseListMap;
159961278191SMatteo Franciolini 
1600f3acb54cSRiver Riddle   /// The table of strings referenced within the bytecode file.
160183dc9999SRiver Riddle   StringSectionReader stringReader;
1602f3acb54cSRiver Riddle 
1603660f714eSMehdi Amini   /// The table of properties referenced by the operation in the bytecode file.
1604660f714eSMehdi Amini   PropertiesSectionReader propertiesReader;
1605660f714eSMehdi Amini 
1606f3acb54cSRiver Riddle   /// The current set of available IR value scopes.
1607f3acb54cSRiver Riddle   std::vector<ValueScope> valueScopes;
160861278191SMatteo Franciolini 
160961278191SMatteo Franciolini   /// The global pre-order operation ordering.
161061278191SMatteo Franciolini   DenseMap<Operation *, unsigned> operationIDs;
161161278191SMatteo Franciolini 
1612f3acb54cSRiver Riddle   /// A block containing the set of operations defined to create forward
1613f3acb54cSRiver Riddle   /// references.
1614f3acb54cSRiver Riddle   Block forwardRefOps;
161561278191SMatteo Franciolini 
1616f3acb54cSRiver Riddle   /// A block containing previously created, and no longer used, forward
1617f3acb54cSRiver Riddle   /// reference operations.
1618f3acb54cSRiver Riddle   Block openForwardRefOps;
161961278191SMatteo Franciolini 
1620f3acb54cSRiver Riddle   /// An operation state used when instantiating forward references.
1621f3acb54cSRiver Riddle   OperationState forwardRefOpState;
162218546ff8SRiver Riddle 
16233128b310SMehdi Amini   /// Reference to the input buffer.
16243128b310SMehdi Amini   llvm::MemoryBufferRef buffer;
16253128b310SMehdi Amini 
162618546ff8SRiver Riddle   /// The optional owning source manager, which when present may be used to
162718546ff8SRiver Riddle   /// extend the lifetime of the input buffer.
162818546ff8SRiver Riddle   const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef;
1629f3acb54cSRiver Riddle };
1630f3acb54cSRiver Riddle 
16313128b310SMehdi Amini LogicalResult BytecodeReader::Impl::read(
16323128b310SMehdi Amini     Block *block, llvm::function_ref<bool(Operation *)> lazyOpsCallback) {
1633f3acb54cSRiver Riddle   EncodingReader reader(buffer.getBuffer(), fileLoc);
16343128b310SMehdi Amini   this->lazyOpsCallback = lazyOpsCallback;
16353128b310SMehdi Amini   auto resetlazyOpsCallback =
16363128b310SMehdi Amini       llvm::make_scope_exit([&] { this->lazyOpsCallback = nullptr; });
1637f3acb54cSRiver Riddle 
1638f3acb54cSRiver Riddle   // Skip over the bytecode header, this should have already been checked.
1639f3acb54cSRiver Riddle   if (failed(reader.skipBytes(StringRef("ML\xefR").size())))
1640f3acb54cSRiver Riddle     return failure();
1641f3acb54cSRiver Riddle   // Parse the bytecode version and producer.
1642f3acb54cSRiver Riddle   if (failed(parseVersion(reader)) ||
1643f3acb54cSRiver Riddle       failed(reader.parseNullTerminatedString(producer)))
1644f3acb54cSRiver Riddle     return failure();
1645f3acb54cSRiver Riddle 
1646f3acb54cSRiver Riddle   // Add a diagnostic handler that attaches a note that includes the original
1647f3acb54cSRiver Riddle   // producer of the bytecode.
1648f3acb54cSRiver Riddle   ScopedDiagnosticHandler diagHandler(getContext(), [&](Diagnostic &diag) {
1649f3acb54cSRiver Riddle     diag.attachNote() << "in bytecode version " << version
1650f3acb54cSRiver Riddle                       << " produced by: " << producer;
1651f3acb54cSRiver Riddle     return failure();
1652f3acb54cSRiver Riddle   });
1653f3acb54cSRiver Riddle 
1654f3acb54cSRiver Riddle   // Parse the raw data for each of the top-level sections of the bytecode.
16550a81ace0SKazu Hirata   std::optional<ArrayRef<uint8_t>>
16560a81ace0SKazu Hirata       sectionDatas[bytecode::Section::kNumSections];
1657f3acb54cSRiver Riddle   while (!reader.empty()) {
1658f3acb54cSRiver Riddle     // Read the next section from the bytecode.
1659f3acb54cSRiver Riddle     bytecode::Section::ID sectionID;
1660f3acb54cSRiver Riddle     ArrayRef<uint8_t> sectionData;
1661f3acb54cSRiver Riddle     if (failed(reader.parseSection(sectionID, sectionData)))
1662f3acb54cSRiver Riddle       return failure();
1663f3acb54cSRiver Riddle 
1664f3acb54cSRiver Riddle     // Check for duplicate sections, we only expect one instance of each.
1665f3acb54cSRiver Riddle     if (sectionDatas[sectionID]) {
1666f3acb54cSRiver Riddle       return reader.emitError("duplicate top-level section: ",
16673128b310SMehdi Amini                               ::toString(sectionID));
1668f3acb54cSRiver Riddle     }
1669f3acb54cSRiver Riddle     sectionDatas[sectionID] = sectionData;
1670f3acb54cSRiver Riddle   }
16716ab2bcffSRiver Riddle   // Check that all of the required sections were found.
1672f3acb54cSRiver Riddle   for (int i = 0; i < bytecode::Section::kNumSections; ++i) {
16736ab2bcffSRiver Riddle     bytecode::Section::ID sectionID = static_cast<bytecode::Section::ID>(i);
1674660f714eSMehdi Amini     if (!sectionDatas[i] && !isSectionOptional(sectionID, version)) {
1675f3acb54cSRiver Riddle       return reader.emitError("missing data for top-level section: ",
16763128b310SMehdi Amini                               ::toString(sectionID));
1677f3acb54cSRiver Riddle     }
1678f3acb54cSRiver Riddle   }
1679f3acb54cSRiver Riddle 
1680f3acb54cSRiver Riddle   // Process the string section first.
168183dc9999SRiver Riddle   if (failed(stringReader.initialize(
168283dc9999SRiver Riddle           fileLoc, *sectionDatas[bytecode::Section::kString])))
1683f3acb54cSRiver Riddle     return failure();
1684f3acb54cSRiver Riddle 
1685660f714eSMehdi Amini   // Process the properties section.
1686660f714eSMehdi Amini   if (sectionDatas[bytecode::Section::kProperties] &&
1687660f714eSMehdi Amini       failed(propertiesReader.initialize(
1688660f714eSMehdi Amini           fileLoc, *sectionDatas[bytecode::Section::kProperties])))
1689660f714eSMehdi Amini     return failure();
1690660f714eSMehdi Amini 
1691f3acb54cSRiver Riddle   // Process the dialect section.
1692f3acb54cSRiver Riddle   if (failed(parseDialectSection(*sectionDatas[bytecode::Section::kDialect])))
1693f3acb54cSRiver Riddle     return failure();
1694f3acb54cSRiver Riddle 
16956ab2bcffSRiver Riddle   // Process the resource section if present.
16966ab2bcffSRiver Riddle   if (failed(parseResourceSection(
16970e0b6070SMatteo Franciolini           reader, sectionDatas[bytecode::Section::kResource],
16986ab2bcffSRiver Riddle           sectionDatas[bytecode::Section::kResourceOffset])))
16996ab2bcffSRiver Riddle     return failure();
17006ab2bcffSRiver Riddle 
1701f3acb54cSRiver Riddle   // Process the attribute and type section.
1702f3acb54cSRiver Riddle   if (failed(attrTypeReader.initialize(
1703f3acb54cSRiver Riddle           dialects, *sectionDatas[bytecode::Section::kAttrType],
1704f3acb54cSRiver Riddle           *sectionDatas[bytecode::Section::kAttrTypeOffset])))
1705f3acb54cSRiver Riddle     return failure();
1706f3acb54cSRiver Riddle 
1707f3acb54cSRiver Riddle   // Finally, process the IR section.
1708f3acb54cSRiver Riddle   return parseIRSection(*sectionDatas[bytecode::Section::kIR], block);
1709f3acb54cSRiver Riddle }
1710f3acb54cSRiver Riddle 
17113128b310SMehdi Amini LogicalResult BytecodeReader::Impl::parseVersion(EncodingReader &reader) {
1712f3acb54cSRiver Riddle   if (failed(reader.parseVarInt(version)))
1713f3acb54cSRiver Riddle     return failure();
1714f3acb54cSRiver Riddle 
1715f3acb54cSRiver Riddle   // Validate the bytecode version.
1716f3acb54cSRiver Riddle   uint64_t currentVersion = bytecode::kVersion;
17170e0b6070SMatteo Franciolini   uint64_t minSupportedVersion = bytecode::kMinSupportedVersion;
17180e0b6070SMatteo Franciolini   if (version < minSupportedVersion) {
1719f3acb54cSRiver Riddle     return reader.emitError("bytecode version ", version,
1720f3acb54cSRiver Riddle                             " is older than the current version of ",
1721f3acb54cSRiver Riddle                             currentVersion, ", and upgrade is not supported");
1722f3acb54cSRiver Riddle   }
1723f3acb54cSRiver Riddle   if (version > currentVersion) {
1724f3acb54cSRiver Riddle     return reader.emitError("bytecode version ", version,
1725f3acb54cSRiver Riddle                             " is newer than the current version ",
1726f3acb54cSRiver Riddle                             currentVersion);
1727f3acb54cSRiver Riddle   }
17283128b310SMehdi Amini   // Override any request to lazy-load if the bytecode version is too old.
17299c1e5587SMehdi Amini   if (version < bytecode::kLazyLoading)
17303128b310SMehdi Amini     lazyLoading = false;
1731f3acb54cSRiver Riddle   return success();
1732f3acb54cSRiver Riddle }
1733f3acb54cSRiver Riddle 
1734f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
1735f3acb54cSRiver Riddle // Dialect Section
1736f3acb54cSRiver Riddle 
1737bff6a429SMatteo Franciolini LogicalResult BytecodeDialect::load(const DialectReader &reader,
1738bff6a429SMatteo Franciolini                                     MLIRContext *ctx) {
17390e0b6070SMatteo Franciolini   if (dialect)
17400e0b6070SMatteo Franciolini     return success();
17410e0b6070SMatteo Franciolini   Dialect *loadedDialect = ctx->getOrLoadDialect(name);
17420e0b6070SMatteo Franciolini   if (!loadedDialect && !ctx->allowsUnregisteredDialects()) {
17430e0b6070SMatteo Franciolini     return reader.emitError("dialect '")
17440e0b6070SMatteo Franciolini            << name
17450e0b6070SMatteo Franciolini            << "' is unknown. If this is intended, please call "
17460e0b6070SMatteo Franciolini               "allowUnregisteredDialects() on the MLIRContext, or use "
17470e0b6070SMatteo Franciolini               "-allow-unregistered-dialect with the MLIR tool used.";
17480e0b6070SMatteo Franciolini   }
17490e0b6070SMatteo Franciolini   dialect = loadedDialect;
17500e0b6070SMatteo Franciolini 
17510e0b6070SMatteo Franciolini   // If the dialect was actually loaded, check to see if it has a bytecode
17520e0b6070SMatteo Franciolini   // interface.
17530e0b6070SMatteo Franciolini   if (loadedDialect)
17540e0b6070SMatteo Franciolini     interface = dyn_cast<BytecodeDialectInterface>(loadedDialect);
17550e0b6070SMatteo Franciolini   if (!versionBuffer.empty()) {
17560e0b6070SMatteo Franciolini     if (!interface)
17570e0b6070SMatteo Franciolini       return reader.emitError("dialect '")
17580e0b6070SMatteo Franciolini              << name
17590e0b6070SMatteo Franciolini              << "' does not implement the bytecode interface, "
17600e0b6070SMatteo Franciolini                 "but found a version entry";
17613449e7a8SJacques Pienaar     EncodingReader encReader(versionBuffer, reader.getLoc());
17623449e7a8SJacques Pienaar     DialectReader versionReader = reader.withEncodingReader(encReader);
17633449e7a8SJacques Pienaar     loadedVersion = interface->readVersion(versionReader);
17640e0b6070SMatteo Franciolini     if (!loadedVersion)
17650e0b6070SMatteo Franciolini       return failure();
17660e0b6070SMatteo Franciolini   }
17670e0b6070SMatteo Franciolini   return success();
17680e0b6070SMatteo Franciolini }
17690e0b6070SMatteo Franciolini 
1770f3acb54cSRiver Riddle LogicalResult
17713128b310SMehdi Amini BytecodeReader::Impl::parseDialectSection(ArrayRef<uint8_t> sectionData) {
1772f3acb54cSRiver Riddle   EncodingReader sectionReader(sectionData, fileLoc);
1773f3acb54cSRiver Riddle 
1774f3acb54cSRiver Riddle   // Parse the number of dialects in the section.
1775f3acb54cSRiver Riddle   uint64_t numDialects;
1776f3acb54cSRiver Riddle   if (failed(sectionReader.parseVarInt(numDialects)))
1777f3acb54cSRiver Riddle     return failure();
1778f3acb54cSRiver Riddle   dialects.resize(numDialects);
1779f3acb54cSRiver Riddle 
1780f3acb54cSRiver Riddle   // Parse each of the dialects.
17810e0b6070SMatteo Franciolini   for (uint64_t i = 0; i < numDialects; ++i) {
1782bff6a429SMatteo Franciolini     dialects[i] = std::make_unique<BytecodeDialect>();
17839c1e5587SMehdi Amini     /// Before version kDialectVersioning, there wasn't any versioning available
17849c1e5587SMehdi Amini     /// for dialects, and the entryIdx represent the string itself.
17859c1e5587SMehdi Amini     if (version < bytecode::kDialectVersioning) {
1786bff6a429SMatteo Franciolini       if (failed(stringReader.parseString(sectionReader, dialects[i]->name)))
1787f3acb54cSRiver Riddle         return failure();
17880e0b6070SMatteo Franciolini       continue;
17890e0b6070SMatteo Franciolini     }
1790bff6a429SMatteo Franciolini 
17910e0b6070SMatteo Franciolini     // Parse ID representing dialect and version.
17920e0b6070SMatteo Franciolini     uint64_t dialectNameIdx;
17930e0b6070SMatteo Franciolini     bool versionAvailable;
17940e0b6070SMatteo Franciolini     if (failed(sectionReader.parseVarIntWithFlag(dialectNameIdx,
17950e0b6070SMatteo Franciolini                                                  versionAvailable)))
17960e0b6070SMatteo Franciolini       return failure();
17970e0b6070SMatteo Franciolini     if (failed(stringReader.parseStringAtIndex(sectionReader, dialectNameIdx,
1798bff6a429SMatteo Franciolini                                                dialects[i]->name)))
17990e0b6070SMatteo Franciolini       return failure();
18000e0b6070SMatteo Franciolini     if (versionAvailable) {
18010e0b6070SMatteo Franciolini       bytecode::Section::ID sectionID;
1802bff6a429SMatteo Franciolini       if (failed(sectionReader.parseSection(sectionID,
1803bff6a429SMatteo Franciolini                                             dialects[i]->versionBuffer)))
18040e0b6070SMatteo Franciolini         return failure();
18050e0b6070SMatteo Franciolini       if (sectionID != bytecode::Section::kDialectVersions) {
18060e0b6070SMatteo Franciolini         emitError(fileLoc, "expected dialect version section");
18070e0b6070SMatteo Franciolini         return failure();
18080e0b6070SMatteo Franciolini       }
18090e0b6070SMatteo Franciolini     }
1810bff6a429SMatteo Franciolini     dialectsMap[dialects[i]->name] = dialects[i].get();
18110e0b6070SMatteo Franciolini   }
1812f3acb54cSRiver Riddle 
1813f3acb54cSRiver Riddle   // Parse the operation names, which are grouped by dialect.
1814f3acb54cSRiver Riddle   auto parseOpName = [&](BytecodeDialect *dialect) {
1815f3acb54cSRiver Riddle     StringRef opName;
1816660f714eSMehdi Amini     std::optional<bool> wasRegistered;
18179c1e5587SMehdi Amini     // Prior to version kNativePropertiesEncoding, the information about wheter
18189c1e5587SMehdi Amini     // an op was registered or not wasn't encoded.
18199c1e5587SMehdi Amini     if (version < bytecode::kNativePropertiesEncoding) {
182083dc9999SRiver Riddle       if (failed(stringReader.parseString(sectionReader, opName)))
1821f3acb54cSRiver Riddle         return failure();
1822660f714eSMehdi Amini     } else {
1823660f714eSMehdi Amini       bool wasRegisteredFlag;
1824660f714eSMehdi Amini       if (failed(stringReader.parseStringWithFlag(sectionReader, opName,
1825660f714eSMehdi Amini                                                   wasRegisteredFlag)))
1826660f714eSMehdi Amini         return failure();
1827660f714eSMehdi Amini       wasRegistered = wasRegisteredFlag;
1828660f714eSMehdi Amini     }
1829660f714eSMehdi Amini     opNames.emplace_back(dialect, opName, wasRegistered);
1830f3acb54cSRiver Riddle     return success();
1831f3acb54cSRiver Riddle   };
18329c1e5587SMehdi Amini   // Avoid re-allocation in bytecode version >=kElideUnknownBlockArgLocation
18339c1e5587SMehdi Amini   // where the number of ops are known.
18349c1e5587SMehdi Amini   if (version >= bytecode::kElideUnknownBlockArgLocation) {
18351826fadbSJacques Pienaar     uint64_t numOps;
18361826fadbSJacques Pienaar     if (failed(sectionReader.parseVarInt(numOps)))
18371826fadbSJacques Pienaar       return failure();
18381826fadbSJacques Pienaar     opNames.reserve(numOps);
18391826fadbSJacques Pienaar   }
1840f3acb54cSRiver Riddle   while (!sectionReader.empty())
1841f3acb54cSRiver Riddle     if (failed(parseDialectGrouping(sectionReader, dialects, parseOpName)))
1842f3acb54cSRiver Riddle       return failure();
1843f3acb54cSRiver Riddle   return success();
1844f3acb54cSRiver Riddle }
1845f3acb54cSRiver Riddle 
18463128b310SMehdi Amini FailureOr<OperationName>
1847660f714eSMehdi Amini BytecodeReader::Impl::parseOpName(EncodingReader &reader,
1848660f714eSMehdi Amini                                   std::optional<bool> &wasRegistered) {
1849f3acb54cSRiver Riddle   BytecodeOperationName *opName = nullptr;
1850f3acb54cSRiver Riddle   if (failed(parseEntry(reader, opNames, opName, "operation name")))
1851f3acb54cSRiver Riddle     return failure();
1852660f714eSMehdi Amini   wasRegistered = opName->wasRegistered;
1853f3acb54cSRiver Riddle   // Check to see if this operation name has already been resolved. If we
1854f3acb54cSRiver Riddle   // haven't, load the dialect and build the operation name.
1855f3acb54cSRiver Riddle   if (!opName->opName) {
18563b0106feSMehdi Amini     // If the opName is empty, this is because we use to accept names such as
18573b0106feSMehdi Amini     // `foo` without any `.` separator. We shouldn't tolerate this in textual
18583b0106feSMehdi Amini     // format anymore but for now we'll be backward compatible. This can only
18593b0106feSMehdi Amini     // happen with unregistered dialects.
18603b0106feSMehdi Amini     if (opName->name.empty()) {
18613b0106feSMehdi Amini       opName->opName.emplace(opName->dialect->name, getContext());
18623b0106feSMehdi Amini     } else {
1863da092e88SMatteo Franciolini       // Load the dialect and its version.
1864da092e88SMatteo Franciolini       DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1865da092e88SMatteo Franciolini                                   dialectsMap, reader, version);
1866da092e88SMatteo Franciolini       if (failed(opName->dialect->load(dialectReader, getContext())))
1867da092e88SMatteo Franciolini         return failure();
1868f3acb54cSRiver Riddle       opName->opName.emplace((opName->dialect->name + "." + opName->name).str(),
1869f3acb54cSRiver Riddle                              getContext());
1870f3acb54cSRiver Riddle     }
18713b0106feSMehdi Amini   }
1872f3acb54cSRiver Riddle   return *opName->opName;
1873f3acb54cSRiver Riddle }
1874f3acb54cSRiver Riddle 
1875f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
18766ab2bcffSRiver Riddle // Resource Section
18776ab2bcffSRiver Riddle 
18783128b310SMehdi Amini LogicalResult BytecodeReader::Impl::parseResourceSection(
18790e0b6070SMatteo Franciolini     EncodingReader &reader, std::optional<ArrayRef<uint8_t>> resourceData,
18800a81ace0SKazu Hirata     std::optional<ArrayRef<uint8_t>> resourceOffsetData) {
18816ab2bcffSRiver Riddle   // Ensure both sections are either present or not.
18826ab2bcffSRiver Riddle   if (resourceData.has_value() != resourceOffsetData.has_value()) {
18836ab2bcffSRiver Riddle     if (resourceOffsetData)
18846ab2bcffSRiver Riddle       return emitError(fileLoc, "unexpected resource offset section when "
18856ab2bcffSRiver Riddle                                 "resource section is not present");
18866ab2bcffSRiver Riddle     return emitError(
18876ab2bcffSRiver Riddle         fileLoc,
18886ab2bcffSRiver Riddle         "expected resource offset section when resource section is present");
18896ab2bcffSRiver Riddle   }
18906ab2bcffSRiver Riddle 
18916ab2bcffSRiver Riddle   // If the resource sections are absent, there is nothing to do.
18926ab2bcffSRiver Riddle   if (!resourceData)
18936ab2bcffSRiver Riddle     return success();
18946ab2bcffSRiver Riddle 
18956ab2bcffSRiver Riddle   // Initialize the resource reader with the resource sections.
18960e0b6070SMatteo Franciolini   DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
1897bff6a429SMatteo Franciolini                               dialectsMap, reader, version);
18986ab2bcffSRiver Riddle   return resourceReader.initialize(fileLoc, config, dialects, stringReader,
189918546ff8SRiver Riddle                                    *resourceData, *resourceOffsetData,
19000e0b6070SMatteo Franciolini                                    dialectReader, bufferOwnerRef);
19016ab2bcffSRiver Riddle }
19026ab2bcffSRiver Riddle 
19036ab2bcffSRiver Riddle //===----------------------------------------------------------------------===//
190461278191SMatteo Franciolini // UseListOrder Helpers
190561278191SMatteo Franciolini 
190661278191SMatteo Franciolini FailureOr<BytecodeReader::Impl::UseListMapT>
190761278191SMatteo Franciolini BytecodeReader::Impl::parseUseListOrderForRange(EncodingReader &reader,
190861278191SMatteo Franciolini                                                 uint64_t numResults) {
190961278191SMatteo Franciolini   BytecodeReader::Impl::UseListMapT map;
191061278191SMatteo Franciolini   uint64_t numValuesToRead = 1;
191161278191SMatteo Franciolini   if (numResults > 1 && failed(reader.parseVarInt(numValuesToRead)))
191261278191SMatteo Franciolini     return failure();
191361278191SMatteo Franciolini 
191461278191SMatteo Franciolini   for (size_t valueIdx = 0; valueIdx < numValuesToRead; valueIdx++) {
191561278191SMatteo Franciolini     uint64_t resultIdx = 0;
191661278191SMatteo Franciolini     if (numResults > 1 && failed(reader.parseVarInt(resultIdx)))
191761278191SMatteo Franciolini       return failure();
191861278191SMatteo Franciolini 
191961278191SMatteo Franciolini     uint64_t numValues;
192061278191SMatteo Franciolini     bool indexPairEncoding;
192161278191SMatteo Franciolini     if (failed(reader.parseVarIntWithFlag(numValues, indexPairEncoding)))
192261278191SMatteo Franciolini       return failure();
192361278191SMatteo Franciolini 
192461278191SMatteo Franciolini     SmallVector<unsigned, 4> useListOrders;
192561278191SMatteo Franciolini     for (size_t idx = 0; idx < numValues; idx++) {
192661278191SMatteo Franciolini       uint64_t index;
192761278191SMatteo Franciolini       if (failed(reader.parseVarInt(index)))
192861278191SMatteo Franciolini         return failure();
192961278191SMatteo Franciolini       useListOrders.push_back(index);
193061278191SMatteo Franciolini     }
193161278191SMatteo Franciolini 
193261278191SMatteo Franciolini     // Store in a map the result index
193361278191SMatteo Franciolini     map.try_emplace(resultIdx, UseListOrderStorage(indexPairEncoding,
193461278191SMatteo Franciolini                                                    std::move(useListOrders)));
193561278191SMatteo Franciolini   }
193661278191SMatteo Franciolini 
193761278191SMatteo Franciolini   return map;
193861278191SMatteo Franciolini }
193961278191SMatteo Franciolini 
194061278191SMatteo Franciolini /// Sorts each use according to the order specified in the use-list parsed. If
194161278191SMatteo Franciolini /// the custom use-list is not found, this means that the order needs to be
194261278191SMatteo Franciolini /// consistent with the reverse pre-order walk of the IR. If multiple uses lie
194361278191SMatteo Franciolini /// on the same operation, the order will follow the reverse operand number
194461278191SMatteo Franciolini /// ordering.
194561278191SMatteo Franciolini LogicalResult BytecodeReader::Impl::sortUseListOrder(Value value) {
194661278191SMatteo Franciolini   // Early return for trivial use-lists.
194761278191SMatteo Franciolini   if (value.use_empty() || value.hasOneUse())
194861278191SMatteo Franciolini     return success();
194961278191SMatteo Franciolini 
195061278191SMatteo Franciolini   bool hasIncomingOrder =
195161278191SMatteo Franciolini       valueToUseListMap.contains(value.getAsOpaquePointer());
195261278191SMatteo Franciolini 
195361278191SMatteo Franciolini   // Compute the current order of the use-list with respect to the global
195461278191SMatteo Franciolini   // ordering. Detect if the order is already sorted while doing so.
195561278191SMatteo Franciolini   bool alreadySorted = true;
195661278191SMatteo Franciolini   auto &firstUse = *value.use_begin();
195761278191SMatteo Franciolini   uint64_t prevID =
195861278191SMatteo Franciolini       bytecode::getUseID(firstUse, operationIDs.at(firstUse.getOwner()));
195961278191SMatteo Franciolini   llvm::SmallVector<std::pair<unsigned, uint64_t>> currentOrder = {{0, prevID}};
196061278191SMatteo Franciolini   for (auto item : llvm::drop_begin(llvm::enumerate(value.getUses()))) {
196161278191SMatteo Franciolini     uint64_t currentID = bytecode::getUseID(
196261278191SMatteo Franciolini         item.value(), operationIDs.at(item.value().getOwner()));
196361278191SMatteo Franciolini     alreadySorted &= prevID > currentID;
196461278191SMatteo Franciolini     currentOrder.push_back({item.index(), currentID});
196561278191SMatteo Franciolini     prevID = currentID;
196661278191SMatteo Franciolini   }
196761278191SMatteo Franciolini 
196861278191SMatteo Franciolini   // If the order is already sorted, and there wasn't a custom order to apply
196961278191SMatteo Franciolini   // from the bytecode file, we are done.
197061278191SMatteo Franciolini   if (alreadySorted && !hasIncomingOrder)
197161278191SMatteo Franciolini     return success();
197261278191SMatteo Franciolini 
197361278191SMatteo Franciolini   // If not already sorted, sort the indices of the current order by descending
197461278191SMatteo Franciolini   // useIDs.
197561278191SMatteo Franciolini   if (!alreadySorted)
197661278191SMatteo Franciolini     std::sort(
197761278191SMatteo Franciolini         currentOrder.begin(), currentOrder.end(),
197861278191SMatteo Franciolini         [](auto elem1, auto elem2) { return elem1.second > elem2.second; });
197961278191SMatteo Franciolini 
198061278191SMatteo Franciolini   if (!hasIncomingOrder) {
198161278191SMatteo Franciolini     // If the bytecode file did not contain any custom use-list order, it means
198261278191SMatteo Franciolini     // that the order was descending useID. Hence, shuffle by the first index
198361278191SMatteo Franciolini     // of the `currentOrder` pair.
198461278191SMatteo Franciolini     SmallVector<unsigned> shuffle = SmallVector<unsigned>(
198561278191SMatteo Franciolini         llvm::map_range(currentOrder, [&](auto item) { return item.first; }));
198661278191SMatteo Franciolini     value.shuffleUseList(shuffle);
198761278191SMatteo Franciolini     return success();
198861278191SMatteo Franciolini   }
198961278191SMatteo Franciolini 
199061278191SMatteo Franciolini   // Pull the custom order info from the map.
199161278191SMatteo Franciolini   UseListOrderStorage customOrder =
199261278191SMatteo Franciolini       valueToUseListMap.at(value.getAsOpaquePointer());
199361278191SMatteo Franciolini   SmallVector<unsigned, 4> shuffle = std::move(customOrder.indices);
199461278191SMatteo Franciolini   uint64_t numUses =
199561278191SMatteo Franciolini       std::distance(value.getUses().begin(), value.getUses().end());
199661278191SMatteo Franciolini 
199761278191SMatteo Franciolini   // If the encoding was a pair of indices `(src, dst)` for every permutation,
199861278191SMatteo Franciolini   // reconstruct the shuffle vector for every use. Initialize the shuffle vector
199961278191SMatteo Franciolini   // as identity, and then apply the mapping encoded in the indices.
200061278191SMatteo Franciolini   if (customOrder.isIndexPairEncoding) {
200161278191SMatteo Franciolini     // Return failure if the number of indices was not representing pairs.
200261278191SMatteo Franciolini     if (shuffle.size() & 1)
200361278191SMatteo Franciolini       return failure();
200461278191SMatteo Franciolini 
200561278191SMatteo Franciolini     SmallVector<unsigned, 4> newShuffle(numUses);
200661278191SMatteo Franciolini     size_t idx = 0;
200761278191SMatteo Franciolini     std::iota(newShuffle.begin(), newShuffle.end(), idx);
200861278191SMatteo Franciolini     for (idx = 0; idx < shuffle.size(); idx += 2)
200961278191SMatteo Franciolini       newShuffle[shuffle[idx]] = shuffle[idx + 1];
201061278191SMatteo Franciolini 
201161278191SMatteo Franciolini     shuffle = std::move(newShuffle);
201261278191SMatteo Franciolini   }
201361278191SMatteo Franciolini 
201461278191SMatteo Franciolini   // Make sure that the indices represent a valid mapping. That is, the sum of
201561278191SMatteo Franciolini   // all the values needs to be equal to (numUses - 1) * numUses / 2, and no
201661278191SMatteo Franciolini   // duplicates are allowed in the list.
201761278191SMatteo Franciolini   DenseSet<unsigned> set;
201861278191SMatteo Franciolini   uint64_t accumulator = 0;
201961278191SMatteo Franciolini   for (const auto &elem : shuffle) {
202085c97c1cSKazu Hirata     if (!set.insert(elem).second)
202161278191SMatteo Franciolini       return failure();
202261278191SMatteo Franciolini     accumulator += elem;
202361278191SMatteo Franciolini   }
202461278191SMatteo Franciolini   if (numUses != shuffle.size() ||
202561278191SMatteo Franciolini       accumulator != (((numUses - 1) * numUses) >> 1))
202661278191SMatteo Franciolini     return failure();
202761278191SMatteo Franciolini 
202861278191SMatteo Franciolini   // Apply the current ordering map onto the shuffle vector to get the final
202961278191SMatteo Franciolini   // use-list sorting indices before shuffling.
203061278191SMatteo Franciolini   shuffle = SmallVector<unsigned, 4>(llvm::map_range(
203161278191SMatteo Franciolini       currentOrder, [&](auto item) { return shuffle[item.first]; }));
203261278191SMatteo Franciolini   value.shuffleUseList(shuffle);
203361278191SMatteo Franciolini   return success();
203461278191SMatteo Franciolini }
203561278191SMatteo Franciolini 
203661278191SMatteo Franciolini LogicalResult BytecodeReader::Impl::processUseLists(Operation *topLevelOp) {
203761278191SMatteo Franciolini   // Precompute operation IDs according to the pre-order walk of the IR. We
203861278191SMatteo Franciolini   // can't do this while parsing since parseRegions ordering is not strictly
203961278191SMatteo Franciolini   // equal to the pre-order walk.
204061278191SMatteo Franciolini   unsigned operationID = 0;
204161278191SMatteo Franciolini   topLevelOp->walk<mlir::WalkOrder::PreOrder>(
204261278191SMatteo Franciolini       [&](Operation *op) { operationIDs.try_emplace(op, operationID++); });
204361278191SMatteo Franciolini 
204461278191SMatteo Franciolini   auto blockWalk = topLevelOp->walk([this](Block *block) {
204561278191SMatteo Franciolini     for (auto arg : block->getArguments())
204661278191SMatteo Franciolini       if (failed(sortUseListOrder(arg)))
204761278191SMatteo Franciolini         return WalkResult::interrupt();
204861278191SMatteo Franciolini     return WalkResult::advance();
204961278191SMatteo Franciolini   });
205061278191SMatteo Franciolini 
205161278191SMatteo Franciolini   auto resultWalk = topLevelOp->walk([this](Operation *op) {
205261278191SMatteo Franciolini     for (auto result : op->getResults())
205361278191SMatteo Franciolini       if (failed(sortUseListOrder(result)))
205461278191SMatteo Franciolini         return WalkResult::interrupt();
205561278191SMatteo Franciolini     return WalkResult::advance();
205661278191SMatteo Franciolini   });
205761278191SMatteo Franciolini 
205861278191SMatteo Franciolini   return failure(blockWalk.wasInterrupted() || resultWalk.wasInterrupted());
205961278191SMatteo Franciolini }
206061278191SMatteo Franciolini 
206161278191SMatteo Franciolini //===----------------------------------------------------------------------===//
2062f3acb54cSRiver Riddle // IR Section
2063f3acb54cSRiver Riddle 
20643128b310SMehdi Amini LogicalResult
20653128b310SMehdi Amini BytecodeReader::Impl::parseIRSection(ArrayRef<uint8_t> sectionData,
2066f3acb54cSRiver Riddle                                      Block *block) {
2067f3acb54cSRiver Riddle   EncodingReader reader(sectionData, fileLoc);
2068f3acb54cSRiver Riddle 
2069f3acb54cSRiver Riddle   // A stack of operation regions currently being read from the bytecode.
2070f3acb54cSRiver Riddle   std::vector<RegionReadState> regionStack;
2071f3acb54cSRiver Riddle 
2072f3acb54cSRiver Riddle   // Parse the top-level block using a temporary module operation.
2073f3acb54cSRiver Riddle   OwningOpRef<ModuleOp> moduleOp = ModuleOp::create(fileLoc);
20743128b310SMehdi Amini   regionStack.emplace_back(*moduleOp, &reader, /*isIsolatedFromAbove=*/true);
2075f3acb54cSRiver Riddle   regionStack.back().curBlocks.push_back(moduleOp->getBody());
2076f3acb54cSRiver Riddle   regionStack.back().curBlock = regionStack.back().curRegion->begin();
20773128b310SMehdi Amini   if (failed(parseBlockHeader(reader, regionStack.back())))
2078f3acb54cSRiver Riddle     return failure();
207935cf7e8bSMehdi Amini   valueScopes.emplace_back();
2080f3acb54cSRiver Riddle   valueScopes.back().push(regionStack.back());
2081f3acb54cSRiver Riddle 
2082f3acb54cSRiver Riddle   // Iteratively parse regions until everything has been resolved.
2083f3acb54cSRiver Riddle   while (!regionStack.empty())
20843128b310SMehdi Amini     if (failed(parseRegions(regionStack, regionStack.back())))
2085f3acb54cSRiver Riddle       return failure();
2086f3acb54cSRiver Riddle   if (!forwardRefOps.empty()) {
2087f3acb54cSRiver Riddle     return reader.emitError(
2088f3acb54cSRiver Riddle         "not all forward unresolved forward operand references");
2089f3acb54cSRiver Riddle   }
2090f3acb54cSRiver Riddle 
209161278191SMatteo Franciolini   // Sort use-lists according to what specified in bytecode.
209261278191SMatteo Franciolini   if (failed(processUseLists(*moduleOp)))
209361278191SMatteo Franciolini     return reader.emitError(
209461278191SMatteo Franciolini         "parsed use-list orders were invalid and could not be applied");
209561278191SMatteo Franciolini 
20960e0b6070SMatteo Franciolini   // Resolve dialect version.
2097bff6a429SMatteo Franciolini   for (const std::unique_ptr<BytecodeDialect> &byteCodeDialect : dialects) {
20980e0b6070SMatteo Franciolini     // Parsing is complete, give an opportunity to each dialect to visit the
20990e0b6070SMatteo Franciolini     // IR and perform upgrades.
2100bff6a429SMatteo Franciolini     if (!byteCodeDialect->loadedVersion)
21010e0b6070SMatteo Franciolini       continue;
2102bff6a429SMatteo Franciolini     if (byteCodeDialect->interface &&
2103bff6a429SMatteo Franciolini         failed(byteCodeDialect->interface->upgradeFromVersion(
2104bff6a429SMatteo Franciolini             *moduleOp, *byteCodeDialect->loadedVersion)))
21050e0b6070SMatteo Franciolini       return failure();
21060e0b6070SMatteo Franciolini   }
21070e0b6070SMatteo Franciolini 
2108f3acb54cSRiver Riddle   // Verify that the parsed operations are valid.
21091ae60e04SRiver Riddle   if (config.shouldVerifyAfterParse() && failed(verify(*moduleOp)))
2110f3acb54cSRiver Riddle     return failure();
2111f3acb54cSRiver Riddle 
2112f3acb54cSRiver Riddle   // Splice the parsed operations over to the provided top-level block.
2113f3acb54cSRiver Riddle   auto &parsedOps = moduleOp->getBody()->getOperations();
2114f3acb54cSRiver Riddle   auto &destOps = block->getOperations();
211554cdc03dSRiver Riddle   destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), parsedOps.end());
2116f3acb54cSRiver Riddle   return success();
2117f3acb54cSRiver Riddle }
2118f3acb54cSRiver Riddle 
2119f3acb54cSRiver Riddle LogicalResult
21203128b310SMehdi Amini BytecodeReader::Impl::parseRegions(std::vector<RegionReadState> &regionStack,
2121f3acb54cSRiver Riddle                                    RegionReadState &readState) {
21223128b310SMehdi Amini   // Process regions, blocks, and operations until the end or if a nested
21233128b310SMehdi Amini   // region is encountered. In this case we push a new state in regionStack and
21243128b310SMehdi Amini   // return, the processing of the current region will resume afterward.
2125f3acb54cSRiver Riddle   for (; readState.curRegion != readState.endRegion; ++readState.curRegion) {
2126f3acb54cSRiver Riddle     // If the current block hasn't been setup yet, parse the header for this
21273128b310SMehdi Amini     // region. The current block is already setup when this function was
21283128b310SMehdi Amini     // interrupted to recurse down in a nested region and we resume the current
21293128b310SMehdi Amini     // block after processing the nested region.
2130f3acb54cSRiver Riddle     if (readState.curBlock == Region::iterator()) {
21313128b310SMehdi Amini       if (failed(parseRegion(readState)))
2132f3acb54cSRiver Riddle         return failure();
2133f3acb54cSRiver Riddle 
2134f3acb54cSRiver Riddle       // If the region is empty, there is nothing to more to do.
2135f3acb54cSRiver Riddle       if (readState.curRegion->empty())
2136f3acb54cSRiver Riddle         continue;
2137f3acb54cSRiver Riddle     }
2138f3acb54cSRiver Riddle 
2139f3acb54cSRiver Riddle     // Parse the blocks within the region.
21403128b310SMehdi Amini     EncodingReader &reader = *readState.reader;
2141f3acb54cSRiver Riddle     do {
2142f3acb54cSRiver Riddle       while (readState.numOpsRemaining--) {
2143f3acb54cSRiver Riddle         // Read in the next operation. We don't read its regions directly, we
2144f3acb54cSRiver Riddle         // handle those afterwards as necessary.
2145f3acb54cSRiver Riddle         bool isIsolatedFromAbove = false;
2146f3acb54cSRiver Riddle         FailureOr<Operation *> op =
2147f3acb54cSRiver Riddle             parseOpWithoutRegions(reader, readState, isIsolatedFromAbove);
2148f3acb54cSRiver Riddle         if (failed(op))
2149f3acb54cSRiver Riddle           return failure();
2150f3acb54cSRiver Riddle 
21513128b310SMehdi Amini         // If the op has regions, add it to the stack for processing and return:
21523128b310SMehdi Amini         // we stop the processing of the current region and resume it after the
21533128b310SMehdi Amini         // inner one is completed. Unless LazyLoading is activated in which case
21543128b310SMehdi Amini         // nested region parsing is delayed.
2155f3acb54cSRiver Riddle         if ((*op)->getNumRegions()) {
21563128b310SMehdi Amini           RegionReadState childState(*op, &reader, isIsolatedFromAbove);
21573128b310SMehdi Amini 
21583128b310SMehdi Amini           // Isolated regions are encoded as a section in version 2 and above.
21599c1e5587SMehdi Amini           if (version >= bytecode::kLazyLoading && isIsolatedFromAbove) {
21603128b310SMehdi Amini             bytecode::Section::ID sectionID;
21613128b310SMehdi Amini             ArrayRef<uint8_t> sectionData;
21623128b310SMehdi Amini             if (failed(reader.parseSection(sectionID, sectionData)))
21633128b310SMehdi Amini               return failure();
21643128b310SMehdi Amini             if (sectionID != bytecode::Section::kIR)
21653128b310SMehdi Amini               return emitError(fileLoc, "expected IR section for region");
21663128b310SMehdi Amini             childState.owningReader =
21673128b310SMehdi Amini                 std::make_unique<EncodingReader>(sectionData, fileLoc);
21683128b310SMehdi Amini             childState.reader = childState.owningReader.get();
21693128b310SMehdi Amini 
21706ee1aba8SRiver Riddle             // If the user has a callback set, they have the opportunity to
21716ee1aba8SRiver Riddle             // control lazyloading as we go.
21726ee1aba8SRiver Riddle             if (lazyLoading && (!lazyOpsCallback || !lazyOpsCallback(*op))) {
21736ee1aba8SRiver Riddle               lazyLoadableOps.emplace_back(*op, std::move(childState));
21743128b310SMehdi Amini               lazyLoadableOpsMap.try_emplace(*op,
21753128b310SMehdi Amini                                              std::prev(lazyLoadableOps.end()));
21763128b310SMehdi Amini               continue;
21773128b310SMehdi Amini             }
21783128b310SMehdi Amini           }
21793128b310SMehdi Amini           regionStack.push_back(std::move(childState));
2180f3acb54cSRiver Riddle 
2181f3acb54cSRiver Riddle           // If the op is isolated from above, push a new value scope.
2182f3acb54cSRiver Riddle           if (isIsolatedFromAbove)
218335cf7e8bSMehdi Amini             valueScopes.emplace_back();
2184f3acb54cSRiver Riddle           return success();
2185f3acb54cSRiver Riddle         }
2186f3acb54cSRiver Riddle       }
2187f3acb54cSRiver Riddle 
2188f3acb54cSRiver Riddle       // Move to the next block of the region.
2189f3acb54cSRiver Riddle       if (++readState.curBlock == readState.curRegion->end())
2190f3acb54cSRiver Riddle         break;
21913128b310SMehdi Amini       if (failed(parseBlockHeader(reader, readState)))
2192f3acb54cSRiver Riddle         return failure();
2193f3acb54cSRiver Riddle     } while (true);
2194f3acb54cSRiver Riddle 
2195f3acb54cSRiver Riddle     // Reset the current block and any values reserved for this region.
2196f3acb54cSRiver Riddle     readState.curBlock = {};
2197f3acb54cSRiver Riddle     valueScopes.back().pop(readState);
2198f3acb54cSRiver Riddle   }
2199f3acb54cSRiver Riddle 
2200f3acb54cSRiver Riddle   // When the regions have been fully parsed, pop them off of the read stack. If
2201f3acb54cSRiver Riddle   // the regions were isolated from above, we also pop the last value scope.
22023128b310SMehdi Amini   if (readState.isIsolatedFromAbove) {
22033128b310SMehdi Amini     assert(!valueScopes.empty() && "Expect a valueScope after reading region");
2204f3acb54cSRiver Riddle     valueScopes.pop_back();
22053128b310SMehdi Amini   }
22063128b310SMehdi Amini   assert(!regionStack.empty() && "Expect a regionStack after reading region");
220796fd3f2dSRiver Riddle   regionStack.pop_back();
2208f3acb54cSRiver Riddle   return success();
2209f3acb54cSRiver Riddle }
2210f3acb54cSRiver Riddle 
2211f3acb54cSRiver Riddle FailureOr<Operation *>
22123128b310SMehdi Amini BytecodeReader::Impl::parseOpWithoutRegions(EncodingReader &reader,
2213f3acb54cSRiver Riddle                                             RegionReadState &readState,
2214f3acb54cSRiver Riddle                                             bool &isIsolatedFromAbove) {
2215f3acb54cSRiver Riddle   // Parse the name of the operation.
2216660f714eSMehdi Amini   std::optional<bool> wasRegistered;
2217660f714eSMehdi Amini   FailureOr<OperationName> opName = parseOpName(reader, wasRegistered);
2218f3acb54cSRiver Riddle   if (failed(opName))
2219f3acb54cSRiver Riddle     return failure();
2220f3acb54cSRiver Riddle 
2221f3acb54cSRiver Riddle   // Parse the operation mask, which indicates which components of the operation
2222f3acb54cSRiver Riddle   // are present.
2223f3acb54cSRiver Riddle   uint8_t opMask;
2224f3acb54cSRiver Riddle   if (failed(reader.parseByte(opMask)))
2225f3acb54cSRiver Riddle     return failure();
2226f3acb54cSRiver Riddle 
2227f3acb54cSRiver Riddle   /// Parse the location.
2228b3449392SRiver Riddle   LocationAttr opLoc;
2229b3449392SRiver Riddle   if (failed(parseAttribute(reader, opLoc)))
2230f3acb54cSRiver Riddle     return failure();
2231f3acb54cSRiver Riddle 
2232f3acb54cSRiver Riddle   // With the location and name resolved, we can start building the operation
2233f3acb54cSRiver Riddle   // state.
2234f3acb54cSRiver Riddle   OperationState opState(opLoc, *opName);
2235f3acb54cSRiver Riddle 
2236f3acb54cSRiver Riddle   // Parse the attributes of the operation.
2237f3acb54cSRiver Riddle   if (opMask & bytecode::OpEncodingMask::kHasAttrs) {
2238b3449392SRiver Riddle     DictionaryAttr dictAttr;
2239b3449392SRiver Riddle     if (failed(parseAttribute(reader, dictAttr)))
2240f3acb54cSRiver Riddle       return failure();
2241f3acb54cSRiver Riddle     opState.attributes = dictAttr;
2242f3acb54cSRiver Riddle   }
2243f3acb54cSRiver Riddle 
2244660f714eSMehdi Amini   if (opMask & bytecode::OpEncodingMask::kHasProperties) {
2245660f714eSMehdi Amini     // kHasProperties wasn't emitted in older bytecode, we should never get
2246660f714eSMehdi Amini     // there without also having the `wasRegistered` flag available.
2247660f714eSMehdi Amini     if (!wasRegistered)
2248660f714eSMehdi Amini       return emitError(fileLoc,
2249660f714eSMehdi Amini                        "Unexpected missing `wasRegistered` opname flag at "
2250660f714eSMehdi Amini                        "bytecode version ")
2251660f714eSMehdi Amini              << version << " with properties.";
2252660f714eSMehdi Amini     // When an operation is emitted without being registered, the properties are
2253660f714eSMehdi Amini     // stored as an attribute. Otherwise the op must implement the bytecode
2254660f714eSMehdi Amini     // interface and control the serialization.
2255660f714eSMehdi Amini     if (wasRegistered) {
2256660f714eSMehdi Amini       DialectReader dialectReader(attrTypeReader, stringReader, resourceReader,
2257bff6a429SMatteo Franciolini                                   dialectsMap, reader, version);
2258660f714eSMehdi Amini       if (failed(
2259660f714eSMehdi Amini               propertiesReader.read(fileLoc, dialectReader, &*opName, opState)))
2260660f714eSMehdi Amini         return failure();
2261660f714eSMehdi Amini     } else {
2262660f714eSMehdi Amini       // If the operation wasn't registered when it was emitted, the properties
2263660f714eSMehdi Amini       // was serialized as an attribute.
2264660f714eSMehdi Amini       if (failed(parseAttribute(reader, opState.propertiesAttr)))
2265660f714eSMehdi Amini         return failure();
2266660f714eSMehdi Amini     }
2267660f714eSMehdi Amini   }
2268660f714eSMehdi Amini 
2269f3acb54cSRiver Riddle   /// Parse the results of the operation.
2270f3acb54cSRiver Riddle   if (opMask & bytecode::OpEncodingMask::kHasResults) {
2271f3acb54cSRiver Riddle     uint64_t numResults;
2272f3acb54cSRiver Riddle     if (failed(reader.parseVarInt(numResults)))
2273f3acb54cSRiver Riddle       return failure();
2274f3acb54cSRiver Riddle     opState.types.resize(numResults);
2275f3acb54cSRiver Riddle     for (int i = 0, e = numResults; i < e; ++i)
2276b3449392SRiver Riddle       if (failed(parseType(reader, opState.types[i])))
2277f3acb54cSRiver Riddle         return failure();
2278f3acb54cSRiver Riddle   }
2279f3acb54cSRiver Riddle 
2280f3acb54cSRiver Riddle   /// Parse the operands of the operation.
2281f3acb54cSRiver Riddle   if (opMask & bytecode::OpEncodingMask::kHasOperands) {
2282f3acb54cSRiver Riddle     uint64_t numOperands;
2283f3acb54cSRiver Riddle     if (failed(reader.parseVarInt(numOperands)))
2284f3acb54cSRiver Riddle       return failure();
2285f3acb54cSRiver Riddle     opState.operands.resize(numOperands);
2286f3acb54cSRiver Riddle     for (int i = 0, e = numOperands; i < e; ++i)
2287f3acb54cSRiver Riddle       if (!(opState.operands[i] = parseOperand(reader)))
2288f3acb54cSRiver Riddle         return failure();
2289f3acb54cSRiver Riddle   }
2290f3acb54cSRiver Riddle 
2291f3acb54cSRiver Riddle   /// Parse the successors of the operation.
2292f3acb54cSRiver Riddle   if (opMask & bytecode::OpEncodingMask::kHasSuccessors) {
2293f3acb54cSRiver Riddle     uint64_t numSuccs;
2294f3acb54cSRiver Riddle     if (failed(reader.parseVarInt(numSuccs)))
2295f3acb54cSRiver Riddle       return failure();
2296f3acb54cSRiver Riddle     opState.successors.resize(numSuccs);
2297f3acb54cSRiver Riddle     for (int i = 0, e = numSuccs; i < e; ++i) {
2298f3acb54cSRiver Riddle       if (failed(parseEntry(reader, readState.curBlocks, opState.successors[i],
2299f3acb54cSRiver Riddle                             "successor")))
2300f3acb54cSRiver Riddle         return failure();
2301f3acb54cSRiver Riddle     }
2302f3acb54cSRiver Riddle   }
2303f3acb54cSRiver Riddle 
230461278191SMatteo Franciolini   /// Parse the use-list orders for the results of the operation. Use-list
230561278191SMatteo Franciolini   /// orders are available since version 3 of the bytecode.
230661278191SMatteo Franciolini   std::optional<UseListMapT> resultIdxToUseListMap = std::nullopt;
23079c1e5587SMehdi Amini   if (version >= bytecode::kUseListOrdering &&
23089c1e5587SMehdi Amini       (opMask & bytecode::OpEncodingMask::kHasUseListOrders)) {
230961278191SMatteo Franciolini     size_t numResults = opState.types.size();
231061278191SMatteo Franciolini     auto parseResult = parseUseListOrderForRange(reader, numResults);
231161278191SMatteo Franciolini     if (failed(parseResult))
231261278191SMatteo Franciolini       return failure();
231361278191SMatteo Franciolini     resultIdxToUseListMap = std::move(*parseResult);
231461278191SMatteo Franciolini   }
231561278191SMatteo Franciolini 
2316f3acb54cSRiver Riddle   /// Parse the regions of the operation.
2317f3acb54cSRiver Riddle   if (opMask & bytecode::OpEncodingMask::kHasInlineRegions) {
2318f3acb54cSRiver Riddle     uint64_t numRegions;
2319f3acb54cSRiver Riddle     if (failed(reader.parseVarIntWithFlag(numRegions, isIsolatedFromAbove)))
2320f3acb54cSRiver Riddle       return failure();
2321f3acb54cSRiver Riddle 
2322f3acb54cSRiver Riddle     opState.regions.reserve(numRegions);
2323f3acb54cSRiver Riddle     for (int i = 0, e = numRegions; i < e; ++i)
2324f3acb54cSRiver Riddle       opState.regions.push_back(std::make_unique<Region>());
2325f3acb54cSRiver Riddle   }
2326f3acb54cSRiver Riddle 
2327f3acb54cSRiver Riddle   // Create the operation at the back of the current block.
2328f3acb54cSRiver Riddle   Operation *op = Operation::create(opState);
2329f3acb54cSRiver Riddle   readState.curBlock->push_back(op);
2330f3acb54cSRiver Riddle 
23315375cbfbSMatteo Franciolini   // If the operation had results, update the value references. We don't need to
23325375cbfbSMatteo Franciolini   // do this if the current value scope is empty. That is, the op was not
23335375cbfbSMatteo Franciolini   // encoded within a parent region.
23345375cbfbSMatteo Franciolini   if (readState.numValues && op->getNumResults() &&
23355375cbfbSMatteo Franciolini       failed(defineValues(reader, op->getResults())))
2336f3acb54cSRiver Riddle     return failure();
2337f3acb54cSRiver Riddle 
233861278191SMatteo Franciolini   /// Store a map for every value that received a custom use-list order from the
233961278191SMatteo Franciolini   /// bytecode file.
234061278191SMatteo Franciolini   if (resultIdxToUseListMap.has_value()) {
234161278191SMatteo Franciolini     for (size_t idx = 0; idx < op->getNumResults(); idx++) {
234261278191SMatteo Franciolini       if (resultIdxToUseListMap->contains(idx)) {
234361278191SMatteo Franciolini         valueToUseListMap.try_emplace(op->getResult(idx).getAsOpaquePointer(),
234461278191SMatteo Franciolini                                       resultIdxToUseListMap->at(idx));
234561278191SMatteo Franciolini       }
234661278191SMatteo Franciolini     }
234761278191SMatteo Franciolini   }
2348f3acb54cSRiver Riddle   return op;
2349f3acb54cSRiver Riddle }
2350f3acb54cSRiver Riddle 
23513128b310SMehdi Amini LogicalResult BytecodeReader::Impl::parseRegion(RegionReadState &readState) {
23523128b310SMehdi Amini   EncodingReader &reader = *readState.reader;
23533128b310SMehdi Amini 
2354f3acb54cSRiver Riddle   // Parse the number of blocks in the region.
2355f3acb54cSRiver Riddle   uint64_t numBlocks;
2356f3acb54cSRiver Riddle   if (failed(reader.parseVarInt(numBlocks)))
2357f3acb54cSRiver Riddle     return failure();
2358f3acb54cSRiver Riddle 
2359f3acb54cSRiver Riddle   // If the region is empty, there is nothing else to do.
2360f3acb54cSRiver Riddle   if (numBlocks == 0)
2361f3acb54cSRiver Riddle     return success();
2362f3acb54cSRiver Riddle 
2363f3acb54cSRiver Riddle   // Parse the number of values defined in this region.
2364f3acb54cSRiver Riddle   uint64_t numValues;
2365f3acb54cSRiver Riddle   if (failed(reader.parseVarInt(numValues)))
2366f3acb54cSRiver Riddle     return failure();
2367f3acb54cSRiver Riddle   readState.numValues = numValues;
2368f3acb54cSRiver Riddle 
2369f3acb54cSRiver Riddle   // Create the blocks within this region. We do this before processing so that
2370f3acb54cSRiver Riddle   // we can rely on the blocks existing when creating operations.
2371f3acb54cSRiver Riddle   readState.curBlocks.clear();
2372f3acb54cSRiver Riddle   readState.curBlocks.reserve(numBlocks);
2373f3acb54cSRiver Riddle   for (uint64_t i = 0; i < numBlocks; ++i) {
2374f3acb54cSRiver Riddle     readState.curBlocks.push_back(new Block());
2375f3acb54cSRiver Riddle     readState.curRegion->push_back(readState.curBlocks.back());
2376f3acb54cSRiver Riddle   }
2377f3acb54cSRiver Riddle 
2378f3acb54cSRiver Riddle   // Prepare the current value scope for this region.
2379f3acb54cSRiver Riddle   valueScopes.back().push(readState);
2380f3acb54cSRiver Riddle 
2381f3acb54cSRiver Riddle   // Parse the entry block of the region.
2382f3acb54cSRiver Riddle   readState.curBlock = readState.curRegion->begin();
23833128b310SMehdi Amini   return parseBlockHeader(reader, readState);
2384f3acb54cSRiver Riddle }
2385f3acb54cSRiver Riddle 
23863128b310SMehdi Amini LogicalResult
23873128b310SMehdi Amini BytecodeReader::Impl::parseBlockHeader(EncodingReader &reader,
2388f3acb54cSRiver Riddle                                        RegionReadState &readState) {
2389f3acb54cSRiver Riddle   bool hasArgs;
2390f3acb54cSRiver Riddle   if (failed(reader.parseVarIntWithFlag(readState.numOpsRemaining, hasArgs)))
2391f3acb54cSRiver Riddle     return failure();
2392f3acb54cSRiver Riddle 
2393f3acb54cSRiver Riddle   // Parse the arguments of the block.
2394f3acb54cSRiver Riddle   if (hasArgs && failed(parseBlockArguments(reader, &*readState.curBlock)))
2395f3acb54cSRiver Riddle     return failure();
2396f3acb54cSRiver Riddle 
239761278191SMatteo Franciolini   // Uselist orders are available since version 3 of the bytecode.
23989c1e5587SMehdi Amini   if (version < bytecode::kUseListOrdering)
239961278191SMatteo Franciolini     return success();
240061278191SMatteo Franciolini 
240161278191SMatteo Franciolini   uint8_t hasUseListOrders = 0;
240261278191SMatteo Franciolini   if (hasArgs && failed(reader.parseByte(hasUseListOrders)))
240361278191SMatteo Franciolini     return failure();
240461278191SMatteo Franciolini 
240561278191SMatteo Franciolini   if (!hasUseListOrders)
240661278191SMatteo Franciolini     return success();
240761278191SMatteo Franciolini 
240861278191SMatteo Franciolini   Block &blk = *readState.curBlock;
240961278191SMatteo Franciolini   auto argIdxToUseListMap =
241061278191SMatteo Franciolini       parseUseListOrderForRange(reader, blk.getNumArguments());
241161278191SMatteo Franciolini   if (failed(argIdxToUseListMap) || argIdxToUseListMap->empty())
241261278191SMatteo Franciolini     return failure();
241361278191SMatteo Franciolini 
241461278191SMatteo Franciolini   for (size_t idx = 0; idx < blk.getNumArguments(); idx++)
241561278191SMatteo Franciolini     if (argIdxToUseListMap->contains(idx))
241661278191SMatteo Franciolini       valueToUseListMap.try_emplace(blk.getArgument(idx).getAsOpaquePointer(),
241761278191SMatteo Franciolini                                     argIdxToUseListMap->at(idx));
241861278191SMatteo Franciolini 
2419f3acb54cSRiver Riddle   // We don't parse the operations of the block here, that's done elsewhere.
2420f3acb54cSRiver Riddle   return success();
2421f3acb54cSRiver Riddle }
2422f3acb54cSRiver Riddle 
24233128b310SMehdi Amini LogicalResult BytecodeReader::Impl::parseBlockArguments(EncodingReader &reader,
2424f3acb54cSRiver Riddle                                                         Block *block) {
2425f3acb54cSRiver Riddle   // Parse the value ID for the first argument, and the number of arguments.
2426f3acb54cSRiver Riddle   uint64_t numArgs;
2427f3acb54cSRiver Riddle   if (failed(reader.parseVarInt(numArgs)))
2428f3acb54cSRiver Riddle     return failure();
2429f3acb54cSRiver Riddle 
2430f3acb54cSRiver Riddle   SmallVector<Type> argTypes;
2431f3acb54cSRiver Riddle   SmallVector<Location> argLocs;
2432f3acb54cSRiver Riddle   argTypes.reserve(numArgs);
2433f3acb54cSRiver Riddle   argLocs.reserve(numArgs);
2434f3acb54cSRiver Riddle 
24351826fadbSJacques Pienaar   Location unknownLoc = UnknownLoc::get(config.getContext());
2436f3acb54cSRiver Riddle   while (numArgs--) {
2437b3449392SRiver Riddle     Type argType;
24381826fadbSJacques Pienaar     LocationAttr argLoc = unknownLoc;
24399c1e5587SMehdi Amini     if (version >= bytecode::kElideUnknownBlockArgLocation) {
24401826fadbSJacques Pienaar       // Parse the type with hasLoc flag to determine if it has type.
24411826fadbSJacques Pienaar       uint64_t typeIdx;
24421826fadbSJacques Pienaar       bool hasLoc;
24431826fadbSJacques Pienaar       if (failed(reader.parseVarIntWithFlag(typeIdx, hasLoc)) ||
24441826fadbSJacques Pienaar           !(argType = attrTypeReader.resolveType(typeIdx)))
24451826fadbSJacques Pienaar         return failure();
24461826fadbSJacques Pienaar       if (hasLoc && failed(parseAttribute(reader, argLoc)))
24471826fadbSJacques Pienaar         return failure();
24481826fadbSJacques Pienaar     } else {
24491826fadbSJacques Pienaar       // All args has type and location.
2450b3449392SRiver Riddle       if (failed(parseType(reader, argType)) ||
2451b3449392SRiver Riddle           failed(parseAttribute(reader, argLoc)))
2452f3acb54cSRiver Riddle         return failure();
24531826fadbSJacques Pienaar     }
2454f3acb54cSRiver Riddle     argTypes.push_back(argType);
2455f3acb54cSRiver Riddle     argLocs.push_back(argLoc);
2456f3acb54cSRiver Riddle   }
2457f3acb54cSRiver Riddle   block->addArguments(argTypes, argLocs);
2458f3acb54cSRiver Riddle   return defineValues(reader, block->getArguments());
2459f3acb54cSRiver Riddle }
2460f3acb54cSRiver Riddle 
2461f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
2462f3acb54cSRiver Riddle // Value Processing
2463f3acb54cSRiver Riddle 
24643128b310SMehdi Amini Value BytecodeReader::Impl::parseOperand(EncodingReader &reader) {
2465f3acb54cSRiver Riddle   std::vector<Value> &values = valueScopes.back().values;
2466f3acb54cSRiver Riddle   Value *value = nullptr;
2467f3acb54cSRiver Riddle   if (failed(parseEntry(reader, values, value, "value")))
2468f3acb54cSRiver Riddle     return Value();
2469f3acb54cSRiver Riddle 
2470f3acb54cSRiver Riddle   // Create a new forward reference if necessary.
2471f3acb54cSRiver Riddle   if (!*value)
2472f3acb54cSRiver Riddle     *value = createForwardRef();
2473f3acb54cSRiver Riddle   return *value;
2474f3acb54cSRiver Riddle }
2475f3acb54cSRiver Riddle 
24763128b310SMehdi Amini LogicalResult BytecodeReader::Impl::defineValues(EncodingReader &reader,
2477f3acb54cSRiver Riddle                                                  ValueRange newValues) {
2478f3acb54cSRiver Riddle   ValueScope &valueScope = valueScopes.back();
2479f3acb54cSRiver Riddle   std::vector<Value> &values = valueScope.values;
2480f3acb54cSRiver Riddle 
2481f3acb54cSRiver Riddle   unsigned &valueID = valueScope.nextValueIDs.back();
2482f3acb54cSRiver Riddle   unsigned valueIDEnd = valueID + newValues.size();
2483f3acb54cSRiver Riddle   if (valueIDEnd > values.size()) {
2484f3acb54cSRiver Riddle     return reader.emitError(
2485f3acb54cSRiver Riddle         "value index range was outside of the expected range for "
2486f3acb54cSRiver Riddle         "the parent region, got [",
2487f3acb54cSRiver Riddle         valueID, ", ", valueIDEnd, "), but the maximum index was ",
2488f3acb54cSRiver Riddle         values.size() - 1);
2489f3acb54cSRiver Riddle   }
2490f3acb54cSRiver Riddle 
2491f3acb54cSRiver Riddle   // Assign the values and update any forward references.
2492f3acb54cSRiver Riddle   for (unsigned i = 0, e = newValues.size(); i != e; ++i, ++valueID) {
2493f3acb54cSRiver Riddle     Value newValue = newValues[i];
2494f3acb54cSRiver Riddle 
2495f3acb54cSRiver Riddle     // Check to see if a definition for this value already exists.
2496f3acb54cSRiver Riddle     if (Value oldValue = std::exchange(values[valueID], newValue)) {
2497f3acb54cSRiver Riddle       Operation *forwardRefOp = oldValue.getDefiningOp();
2498f3acb54cSRiver Riddle 
2499f3acb54cSRiver Riddle       // Assert that this is a forward reference operation. Given how we compute
2500f3acb54cSRiver Riddle       // definition ids (incrementally as we parse), it shouldn't be possible
2501f3acb54cSRiver Riddle       // for the value to be defined any other way.
2502f3acb54cSRiver Riddle       assert(forwardRefOp && forwardRefOp->getBlock() == &forwardRefOps &&
2503f3acb54cSRiver Riddle              "value index was already defined?");
2504f3acb54cSRiver Riddle 
2505f3acb54cSRiver Riddle       oldValue.replaceAllUsesWith(newValue);
2506f3acb54cSRiver Riddle       forwardRefOp->moveBefore(&openForwardRefOps, openForwardRefOps.end());
2507f3acb54cSRiver Riddle     }
2508f3acb54cSRiver Riddle   }
2509f3acb54cSRiver Riddle   return success();
2510f3acb54cSRiver Riddle }
2511f3acb54cSRiver Riddle 
25123128b310SMehdi Amini Value BytecodeReader::Impl::createForwardRef() {
2513*b77e4026SWang Qiang   // Check for an available existing operation to use. Otherwise, create a new
2514f3acb54cSRiver Riddle   // fake operation to use for the reference.
2515f3acb54cSRiver Riddle   if (!openForwardRefOps.empty()) {
2516f3acb54cSRiver Riddle     Operation *op = &openForwardRefOps.back();
2517f3acb54cSRiver Riddle     op->moveBefore(&forwardRefOps, forwardRefOps.end());
2518f3acb54cSRiver Riddle   } else {
2519f3acb54cSRiver Riddle     forwardRefOps.push_back(Operation::create(forwardRefOpState));
2520f3acb54cSRiver Riddle   }
2521f3acb54cSRiver Riddle   return forwardRefOps.back().getResult(0);
2522f3acb54cSRiver Riddle }
2523f3acb54cSRiver Riddle 
2524f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
2525f3acb54cSRiver Riddle // Entry Points
2526f3acb54cSRiver Riddle //===----------------------------------------------------------------------===//
2527f3acb54cSRiver Riddle 
25283128b310SMehdi Amini BytecodeReader::~BytecodeReader() { assert(getNumOpsToMaterialize() == 0); }
25293128b310SMehdi Amini 
25303128b310SMehdi Amini BytecodeReader::BytecodeReader(
25313128b310SMehdi Amini     llvm::MemoryBufferRef buffer, const ParserConfig &config, bool lazyLoading,
25323128b310SMehdi Amini     const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
25333128b310SMehdi Amini   Location sourceFileLoc =
25343128b310SMehdi Amini       FileLineColLoc::get(config.getContext(), buffer.getBufferIdentifier(),
25353128b310SMehdi Amini                           /*line=*/0, /*column=*/0);
25363128b310SMehdi Amini   impl = std::make_unique<Impl>(sourceFileLoc, config, lazyLoading, buffer,
25373128b310SMehdi Amini                                 bufferOwnerRef);
25383128b310SMehdi Amini }
25393128b310SMehdi Amini 
25403128b310SMehdi Amini LogicalResult BytecodeReader::readTopLevel(
25413128b310SMehdi Amini     Block *block, llvm::function_ref<bool(Operation *)> lazyOpsCallback) {
25423128b310SMehdi Amini   return impl->read(block, lazyOpsCallback);
25433128b310SMehdi Amini }
25443128b310SMehdi Amini 
25453128b310SMehdi Amini int64_t BytecodeReader::getNumOpsToMaterialize() const {
25463128b310SMehdi Amini   return impl->getNumOpsToMaterialize();
25473128b310SMehdi Amini }
25483128b310SMehdi Amini 
25493128b310SMehdi Amini bool BytecodeReader::isMaterializable(Operation *op) {
25503128b310SMehdi Amini   return impl->isMaterializable(op);
25513128b310SMehdi Amini }
25523128b310SMehdi Amini 
25533128b310SMehdi Amini LogicalResult BytecodeReader::materialize(
25543128b310SMehdi Amini     Operation *op, llvm::function_ref<bool(Operation *)> lazyOpsCallback) {
25553128b310SMehdi Amini   return impl->materialize(op, lazyOpsCallback);
25563128b310SMehdi Amini }
25573128b310SMehdi Amini 
25583128b310SMehdi Amini LogicalResult
25593128b310SMehdi Amini BytecodeReader::finalize(function_ref<bool(Operation *)> shouldMaterialize) {
25603128b310SMehdi Amini   return impl->finalize(shouldMaterialize);
25613128b310SMehdi Amini }
25623128b310SMehdi Amini 
2563f3acb54cSRiver Riddle bool mlir::isBytecode(llvm::MemoryBufferRef buffer) {
256488d319a2SKazu Hirata   return buffer.getBuffer().starts_with("ML\xefR");
2565f3acb54cSRiver Riddle }
2566f3acb54cSRiver Riddle 
256718546ff8SRiver Riddle /// Read the bytecode from the provided memory buffer reference.
256818546ff8SRiver Riddle /// `bufferOwnerRef` if provided is the owning source manager for the buffer,
256918546ff8SRiver Riddle /// and may be used to extend the lifetime of the buffer.
257018546ff8SRiver Riddle static LogicalResult
257118546ff8SRiver Riddle readBytecodeFileImpl(llvm::MemoryBufferRef buffer, Block *block,
257218546ff8SRiver Riddle                      const ParserConfig &config,
257318546ff8SRiver Riddle                      const std::shared_ptr<llvm::SourceMgr> &bufferOwnerRef) {
2574f3acb54cSRiver Riddle   Location sourceFileLoc =
2575f3acb54cSRiver Riddle       FileLineColLoc::get(config.getContext(), buffer.getBufferIdentifier(),
2576f3acb54cSRiver Riddle                           /*line=*/0, /*column=*/0);
2577f3acb54cSRiver Riddle   if (!isBytecode(buffer)) {
2578f3acb54cSRiver Riddle     return emitError(sourceFileLoc,
2579f3acb54cSRiver Riddle                      "input buffer is not an MLIR bytecode file");
2580f3acb54cSRiver Riddle   }
2581f3acb54cSRiver Riddle 
25823128b310SMehdi Amini   BytecodeReader::Impl reader(sourceFileLoc, config, /*lazyLoading=*/false,
25833128b310SMehdi Amini                               buffer, bufferOwnerRef);
25843128b310SMehdi Amini   return reader.read(block, /*lazyOpsCallback=*/nullptr);
2585f3acb54cSRiver Riddle }
258618546ff8SRiver Riddle 
258718546ff8SRiver Riddle LogicalResult mlir::readBytecodeFile(llvm::MemoryBufferRef buffer, Block *block,
258818546ff8SRiver Riddle                                      const ParserConfig &config) {
258918546ff8SRiver Riddle   return readBytecodeFileImpl(buffer, block, config, /*bufferOwnerRef=*/{});
259018546ff8SRiver Riddle }
259118546ff8SRiver Riddle LogicalResult
259218546ff8SRiver Riddle mlir::readBytecodeFile(const std::shared_ptr<llvm::SourceMgr> &sourceMgr,
259318546ff8SRiver Riddle                        Block *block, const ParserConfig &config) {
259418546ff8SRiver Riddle   return readBytecodeFileImpl(
259518546ff8SRiver Riddle       *sourceMgr->getMemoryBuffer(sourceMgr->getMainFileID()), block, config,
259618546ff8SRiver Riddle       sourceMgr);
259718546ff8SRiver Riddle }
2598