// smol-v - public domain - https://github.com/aras-p/smol-v // authored 2016-2020 by Aras Pranckevicius // no warranty implied; use at your own risk // See end of file for license information. #include "smolv.h" #include <stdint.h> #include <vector> #include <algorithm> #include <cstdio> #include <cstring> #if !defined(_MSC_VER) && __cplusplus < 201103L #define static_assert(x,y) #endif #define _SMOLV_ARRAY_SIZE(a) … // -------------------------------------------------------------------------------------------- // Metadata about known SPIR-V operations enum SpvOp { … }; static const int kKnownOpsCount = …; static const char* kSpirvOpNames[] = …; static_assert …; struct OpData { … }; static const OpData kSpirvOpData[] = …; static_assert …; // Instruction encoding depends on the table that describes the various SPIR-V opcodes. // Whenever we change or expand the table, we need to bump up the SMOL-V version, and make // sure that we can still decode files encoded by an older version. static int smolv_GetKnownOpsCount(int version) { … } static bool smolv_OpHasResult(SpvOp op, int opsCount) { … } static bool smolv_OpHasType(SpvOp op, int opsCount) { … } static int smolv_OpDeltaFromResult(SpvOp op, int opsCount) { … } static bool smolv_OpVarRest(SpvOp op, int opsCount) { … } static bool smolv_OpDebugInfo(SpvOp op, int opsCount) { … } static int smolv_DecorationExtraOps(int dec) { … } // -------------------------------------------------------------------------------------------- static bool smolv_CheckGenericHeader(const uint32_t* words, size_t wordCount, uint32_t expectedMagic, uint32_t versionMask) { … } static const int kSpirVHeaderMagic = …; static const int kSmolHeaderMagic = …; // "SMOL" static const int kSmolCurrEncodingVersion = …; static bool smolv_CheckSpirVHeader(const uint32_t* words, size_t wordCount) { … } static bool smolv_CheckSmolHeader(const uint8_t* bytes, size_t byteCount) { … } static void smolv_Write4(smolv::ByteArray& arr, uint32_t v) { … } static void smolv_Write4(uint8_t*& buf, uint32_t v) { … } static bool smolv_Read4(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outv) { … } // -------------------------------------------------------------------------------------------- // Variable-length integer encoding for unsigned integers. In each byte: // - highest bit set if more bytes follow, cleared if this is last byte. // - other 7 bits are the actual value payload. // Takes 1-5 bytes to encode an integer (values between 0 and 127 take one byte, etc.). static void smolv_WriteVarint(smolv::ByteArray& arr, uint32_t v) { … } static bool smolv_ReadVarint(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outVal) { … } static uint32_t smolv_ZigEncode(int32_t i) { … } static int32_t smolv_ZigDecode(uint32_t u) { … } // Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in < 16 range, for // more compact varint encoding. This basically swaps rarely used op values that are < 16 with the // ones that are common. static SpvOp smolv_RemapOp(SpvOp op) { … } // For most compact varint encoding of common instructions, the instruction length should come out // into 3 bits (be <8). SPIR-V instruction lengths are always at least 1, and for some other // instructions they are guaranteed to be some other minimum length. Adjust the length before encoding, // and after decoding accordingly. static uint32_t smolv_EncodeLen(SpvOp op, uint32_t len) { … } static uint32_t smolv_DecodeLen(SpvOp op, uint32_t len) { … } // Shuffling bits of length + opcode to be more compact in varint encoding in typical cases: // 0x LLLL OOOO is how SPIR-V encodes it (L=length, O=op), we shuffle into: // 0x LLLO OOLO, so that common case (op<16, len<8) is encoded into one byte. static bool smolv_WriteLengthOp(smolv::ByteArray& arr, uint32_t len, SpvOp op) { … } static bool smolv_ReadLengthOp(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outLen, SpvOp& outOp) { … } #define _SMOLV_READ_OP(len, words, op) … bool smolv::Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags, StripOpNameFilterFunc stripFilter) { … } size_t smolv::GetDecodedBufferSize(const void* smolvData, size_t smolvSize) { … } bool smolv::Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags) { … } // -------------------------------------------------------------------------------------------- // Calculating instruction count / space stats on SPIR-V and SMOL-V struct smolv::Stats { … }; smolv::Stats* smolv::StatsCreate() { … } void smolv::StatsDelete(smolv::Stats *s) { … } bool smolv::StatsCalculate(smolv::Stats* stats, const void* spirvData, size_t spirvSize) { … } bool smolv::StatsCalculateSmol(smolv::Stats* stats, const void* smolvData, size_t smolvSize) { … } static bool CompareOpCounters (std::pair<SpvOp,size_t> a, std::pair<SpvOp,size_t> b) { … } void smolv::StatsPrint(const Stats* stats) { … } // ------------------------------------------------------------------------------ // This software is available under 2 licenses -- choose whichever you prefer. // ------------------------------------------------------------------------------ // ALTERNATIVE A - MIT License // Copyright (c) 2016-2020 Aras Pranckevicius // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // ------------------------------------------------------------------------------ // ALTERNATIVE B - Public Domain (www.unlicense.org) // This is free and unencumbered software released into the public domain. // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this // software, either in source code form or as a compiled binary, for any purpose, // commercial or non-commercial, and by any means. // In jurisdictions that recognize copyright laws, the author or authors of this // software dedicate any and all copyright interest in the software to the public // domain. We make this dedication for the benefit of the public at large and to // the detriment of our heirs and successors. We intend this dedication to be an // overt act of relinquishment in perpetuity of all present and future rights to // this software under copyright law. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ------------------------------------------------------------------------------