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 §ionID, 264f3acb54cSRiver Riddle ArrayRef<uint8_t> §ionData) { 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> ®ionStack, 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> ®ionStack, 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