diff options
Diffstat (limited to 'source/slang/ir-serialize.cpp')
| -rw-r--r-- | source/slang/ir-serialize.cpp | 633 |
1 files changed, 583 insertions, 50 deletions
diff --git a/source/slang/ir-serialize.cpp b/source/slang/ir-serialize.cpp index 6def3d9e1..c02ef7ee5 100644 --- a/source/slang/ir-serialize.cpp +++ b/source/slang/ir-serialize.cpp @@ -2,9 +2,12 @@ #include "ir-serialize.h" #include "../core/text-io.h" +#include "../core/slang-byte-encode-util.h" #include "ir-insts.h" +#include "../core/slang-math.h" + namespace Slang { // Needed for linkage with some compilers @@ -124,6 +127,48 @@ void IRSerialData::clear() m_decorationBaseIndex = 0; } +template <typename T> +static bool _isEqual(const List<T>& aIn, const List<T>& bIn) +{ + if (aIn.Count() != bIn.Count()) + { + return false; + } + + size_t size = size_t(aIn.Count()); + + const T* a = aIn.begin(); + const T* b = bIn.begin(); + + if (a == b) + { + return true; + } + + for (size_t i = 0; i < size; ++i) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; +} + + +bool IRSerialData::operator==(const ThisType& rhs) const +{ + return (this == &rhs) || + (m_decorationBaseIndex == rhs.m_decorationBaseIndex && + _isEqual(m_insts, rhs.m_insts) && + _isEqual(m_childRuns, rhs.m_childRuns) && + _isEqual(m_decorationRuns, rhs.m_decorationRuns) && + _isEqual(m_externalOperands, rhs.m_externalOperands) && + _isEqual(m_rawSourceLocs, rhs.m_rawSourceLocs) && + _isEqual(m_strings, rhs.m_strings)); +} + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IRSerialWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void IRSerialWriter::_addInstruction(IRInst* inst) @@ -585,14 +630,31 @@ IRSerialData::StringIndex IRSerialWriter::getStringIndex(const UnownedStringSlic } template <typename T> -static size_t _calcChunkSize(const List<T>& array) +static size_t _calcChunkSize(IRSerialBinary::CompressionType compressionType, const List<T>& array) { typedef IRSerialBinary Bin; if (array.Count()) { - const size_t size = sizeof(Bin::ArrayHeader) + sizeof(T) * array.Count(); - return (size + 3) & ~size_t(3); + switch (compressionType) + { + case Bin::CompressionType::None: + { + const size_t size = sizeof(Bin::ArrayHeader) + sizeof(T) * array.Count(); + return (size + 3) & ~size_t(3); + } + case Bin::CompressionType::VariableByteLite: + { + const size_t payloadSize = ByteEncodeUtil::calcEncodeLiteSizeUInt32((const uint32_t*)array.begin(), (array.Count() * sizeof(T)) / sizeof(uint32_t)); + const size_t size = sizeof(Bin::CompressedArrayHeader) + payloadSize; + return (size + 3) & ~size_t(3); + } + default: + { + SLANG_ASSERT(!"Unhandled compression type"); + return 0; + } + } } else { @@ -600,27 +662,59 @@ static size_t _calcChunkSize(const List<T>& array) } } -template <typename T> -Result _writeArrayChunk(uint32_t chunkId, const List<T>& array, Stream* stream) +static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType, uint32_t chunkId, const void* data, size_t numEntries, size_t typeSize, Stream* stream) { typedef IRSerialBinary Bin; - if (array.Count() == 0) + if (numEntries == 0) { return SLANG_OK; } - size_t payloadSize = sizeof(Bin::ArrayHeader) - sizeof(Bin::Chunk) + sizeof(T) * array.Count(); + size_t payloadSize; - Bin::ArrayHeader header; - header.m_chunk.m_type = chunkId; - header.m_chunk.m_size = uint32_t(payloadSize); - header.m_numEntries = uint32_t(array.Count()); + switch (compressionType) + { + case Bin::CompressionType::None: + { + payloadSize = sizeof(Bin::ArrayHeader) - sizeof(Bin::Chunk) + typeSize * numEntries; + + Bin::ArrayHeader header; + header.m_chunk.m_type = chunkId; + header.m_chunk.m_size = uint32_t(payloadSize); + header.m_numEntries = uint32_t(numEntries); + + stream->Write(&header, sizeof(header)); + + stream->Write(data, typeSize * numEntries); + break; + } + case Bin::CompressionType::VariableByteLite: + { + List<uint8_t> compressedPayload; + + size_t numCompressedEntries = (numEntries * typeSize) / sizeof(uint32_t); + + ByteEncodeUtil::encodeLiteUInt32((const uint32_t*)data, numCompressedEntries, compressedPayload); + + payloadSize = sizeof(Bin::CompressedArrayHeader) - sizeof(Bin::Chunk) + compressedPayload.Count(); - stream->Write(&header, sizeof(header)); + Bin::CompressedArrayHeader header; + header.m_chunk.m_type = SLANG_MAKE_COMPRESSED_FOUR_CC(chunkId); + header.m_chunk.m_size = uint32_t(payloadSize); + header.m_numEntries = uint32_t(numEntries); + header.m_numCompressedEntries = uint32_t(numCompressedEntries); - stream->Write(array.begin(), sizeof(T) * array.Count()); + stream->Write(&header, sizeof(header)); + stream->Write(compressedPayload.begin(), compressedPayload.Count()); + break; + } + default: + { + return SLANG_FAIL; + } + } // All chunks have sizes rounded to dword size if (payloadSize & 3) { @@ -633,25 +727,237 @@ Result _writeArrayChunk(uint32_t chunkId, const List<T>& array, Stream* stream) return SLANG_OK; } -/* static */Result IRSerialWriter::writeStream(const IRSerialData& data, Stream* stream) +template <typename T> +Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType, uint32_t chunkId, const List<T>& array, Stream* stream) +{ + return _writeArrayChunk(compressionType, chunkId, array.begin(), size_t(array.Count()), sizeof(T), stream); +} + +Result _encodeInsts(IRSerialBinary::CompressionType compressionType, const List<IRSerialData::Inst>& instsIn, List<uint8_t>& encodeArrayOut) { typedef IRSerialBinary Bin; + typedef IRSerialData::Inst::PayloadType PayloadType; + + if (compressionType != Bin::CompressionType::VariableByteLite) + { + return SLANG_FAIL; + } + encodeArrayOut.Clear(); + + const size_t numInsts = size_t(instsIn.Count()); + const IRSerialData::Inst* insts = instsIn.begin(); + + uint8_t* encodeOut = encodeArrayOut.begin(); + uint8_t* encodeEnd = encodeArrayOut.end(); + // Calculate the maximum instruction size with worst case possible encoding + // 2 bytes hold the payload size, and the result type + // Note that if there were some free bits, we could encode some of this stuff into bits, but if we remove payloadType, then there are no free bits + const size_t maxInstSize = 2 + ByteEncodeUtil::kMaxLiteEncodeUInt32 + Math::Max(sizeof(insts->m_payload.m_float64), size_t(2 * ByteEncodeUtil::kMaxLiteEncodeUInt32)); + + for (size_t i = 0; i < numInsts; ++i) + { + const auto& inst = insts[i]; + + // Make sure there is space for the largest possible instruction + if (encodeOut + maxInstSize >= encodeEnd) + { + const size_t offset = size_t(encodeOut - encodeArrayOut.begin()); + + const UInt oldCapacity = encodeArrayOut.Capacity(); + + encodeArrayOut.Reserve(oldCapacity + (oldCapacity >> 1) + maxInstSize); + const UInt capacity = encodeArrayOut.Capacity(); + encodeArrayOut.SetSize(capacity); + + encodeOut = encodeArrayOut.begin() + offset; + encodeEnd = encodeArrayOut.end(); + } + + *encodeOut++ = uint8_t(inst.m_op); + *encodeOut++ = uint8_t(inst.m_payloadType); + + encodeOut += ByteEncodeUtil::encodeLiteUInt32((uint32_t)inst.m_resultTypeIndex, encodeOut); + + switch (inst.m_payloadType) + { + case PayloadType::Empty: + { + break; + } + case PayloadType::Operand_1: + case PayloadType::String_1: + case PayloadType::UInt32: + { + // 1 UInt32 + encodeOut += ByteEncodeUtil::encodeLiteUInt32((uint32_t)inst.m_payload.m_operands[0], encodeOut); + break; + } + case PayloadType::Operand_2: + case PayloadType::OperandAndUInt32: + case PayloadType::OperandExternal: + case PayloadType::String_2: + { + // 2 UInt32 + encodeOut += ByteEncodeUtil::encodeLiteUInt32((uint32_t)inst.m_payload.m_operands[0], encodeOut); + encodeOut += ByteEncodeUtil::encodeLiteUInt32((uint32_t)inst.m_payload.m_operands[1], encodeOut); + break; + } + case PayloadType::Float64: + { + memcpy(encodeOut, &inst.m_payload.m_float64, sizeof(inst.m_payload.m_float64)); + encodeOut += sizeof(inst.m_payload.m_float64); + break; + } + case PayloadType::Int64: + { + memcpy(encodeOut, &inst.m_payload.m_int64, sizeof(inst.m_payload.m_int64)); + encodeOut += sizeof(inst.m_payload.m_int64); + break; + } + } + } + + // Fix the size + encodeArrayOut.SetSize(UInt(encodeOut - encodeArrayOut.begin())); + return SLANG_OK; +} + +Result _writeInstArrayChunk(IRSerialBinary::CompressionType compressionType, uint32_t chunkId, const List<IRSerialData::Inst>& array, Stream* stream) +{ + typedef IRSerialBinary Bin; + if (array.Count() == 0) + { + return SLANG_OK; + } + + switch (compressionType) + { + case Bin::CompressionType::None: + { + return _writeArrayChunk(compressionType, chunkId, array, stream); + } + case Bin::CompressionType::VariableByteLite: + { + List<uint8_t> compressedPayload; + SLANG_RETURN_ON_FAIL(_encodeInsts(compressionType, array, compressedPayload)); + + size_t payloadSize = sizeof(Bin::CompressedArrayHeader) - sizeof(Bin::Chunk) + compressedPayload.Count(); + + Bin::CompressedArrayHeader header; + header.m_chunk.m_type = SLANG_MAKE_COMPRESSED_FOUR_CC(chunkId); + header.m_chunk.m_size = uint32_t(payloadSize); + header.m_numEntries = uint32_t(array.Count()); + header.m_numCompressedEntries = 0; + + stream->Write(&header, sizeof(header)); + stream->Write(compressedPayload.begin(), compressedPayload.Count()); + + // All chunks have sizes rounded to dword size + if (payloadSize & 3) + { + const uint8_t pad[4] = { 0, 0, 0, 0 }; + // Pad outs + int padSize = 4 - (payloadSize & 3); + stream->Write(pad, padSize); + } + return SLANG_OK; + } + default: break; + } + return SLANG_FAIL; +} + +static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType, const List<IRSerialData::Inst>& instsIn) +{ + typedef IRSerialBinary Bin; + typedef IRSerialData::Inst::PayloadType PayloadType; + + switch (compressionType) + { + case Bin::CompressionType::None: + { + return _calcChunkSize(compressionType, instsIn); + } + case Bin::CompressionType::VariableByteLite: + { + size_t size = sizeof(Bin::CompressedArrayHeader); + + size_t numInsts = size_t(instsIn.Count()); + size += numInsts * 2; // op and payload + + + IRSerialData::Inst* insts = instsIn.begin(); + + for (size_t i = 0; i < numInsts; ++i) + { + const auto& inst = insts[i]; + + size += ByteEncodeUtil::calcEncodeLiteSizeUInt32((uint32_t)inst.m_resultTypeIndex); + + switch (inst.m_payloadType) + { + case PayloadType::Empty: + { + break; + } + case PayloadType::Operand_1: + case PayloadType::String_1: + case PayloadType::UInt32: + { + // 1 UInt32 + size += ByteEncodeUtil::calcEncodeLiteSizeUInt32((uint32_t)inst.m_payload.m_operands[0]); + break; + } + case PayloadType::Operand_2: + case PayloadType::OperandAndUInt32: + case PayloadType::OperandExternal: + case PayloadType::String_2: + { + // 2 UInt32 + size += ByteEncodeUtil::calcEncodeLiteSizeUInt32((uint32_t)inst.m_payload.m_operands[0]); + size += ByteEncodeUtil::calcEncodeLiteSizeUInt32((uint32_t)inst.m_payload.m_operands[1]); + break; + } + case PayloadType::Float64: + { + size += sizeof(inst.m_payload.m_float64); + break; + } + case PayloadType::Int64: + { + size += sizeof(inst.m_payload.m_int64); + break; + } + } + } + + return (size + 3) & ~size_t(3); + } + default: break; + } + + SLANG_ASSERT(!"Unhandled compression type"); + return 0; +} + +/* static */Result IRSerialWriter::writeStream(const IRSerialData& data, Bin::CompressionType compressionType, Stream* stream) +{ size_t totalSize = 0; totalSize += sizeof(Bin::SlangHeader) + - _calcChunkSize(data.m_insts) + - _calcChunkSize(data.m_childRuns) + - _calcChunkSize(data.m_decorationRuns) + - _calcChunkSize(data.m_externalOperands) + - _calcChunkSize(data.m_strings) + - _calcChunkSize(data.m_rawSourceLocs); + _calcInstChunkSize(compressionType, data.m_insts) + + _calcChunkSize(compressionType, data.m_childRuns) + + _calcChunkSize(compressionType, data.m_decorationRuns) + + _calcChunkSize(compressionType, data.m_externalOperands) + + _calcChunkSize(Bin::CompressionType::None, data.m_strings) + + _calcChunkSize(Bin::CompressionType::None, data.m_rawSourceLocs); { Bin::Chunk riffHeader; riffHeader.m_type = Bin::kRiffFourCc; riffHeader.m_size = uint32_t(totalSize); - + stream->Write(&riffHeader, sizeof(riffHeader)); } { @@ -659,19 +965,20 @@ Result _writeArrayChunk(uint32_t chunkId, const List<T>& array, Stream* stream) slangHeader.m_chunk.m_type = Bin::kSlangFourCc; slangHeader.m_chunk.m_size = uint32_t(sizeof(slangHeader) - sizeof(Bin::Chunk)); slangHeader.m_decorationBase = uint32_t(data.m_decorationBaseIndex); + slangHeader.m_compressionType = uint32_t(Bin::CompressionType::VariableByteLite); stream->Write(&slangHeader, sizeof(slangHeader)); } - _writeArrayChunk(Bin::kInstFourCc, data.m_insts, stream); - _writeArrayChunk(Bin::kChildRunFourCc, data.m_childRuns, stream); - _writeArrayChunk(Bin::kDecoratorRunFourCc, data.m_decorationRuns, stream); - _writeArrayChunk(Bin::kExternalOperandsFourCc, data.m_externalOperands, stream); - _writeArrayChunk(Bin::kStringFourCc, data.m_strings, stream); + SLANG_RETURN_ON_FAIL(_writeInstArrayChunk(compressionType, Bin::kInstFourCc, data.m_insts, stream)); + SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kChildRunFourCc, data.m_childRuns, stream)); + SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kDecoratorRunFourCc, data.m_decorationRuns, stream)); + SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kExternalOperandsFourCc, data.m_externalOperands, stream)); + SLANG_RETURN_ON_FAIL(_writeArrayChunk(Bin::CompressionType::None, Bin::kStringFourCc, data.m_strings, stream)); { uint32_t fourCc = sizeof(IRSerialData::RawSourceLoc) == 4 ? Bin::kUInt32SourceLocFourCc : Bin::kUInt64SourceLocFourCc; - _writeArrayChunk(fourCc, data.m_rawSourceLocs, stream); + SLANG_RETURN_ON_FAIL(_writeArrayChunk(Bin::CompressionType::None, fourCc, data.m_rawSourceLocs, stream)); } return SLANG_OK; @@ -679,33 +986,250 @@ Result _writeArrayChunk(uint32_t chunkId, const List<T>& array, Stream* stream) // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IRSerialReader !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +class ListResizer +{ + public: + virtual void* setSize(size_t newSize) = 0; + SLANG_FORCE_INLINE size_t getTypeSize() const { return m_typeSize; } + ListResizer(size_t typeSize):m_typeSize(typeSize) {} + + protected: + size_t m_typeSize; +}; + +template <typename T> +class ListResizerForType: public ListResizer +{ + public: + typedef ListResizer Parent; + + SLANG_FORCE_INLINE ListResizerForType(List<T>& list): + Parent(sizeof(T)), + m_list(list) + {} + + virtual void* setSize(size_t newSize) SLANG_OVERRIDE + { + m_list.SetSize(UInt(newSize)); + return (void*)m_list.begin(); + } + + protected: + List<T>& m_list; +}; + +static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, const IRSerialBinary::Chunk& chunk, Stream* stream, size_t* numReadInOut, ListResizer& listOut) +{ + typedef IRSerialBinary Bin; + + const size_t typeSize = listOut.getTypeSize(); + + switch (compressionType) + { + case Bin::CompressionType::VariableByteLite: + { + // We have a compressed header + Bin::CompressedArrayHeader header; + header.m_chunk = chunk; + + stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(Bin::Chunk)); + *numReadInOut += sizeof(header) - sizeof(Bin::Chunk); + + void* data = listOut.setSize(header.m_numEntries); + + // Need to read all the compressed data... + size_t payloadSize = header.m_chunk.m_size - (sizeof(header) - sizeof(Bin::Chunk)); + + List<uint8_t> compressedPayload; + compressedPayload.SetSize(payloadSize); + + stream->Read(compressedPayload.begin(), payloadSize); + *numReadInOut += payloadSize; + + SLANG_ASSERT(header.m_numCompressedEntries == uint32_t((header.m_numEntries * typeSize) / sizeof(uint32_t))); + + // Decode.. + ByteEncodeUtil::decodeLiteUInt32(compressedPayload.begin(), header.m_numCompressedEntries, (uint32_t*)data); + break; + } + case Bin::CompressionType::None: + { + // Read uncompressed + Bin::ArrayHeader header; + header.m_chunk = chunk; + + stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(Bin::Chunk)); + *numReadInOut += sizeof(header) - sizeof(Bin::Chunk); + + const size_t payloadSize = header.m_numEntries * typeSize; + + void* data = listOut.setSize(header.m_numEntries); + + stream->Read(data, payloadSize); + *numReadInOut += payloadSize; + break; + } + } + + // All chunks have sizes rounded to dword size + if (*numReadInOut & 3) + { + const uint8_t pad[4] = { 0, 0, 0, 0 }; + // Pad outs + int padSize = 4 - int(*numReadInOut & 3); + stream->Seek(SeekOrigin::Current, padSize); + + *numReadInOut += padSize; + } + + return SLANG_OK; +} + template <typename T> -Result _readArrayChunk(const IRSerialBinary::Chunk& chunk, Stream* stream, List<T>& arrayOut) +Result _readArrayChunk(const IRSerialBinary::SlangHeader& header, const IRSerialBinary::Chunk& chunk, Stream* stream, size_t* numReadInOut, List<T>& arrayOut) { typedef IRSerialBinary Bin; - Bin::ArrayHeader header; - header.m_chunk = chunk; + Bin::CompressionType compressionType = Bin::CompressionType::None; - stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(Bin::Chunk)); + if (chunk.m_type == SLANG_MAKE_COMPRESSED_FOUR_CC(chunk.m_type)) + { + // If it has compression, use the compression type set in the header + compressionType = Bin::CompressionType(header.m_compressionType); + } + ListResizerForType<T> resizer(arrayOut); + return _readArrayChunk(compressionType, chunk, stream, numReadInOut, resizer); +} - size_t payloadSize = sizeof(Bin::ArrayHeader) - sizeof(Bin::Chunk) + sizeof(T) * header.m_numEntries; - if (payloadSize != header.m_chunk.m_size) +template <typename T> +Result _readArrayUncompressedChunk(const IRSerialBinary::SlangHeader& header, const IRSerialBinary::Chunk& chunk, Stream* stream, size_t* numReadInOut, List<T>& arrayOut) +{ + typedef IRSerialBinary Bin; + SLANG_UNUSED(header); + ListResizerForType<T> resizer(arrayOut); + return _readArrayChunk(Bin::CompressionType::None, chunk, stream, numReadInOut, resizer); +} + +static Result _decodeInsts(IRSerialBinary::CompressionType compressionType, const List<uint8_t>& encodeIn, List<IRSerialData::Inst>& instsOut) +{ + typedef IRSerialBinary Bin; + typedef IRSerialData::Inst::PayloadType PayloadType; + + if (compressionType != Bin::CompressionType::VariableByteLite) { return SLANG_FAIL; } - arrayOut.SetSize(header.m_numEntries); + const size_t numInsts = size_t(instsOut.Count()); + IRSerialData::Inst* insts = instsOut.begin(); + + const uint8_t* encodeCur = encodeIn.begin(); + + for (size_t i = 0; i < numInsts; ++i) + { + auto& inst = insts[i]; + + inst.m_op = *encodeCur++; + const PayloadType payloadType = PayloadType(*encodeCur++); + inst.m_payloadType = payloadType; + + // Read the result value + encodeCur += ByteEncodeUtil::decodeLiteUInt32(encodeCur, (uint32_t*)&inst.m_resultTypeIndex); + + switch (inst.m_payloadType) + { + case PayloadType::Empty: + { + break; + } + case PayloadType::Operand_1: + case PayloadType::String_1: + case PayloadType::UInt32: + { + // 1 UInt32 + encodeCur += ByteEncodeUtil::decodeLiteUInt32(encodeCur, (uint32_t*)&inst.m_payload.m_operands[0]); + break; + } + case PayloadType::Operand_2: + case PayloadType::OperandAndUInt32: + case PayloadType::OperandExternal: + case PayloadType::String_2: + { + // 2 UInt32 + encodeCur += ByteEncodeUtil::decodeLiteUInt32(encodeCur, 2, (uint32_t*)&inst.m_payload.m_operands[0]); + break; + } + case PayloadType::Float64: + { + memcpy(&inst.m_payload.m_float64, encodeCur, sizeof(inst.m_payload.m_float64)); + encodeCur += sizeof(inst.m_payload.m_float64); + break; + } + case PayloadType::Int64: + { + memcpy(&inst.m_payload.m_int64, encodeCur, sizeof(inst.m_payload.m_int64)); + encodeCur += sizeof(inst.m_payload.m_int64); + break; + } + } + } + + return SLANG_OK; +} - stream->Read(arrayOut.begin(), sizeof(T) * header.m_numEntries); +Result _readInstArrayChunk(const IRSerialBinary::SlangHeader& slangHeader, const IRSerialBinary::Chunk& chunk, Stream* stream, size_t* numReadInOut, List<IRSerialData::Inst>& arrayOut) +{ + typedef IRSerialBinary Bin; + + Bin::CompressionType compressionType = Bin::CompressionType::None; + if (chunk.m_type == SLANG_MAKE_COMPRESSED_FOUR_CC(chunk.m_type)) + { + compressionType = Bin::CompressionType(slangHeader.m_compressionType); + } + + switch (compressionType) + { + case Bin::CompressionType::None: + { + ListResizerForType<IRSerialData::Inst> resizer(arrayOut); + return _readArrayChunk(compressionType, chunk, stream, numReadInOut, resizer); + } + case Bin::CompressionType::VariableByteLite: + { + // We have a compressed header + Bin::CompressedArrayHeader header; + header.m_chunk = chunk; + + stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(Bin::Chunk)); + *numReadInOut += sizeof(header) - sizeof(Bin::Chunk); + + // Need to read all the compressed data... + size_t payloadSize = header.m_chunk.m_size - (sizeof(header) - sizeof(Bin::Chunk)); + + List<uint8_t> compressedPayload; + compressedPayload.SetSize(payloadSize); + + stream->Read(compressedPayload.begin(), payloadSize); + *numReadInOut += payloadSize; + + arrayOut.SetSize(header.m_numEntries); + + SLANG_RETURN_ON_FAIL(_decodeInsts(compressionType, compressedPayload, arrayOut)); + break; + } + default: + { + return SLANG_FAIL; + } + } // All chunks have sizes rounded to dword size - if (payloadSize & 3) + if (*numReadInOut & 3) { - const uint8_t pad[4] = { 0, 0, 0, 0 }; // Pad outs - int padSize = 4 - (payloadSize & 3); + int padSize = 4 - int(*numReadInOut & 3); stream->Seek(SeekOrigin::Current, padSize); + *numReadInOut += padSize; } return SLANG_OK; @@ -749,57 +1273,66 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) remainingBytes = header.m_size; } + // Header + // Chunk will not be kSlangFourCC if not read yet + Bin::SlangHeader slangHeader; + memset(&slangHeader, 0, sizeof(slangHeader)); + while (remainingBytes > 0) { Bin::Chunk chunk; stream->Read(&chunk, sizeof(chunk)); + size_t bytesRead = sizeof(chunk); + switch (chunk.m_type) { case Bin::kSlangFourCc: { // Slang header - Bin::SlangHeader header; - header.m_chunk = chunk; + slangHeader.m_chunk = chunk; // NOTE! Really we should only read what we know the size to be... // and skip if it's larger - stream->Read(&header.m_chunk + 1, sizeof(header) - sizeof(chunk)); - - dataOut->m_decorationBaseIndex = header.m_decorationBase; + stream->Read(&slangHeader.m_chunk + 1, sizeof(slangHeader) - sizeof(chunk)); + dataOut->m_decorationBaseIndex = slangHeader.m_decorationBase; remainingBytes -= _calcChunkTotalSize(chunk); break; } + case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kInstFourCc): case Bin::kInstFourCc: { - SLANG_RETURN_ON_FAIL(_readArrayChunk(chunk, stream, dataOut->m_insts)); + SLANG_RETURN_ON_FAIL(_readInstArrayChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_insts)); remainingBytes -= _calcChunkTotalSize(chunk); break; } + case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kDecoratorRunFourCc): case Bin::kDecoratorRunFourCc: { - SLANG_RETURN_ON_FAIL(_readArrayChunk(chunk, stream, dataOut->m_decorationRuns)); + SLANG_RETURN_ON_FAIL(_readArrayChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_decorationRuns)); remainingBytes -= _calcChunkTotalSize(chunk); break; } + case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kChildRunFourCc): case Bin::kChildRunFourCc: { - SLANG_RETURN_ON_FAIL(_readArrayChunk(chunk, stream, dataOut->m_childRuns)); + SLANG_RETURN_ON_FAIL(_readArrayChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_childRuns)); remainingBytes -= _calcChunkTotalSize(chunk); break; } + case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kExternalOperandsFourCc): case Bin::kExternalOperandsFourCc: { - SLANG_RETURN_ON_FAIL(_readArrayChunk(chunk, stream, dataOut->m_externalOperands)); + SLANG_RETURN_ON_FAIL(_readArrayChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_externalOperands)); remainingBytes -= _calcChunkTotalSize(chunk); break; } case Bin::kStringFourCc: { - SLANG_RETURN_ON_FAIL(_readArrayChunk(chunk, stream, dataOut->m_strings)); + SLANG_RETURN_ON_FAIL(_readArrayUncompressedChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_strings)); remainingBytes -= _calcChunkTotalSize(chunk); break; } @@ -809,7 +1342,7 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) if ((sizeof(IRSerialData::RawSourceLoc) == 4 && chunk.m_type == Bin::kUInt32SourceLocFourCc) || (sizeof(IRSerialData::RawSourceLoc) == 8 && chunk.m_type == Bin::kUInt64SourceLocFourCc)) { - SLANG_RETURN_ON_FAIL(_readArrayChunk(chunk, stream, dataOut->m_rawSourceLocs)); + SLANG_RETURN_ON_FAIL(_readArrayUncompressedChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_rawSourceLocs)); remainingBytes -= _calcChunkTotalSize(chunk); } else @@ -1270,7 +1803,7 @@ Result serializeModule(IRModule* module, SourceManager* sourceManager, Stream* s if (stream) { - SLANG_RETURN_ON_FAIL(IRSerialWriter::writeStream(serialData, stream)); + SLANG_RETURN_ON_FAIL(IRSerialWriter::writeStream(serialData, IRSerialBinary::CompressionType::VariableByteLite, stream)); } return SLANG_OK; |
