0d2e02945b
* Shader compilation is now cached. Subsequent loads take less than a millisecond. * Improved game, editor and project manager startup time. * Editor uses .godot/shader_cache to store shaders. * Game uses user://shader_cache * Project manager uses $config_dir/shader_cache * Options to tweak shader caching in project settings. * Editor path configuration moved from EditorSettings to new class, EditorPaths, so it can be available early on (before shaders are compiled). * Reworked ShaderCompilerRD to ensure deterministic shader code creation (else shader may change and cache will be invalidated). * Added shader compression with SMOLV: https://github.com/aras-p/smol-v
2109 lines
60 KiB
C++
2109 lines
60 KiB
C++
// 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) (sizeof(a)/sizeof((a)[0]))
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
// Metadata about known SPIR-V operations
|
|
|
|
enum SpvOp
|
|
{
|
|
SpvOpNop = 0,
|
|
SpvOpUndef = 1,
|
|
SpvOpSourceContinued = 2,
|
|
SpvOpSource = 3,
|
|
SpvOpSourceExtension = 4,
|
|
SpvOpName = 5,
|
|
SpvOpMemberName = 6,
|
|
SpvOpString = 7,
|
|
SpvOpLine = 8,
|
|
SpvOpExtension = 10,
|
|
SpvOpExtInstImport = 11,
|
|
SpvOpExtInst = 12,
|
|
SpvOpVectorShuffleCompact = 13, // not in SPIR-V, added for SMOL-V!
|
|
SpvOpMemoryModel = 14,
|
|
SpvOpEntryPoint = 15,
|
|
SpvOpExecutionMode = 16,
|
|
SpvOpCapability = 17,
|
|
SpvOpTypeVoid = 19,
|
|
SpvOpTypeBool = 20,
|
|
SpvOpTypeInt = 21,
|
|
SpvOpTypeFloat = 22,
|
|
SpvOpTypeVector = 23,
|
|
SpvOpTypeMatrix = 24,
|
|
SpvOpTypeImage = 25,
|
|
SpvOpTypeSampler = 26,
|
|
SpvOpTypeSampledImage = 27,
|
|
SpvOpTypeArray = 28,
|
|
SpvOpTypeRuntimeArray = 29,
|
|
SpvOpTypeStruct = 30,
|
|
SpvOpTypeOpaque = 31,
|
|
SpvOpTypePointer = 32,
|
|
SpvOpTypeFunction = 33,
|
|
SpvOpTypeEvent = 34,
|
|
SpvOpTypeDeviceEvent = 35,
|
|
SpvOpTypeReserveId = 36,
|
|
SpvOpTypeQueue = 37,
|
|
SpvOpTypePipe = 38,
|
|
SpvOpTypeForwardPointer = 39,
|
|
SpvOpConstantTrue = 41,
|
|
SpvOpConstantFalse = 42,
|
|
SpvOpConstant = 43,
|
|
SpvOpConstantComposite = 44,
|
|
SpvOpConstantSampler = 45,
|
|
SpvOpConstantNull = 46,
|
|
SpvOpSpecConstantTrue = 48,
|
|
SpvOpSpecConstantFalse = 49,
|
|
SpvOpSpecConstant = 50,
|
|
SpvOpSpecConstantComposite = 51,
|
|
SpvOpSpecConstantOp = 52,
|
|
SpvOpFunction = 54,
|
|
SpvOpFunctionParameter = 55,
|
|
SpvOpFunctionEnd = 56,
|
|
SpvOpFunctionCall = 57,
|
|
SpvOpVariable = 59,
|
|
SpvOpImageTexelPointer = 60,
|
|
SpvOpLoad = 61,
|
|
SpvOpStore = 62,
|
|
SpvOpCopyMemory = 63,
|
|
SpvOpCopyMemorySized = 64,
|
|
SpvOpAccessChain = 65,
|
|
SpvOpInBoundsAccessChain = 66,
|
|
SpvOpPtrAccessChain = 67,
|
|
SpvOpArrayLength = 68,
|
|
SpvOpGenericPtrMemSemantics = 69,
|
|
SpvOpInBoundsPtrAccessChain = 70,
|
|
SpvOpDecorate = 71,
|
|
SpvOpMemberDecorate = 72,
|
|
SpvOpDecorationGroup = 73,
|
|
SpvOpGroupDecorate = 74,
|
|
SpvOpGroupMemberDecorate = 75,
|
|
SpvOpVectorExtractDynamic = 77,
|
|
SpvOpVectorInsertDynamic = 78,
|
|
SpvOpVectorShuffle = 79,
|
|
SpvOpCompositeConstruct = 80,
|
|
SpvOpCompositeExtract = 81,
|
|
SpvOpCompositeInsert = 82,
|
|
SpvOpCopyObject = 83,
|
|
SpvOpTranspose = 84,
|
|
SpvOpSampledImage = 86,
|
|
SpvOpImageSampleImplicitLod = 87,
|
|
SpvOpImageSampleExplicitLod = 88,
|
|
SpvOpImageSampleDrefImplicitLod = 89,
|
|
SpvOpImageSampleDrefExplicitLod = 90,
|
|
SpvOpImageSampleProjImplicitLod = 91,
|
|
SpvOpImageSampleProjExplicitLod = 92,
|
|
SpvOpImageSampleProjDrefImplicitLod = 93,
|
|
SpvOpImageSampleProjDrefExplicitLod = 94,
|
|
SpvOpImageFetch = 95,
|
|
SpvOpImageGather = 96,
|
|
SpvOpImageDrefGather = 97,
|
|
SpvOpImageRead = 98,
|
|
SpvOpImageWrite = 99,
|
|
SpvOpImage = 100,
|
|
SpvOpImageQueryFormat = 101,
|
|
SpvOpImageQueryOrder = 102,
|
|
SpvOpImageQuerySizeLod = 103,
|
|
SpvOpImageQuerySize = 104,
|
|
SpvOpImageQueryLod = 105,
|
|
SpvOpImageQueryLevels = 106,
|
|
SpvOpImageQuerySamples = 107,
|
|
SpvOpConvertFToU = 109,
|
|
SpvOpConvertFToS = 110,
|
|
SpvOpConvertSToF = 111,
|
|
SpvOpConvertUToF = 112,
|
|
SpvOpUConvert = 113,
|
|
SpvOpSConvert = 114,
|
|
SpvOpFConvert = 115,
|
|
SpvOpQuantizeToF16 = 116,
|
|
SpvOpConvertPtrToU = 117,
|
|
SpvOpSatConvertSToU = 118,
|
|
SpvOpSatConvertUToS = 119,
|
|
SpvOpConvertUToPtr = 120,
|
|
SpvOpPtrCastToGeneric = 121,
|
|
SpvOpGenericCastToPtr = 122,
|
|
SpvOpGenericCastToPtrExplicit = 123,
|
|
SpvOpBitcast = 124,
|
|
SpvOpSNegate = 126,
|
|
SpvOpFNegate = 127,
|
|
SpvOpIAdd = 128,
|
|
SpvOpFAdd = 129,
|
|
SpvOpISub = 130,
|
|
SpvOpFSub = 131,
|
|
SpvOpIMul = 132,
|
|
SpvOpFMul = 133,
|
|
SpvOpUDiv = 134,
|
|
SpvOpSDiv = 135,
|
|
SpvOpFDiv = 136,
|
|
SpvOpUMod = 137,
|
|
SpvOpSRem = 138,
|
|
SpvOpSMod = 139,
|
|
SpvOpFRem = 140,
|
|
SpvOpFMod = 141,
|
|
SpvOpVectorTimesScalar = 142,
|
|
SpvOpMatrixTimesScalar = 143,
|
|
SpvOpVectorTimesMatrix = 144,
|
|
SpvOpMatrixTimesVector = 145,
|
|
SpvOpMatrixTimesMatrix = 146,
|
|
SpvOpOuterProduct = 147,
|
|
SpvOpDot = 148,
|
|
SpvOpIAddCarry = 149,
|
|
SpvOpISubBorrow = 150,
|
|
SpvOpUMulExtended = 151,
|
|
SpvOpSMulExtended = 152,
|
|
SpvOpAny = 154,
|
|
SpvOpAll = 155,
|
|
SpvOpIsNan = 156,
|
|
SpvOpIsInf = 157,
|
|
SpvOpIsFinite = 158,
|
|
SpvOpIsNormal = 159,
|
|
SpvOpSignBitSet = 160,
|
|
SpvOpLessOrGreater = 161,
|
|
SpvOpOrdered = 162,
|
|
SpvOpUnordered = 163,
|
|
SpvOpLogicalEqual = 164,
|
|
SpvOpLogicalNotEqual = 165,
|
|
SpvOpLogicalOr = 166,
|
|
SpvOpLogicalAnd = 167,
|
|
SpvOpLogicalNot = 168,
|
|
SpvOpSelect = 169,
|
|
SpvOpIEqual = 170,
|
|
SpvOpINotEqual = 171,
|
|
SpvOpUGreaterThan = 172,
|
|
SpvOpSGreaterThan = 173,
|
|
SpvOpUGreaterThanEqual = 174,
|
|
SpvOpSGreaterThanEqual = 175,
|
|
SpvOpULessThan = 176,
|
|
SpvOpSLessThan = 177,
|
|
SpvOpULessThanEqual = 178,
|
|
SpvOpSLessThanEqual = 179,
|
|
SpvOpFOrdEqual = 180,
|
|
SpvOpFUnordEqual = 181,
|
|
SpvOpFOrdNotEqual = 182,
|
|
SpvOpFUnordNotEqual = 183,
|
|
SpvOpFOrdLessThan = 184,
|
|
SpvOpFUnordLessThan = 185,
|
|
SpvOpFOrdGreaterThan = 186,
|
|
SpvOpFUnordGreaterThan = 187,
|
|
SpvOpFOrdLessThanEqual = 188,
|
|
SpvOpFUnordLessThanEqual = 189,
|
|
SpvOpFOrdGreaterThanEqual = 190,
|
|
SpvOpFUnordGreaterThanEqual = 191,
|
|
SpvOpShiftRightLogical = 194,
|
|
SpvOpShiftRightArithmetic = 195,
|
|
SpvOpShiftLeftLogical = 196,
|
|
SpvOpBitwiseOr = 197,
|
|
SpvOpBitwiseXor = 198,
|
|
SpvOpBitwiseAnd = 199,
|
|
SpvOpNot = 200,
|
|
SpvOpBitFieldInsert = 201,
|
|
SpvOpBitFieldSExtract = 202,
|
|
SpvOpBitFieldUExtract = 203,
|
|
SpvOpBitReverse = 204,
|
|
SpvOpBitCount = 205,
|
|
SpvOpDPdx = 207,
|
|
SpvOpDPdy = 208,
|
|
SpvOpFwidth = 209,
|
|
SpvOpDPdxFine = 210,
|
|
SpvOpDPdyFine = 211,
|
|
SpvOpFwidthFine = 212,
|
|
SpvOpDPdxCoarse = 213,
|
|
SpvOpDPdyCoarse = 214,
|
|
SpvOpFwidthCoarse = 215,
|
|
SpvOpEmitVertex = 218,
|
|
SpvOpEndPrimitive = 219,
|
|
SpvOpEmitStreamVertex = 220,
|
|
SpvOpEndStreamPrimitive = 221,
|
|
SpvOpControlBarrier = 224,
|
|
SpvOpMemoryBarrier = 225,
|
|
SpvOpAtomicLoad = 227,
|
|
SpvOpAtomicStore = 228,
|
|
SpvOpAtomicExchange = 229,
|
|
SpvOpAtomicCompareExchange = 230,
|
|
SpvOpAtomicCompareExchangeWeak = 231,
|
|
SpvOpAtomicIIncrement = 232,
|
|
SpvOpAtomicIDecrement = 233,
|
|
SpvOpAtomicIAdd = 234,
|
|
SpvOpAtomicISub = 235,
|
|
SpvOpAtomicSMin = 236,
|
|
SpvOpAtomicUMin = 237,
|
|
SpvOpAtomicSMax = 238,
|
|
SpvOpAtomicUMax = 239,
|
|
SpvOpAtomicAnd = 240,
|
|
SpvOpAtomicOr = 241,
|
|
SpvOpAtomicXor = 242,
|
|
SpvOpPhi = 245,
|
|
SpvOpLoopMerge = 246,
|
|
SpvOpSelectionMerge = 247,
|
|
SpvOpLabel = 248,
|
|
SpvOpBranch = 249,
|
|
SpvOpBranchConditional = 250,
|
|
SpvOpSwitch = 251,
|
|
SpvOpKill = 252,
|
|
SpvOpReturn = 253,
|
|
SpvOpReturnValue = 254,
|
|
SpvOpUnreachable = 255,
|
|
SpvOpLifetimeStart = 256,
|
|
SpvOpLifetimeStop = 257,
|
|
SpvOpGroupAsyncCopy = 259,
|
|
SpvOpGroupWaitEvents = 260,
|
|
SpvOpGroupAll = 261,
|
|
SpvOpGroupAny = 262,
|
|
SpvOpGroupBroadcast = 263,
|
|
SpvOpGroupIAdd = 264,
|
|
SpvOpGroupFAdd = 265,
|
|
SpvOpGroupFMin = 266,
|
|
SpvOpGroupUMin = 267,
|
|
SpvOpGroupSMin = 268,
|
|
SpvOpGroupFMax = 269,
|
|
SpvOpGroupUMax = 270,
|
|
SpvOpGroupSMax = 271,
|
|
SpvOpReadPipe = 274,
|
|
SpvOpWritePipe = 275,
|
|
SpvOpReservedReadPipe = 276,
|
|
SpvOpReservedWritePipe = 277,
|
|
SpvOpReserveReadPipePackets = 278,
|
|
SpvOpReserveWritePipePackets = 279,
|
|
SpvOpCommitReadPipe = 280,
|
|
SpvOpCommitWritePipe = 281,
|
|
SpvOpIsValidReserveId = 282,
|
|
SpvOpGetNumPipePackets = 283,
|
|
SpvOpGetMaxPipePackets = 284,
|
|
SpvOpGroupReserveReadPipePackets = 285,
|
|
SpvOpGroupReserveWritePipePackets = 286,
|
|
SpvOpGroupCommitReadPipe = 287,
|
|
SpvOpGroupCommitWritePipe = 288,
|
|
SpvOpEnqueueMarker = 291,
|
|
SpvOpEnqueueKernel = 292,
|
|
SpvOpGetKernelNDrangeSubGroupCount = 293,
|
|
SpvOpGetKernelNDrangeMaxSubGroupSize = 294,
|
|
SpvOpGetKernelWorkGroupSize = 295,
|
|
SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296,
|
|
SpvOpRetainEvent = 297,
|
|
SpvOpReleaseEvent = 298,
|
|
SpvOpCreateUserEvent = 299,
|
|
SpvOpIsValidEvent = 300,
|
|
SpvOpSetUserEventStatus = 301,
|
|
SpvOpCaptureEventProfilingInfo = 302,
|
|
SpvOpGetDefaultQueue = 303,
|
|
SpvOpBuildNDRange = 304,
|
|
SpvOpImageSparseSampleImplicitLod = 305,
|
|
SpvOpImageSparseSampleExplicitLod = 306,
|
|
SpvOpImageSparseSampleDrefImplicitLod = 307,
|
|
SpvOpImageSparseSampleDrefExplicitLod = 308,
|
|
SpvOpImageSparseSampleProjImplicitLod = 309,
|
|
SpvOpImageSparseSampleProjExplicitLod = 310,
|
|
SpvOpImageSparseSampleProjDrefImplicitLod = 311,
|
|
SpvOpImageSparseSampleProjDrefExplicitLod = 312,
|
|
SpvOpImageSparseFetch = 313,
|
|
SpvOpImageSparseGather = 314,
|
|
SpvOpImageSparseDrefGather = 315,
|
|
SpvOpImageSparseTexelsResident = 316,
|
|
SpvOpNoLine = 317,
|
|
SpvOpAtomicFlagTestAndSet = 318,
|
|
SpvOpAtomicFlagClear = 319,
|
|
SpvOpImageSparseRead = 320,
|
|
SpvOpSizeOf = 321,
|
|
SpvOpTypePipeStorage = 322,
|
|
SpvOpConstantPipeStorage = 323,
|
|
SpvOpCreatePipeFromPipeStorage = 324,
|
|
SpvOpGetKernelLocalSizeForSubgroupCount = 325,
|
|
SpvOpGetKernelMaxNumSubgroups = 326,
|
|
SpvOpTypeNamedBarrier = 327,
|
|
SpvOpNamedBarrierInitialize = 328,
|
|
SpvOpMemoryNamedBarrier = 329,
|
|
SpvOpModuleProcessed = 330,
|
|
SpvOpExecutionModeId = 331,
|
|
SpvOpDecorateId = 332,
|
|
SpvOpGroupNonUniformElect = 333,
|
|
SpvOpGroupNonUniformAll = 334,
|
|
SpvOpGroupNonUniformAny = 335,
|
|
SpvOpGroupNonUniformAllEqual = 336,
|
|
SpvOpGroupNonUniformBroadcast = 337,
|
|
SpvOpGroupNonUniformBroadcastFirst = 338,
|
|
SpvOpGroupNonUniformBallot = 339,
|
|
SpvOpGroupNonUniformInverseBallot = 340,
|
|
SpvOpGroupNonUniformBallotBitExtract = 341,
|
|
SpvOpGroupNonUniformBallotBitCount = 342,
|
|
SpvOpGroupNonUniformBallotFindLSB = 343,
|
|
SpvOpGroupNonUniformBallotFindMSB = 344,
|
|
SpvOpGroupNonUniformShuffle = 345,
|
|
SpvOpGroupNonUniformShuffleXor = 346,
|
|
SpvOpGroupNonUniformShuffleUp = 347,
|
|
SpvOpGroupNonUniformShuffleDown = 348,
|
|
SpvOpGroupNonUniformIAdd = 349,
|
|
SpvOpGroupNonUniformFAdd = 350,
|
|
SpvOpGroupNonUniformIMul = 351,
|
|
SpvOpGroupNonUniformFMul = 352,
|
|
SpvOpGroupNonUniformSMin = 353,
|
|
SpvOpGroupNonUniformUMin = 354,
|
|
SpvOpGroupNonUniformFMin = 355,
|
|
SpvOpGroupNonUniformSMax = 356,
|
|
SpvOpGroupNonUniformUMax = 357,
|
|
SpvOpGroupNonUniformFMax = 358,
|
|
SpvOpGroupNonUniformBitwiseAnd = 359,
|
|
SpvOpGroupNonUniformBitwiseOr = 360,
|
|
SpvOpGroupNonUniformBitwiseXor = 361,
|
|
SpvOpGroupNonUniformLogicalAnd = 362,
|
|
SpvOpGroupNonUniformLogicalOr = 363,
|
|
SpvOpGroupNonUniformLogicalXor = 364,
|
|
SpvOpGroupNonUniformQuadBroadcast = 365,
|
|
SpvOpGroupNonUniformQuadSwap = 366,
|
|
};
|
|
static const int kKnownOpsCount = SpvOpGroupNonUniformQuadSwap+1;
|
|
|
|
|
|
static const char* kSpirvOpNames[] =
|
|
{
|
|
"Nop",
|
|
"Undef",
|
|
"SourceContinued",
|
|
"Source",
|
|
"SourceExtension",
|
|
"Name",
|
|
"MemberName",
|
|
"String",
|
|
"Line",
|
|
"#9",
|
|
"Extension",
|
|
"ExtInstImport",
|
|
"ExtInst",
|
|
"VectorShuffleCompact",
|
|
"MemoryModel",
|
|
"EntryPoint",
|
|
"ExecutionMode",
|
|
"Capability",
|
|
"#18",
|
|
"TypeVoid",
|
|
"TypeBool",
|
|
"TypeInt",
|
|
"TypeFloat",
|
|
"TypeVector",
|
|
"TypeMatrix",
|
|
"TypeImage",
|
|
"TypeSampler",
|
|
"TypeSampledImage",
|
|
"TypeArray",
|
|
"TypeRuntimeArray",
|
|
"TypeStruct",
|
|
"TypeOpaque",
|
|
"TypePointer",
|
|
"TypeFunction",
|
|
"TypeEvent",
|
|
"TypeDeviceEvent",
|
|
"TypeReserveId",
|
|
"TypeQueue",
|
|
"TypePipe",
|
|
"TypeForwardPointer",
|
|
"#40",
|
|
"ConstantTrue",
|
|
"ConstantFalse",
|
|
"Constant",
|
|
"ConstantComposite",
|
|
"ConstantSampler",
|
|
"ConstantNull",
|
|
"#47",
|
|
"SpecConstantTrue",
|
|
"SpecConstantFalse",
|
|
"SpecConstant",
|
|
"SpecConstantComposite",
|
|
"SpecConstantOp",
|
|
"#53",
|
|
"Function",
|
|
"FunctionParameter",
|
|
"FunctionEnd",
|
|
"FunctionCall",
|
|
"#58",
|
|
"Variable",
|
|
"ImageTexelPointer",
|
|
"Load",
|
|
"Store",
|
|
"CopyMemory",
|
|
"CopyMemorySized",
|
|
"AccessChain",
|
|
"InBoundsAccessChain",
|
|
"PtrAccessChain",
|
|
"ArrayLength",
|
|
"GenericPtrMemSemantics",
|
|
"InBoundsPtrAccessChain",
|
|
"Decorate",
|
|
"MemberDecorate",
|
|
"DecorationGroup",
|
|
"GroupDecorate",
|
|
"GroupMemberDecorate",
|
|
"#76",
|
|
"VectorExtractDynamic",
|
|
"VectorInsertDynamic",
|
|
"VectorShuffle",
|
|
"CompositeConstruct",
|
|
"CompositeExtract",
|
|
"CompositeInsert",
|
|
"CopyObject",
|
|
"Transpose",
|
|
"#85",
|
|
"SampledImage",
|
|
"ImageSampleImplicitLod",
|
|
"ImageSampleExplicitLod",
|
|
"ImageSampleDrefImplicitLod",
|
|
"ImageSampleDrefExplicitLod",
|
|
"ImageSampleProjImplicitLod",
|
|
"ImageSampleProjExplicitLod",
|
|
"ImageSampleProjDrefImplicitLod",
|
|
"ImageSampleProjDrefExplicitLod",
|
|
"ImageFetch",
|
|
"ImageGather",
|
|
"ImageDrefGather",
|
|
"ImageRead",
|
|
"ImageWrite",
|
|
"Image",
|
|
"ImageQueryFormat",
|
|
"ImageQueryOrder",
|
|
"ImageQuerySizeLod",
|
|
"ImageQuerySize",
|
|
"ImageQueryLod",
|
|
"ImageQueryLevels",
|
|
"ImageQuerySamples",
|
|
"#108",
|
|
"ConvertFToU",
|
|
"ConvertFToS",
|
|
"ConvertSToF",
|
|
"ConvertUToF",
|
|
"UConvert",
|
|
"SConvert",
|
|
"FConvert",
|
|
"QuantizeToF16",
|
|
"ConvertPtrToU",
|
|
"SatConvertSToU",
|
|
"SatConvertUToS",
|
|
"ConvertUToPtr",
|
|
"PtrCastToGeneric",
|
|
"GenericCastToPtr",
|
|
"GenericCastToPtrExplicit",
|
|
"Bitcast",
|
|
"#125",
|
|
"SNegate",
|
|
"FNegate",
|
|
"IAdd",
|
|
"FAdd",
|
|
"ISub",
|
|
"FSub",
|
|
"IMul",
|
|
"FMul",
|
|
"UDiv",
|
|
"SDiv",
|
|
"FDiv",
|
|
"UMod",
|
|
"SRem",
|
|
"SMod",
|
|
"FRem",
|
|
"FMod",
|
|
"VectorTimesScalar",
|
|
"MatrixTimesScalar",
|
|
"VectorTimesMatrix",
|
|
"MatrixTimesVector",
|
|
"MatrixTimesMatrix",
|
|
"OuterProduct",
|
|
"Dot",
|
|
"IAddCarry",
|
|
"ISubBorrow",
|
|
"UMulExtended",
|
|
"SMulExtended",
|
|
"#153",
|
|
"Any",
|
|
"All",
|
|
"IsNan",
|
|
"IsInf",
|
|
"IsFinite",
|
|
"IsNormal",
|
|
"SignBitSet",
|
|
"LessOrGreater",
|
|
"Ordered",
|
|
"Unordered",
|
|
"LogicalEqual",
|
|
"LogicalNotEqual",
|
|
"LogicalOr",
|
|
"LogicalAnd",
|
|
"LogicalNot",
|
|
"Select",
|
|
"IEqual",
|
|
"INotEqual",
|
|
"UGreaterThan",
|
|
"SGreaterThan",
|
|
"UGreaterThanEqual",
|
|
"SGreaterThanEqual",
|
|
"ULessThan",
|
|
"SLessThan",
|
|
"ULessThanEqual",
|
|
"SLessThanEqual",
|
|
"FOrdEqual",
|
|
"FUnordEqual",
|
|
"FOrdNotEqual",
|
|
"FUnordNotEqual",
|
|
"FOrdLessThan",
|
|
"FUnordLessThan",
|
|
"FOrdGreaterThan",
|
|
"FUnordGreaterThan",
|
|
"FOrdLessThanEqual",
|
|
"FUnordLessThanEqual",
|
|
"FOrdGreaterThanEqual",
|
|
"FUnordGreaterThanEqual",
|
|
"#192",
|
|
"#193",
|
|
"ShiftRightLogical",
|
|
"ShiftRightArithmetic",
|
|
"ShiftLeftLogical",
|
|
"BitwiseOr",
|
|
"BitwiseXor",
|
|
"BitwiseAnd",
|
|
"Not",
|
|
"BitFieldInsert",
|
|
"BitFieldSExtract",
|
|
"BitFieldUExtract",
|
|
"BitReverse",
|
|
"BitCount",
|
|
"#206",
|
|
"DPdx",
|
|
"DPdy",
|
|
"Fwidth",
|
|
"DPdxFine",
|
|
"DPdyFine",
|
|
"FwidthFine",
|
|
"DPdxCoarse",
|
|
"DPdyCoarse",
|
|
"FwidthCoarse",
|
|
"#216",
|
|
"#217",
|
|
"EmitVertex",
|
|
"EndPrimitive",
|
|
"EmitStreamVertex",
|
|
"EndStreamPrimitive",
|
|
"#222",
|
|
"#223",
|
|
"ControlBarrier",
|
|
"MemoryBarrier",
|
|
"#226",
|
|
"AtomicLoad",
|
|
"AtomicStore",
|
|
"AtomicExchange",
|
|
"AtomicCompareExchange",
|
|
"AtomicCompareExchangeWeak",
|
|
"AtomicIIncrement",
|
|
"AtomicIDecrement",
|
|
"AtomicIAdd",
|
|
"AtomicISub",
|
|
"AtomicSMin",
|
|
"AtomicUMin",
|
|
"AtomicSMax",
|
|
"AtomicUMax",
|
|
"AtomicAnd",
|
|
"AtomicOr",
|
|
"AtomicXor",
|
|
"#243",
|
|
"#244",
|
|
"Phi",
|
|
"LoopMerge",
|
|
"SelectionMerge",
|
|
"Label",
|
|
"Branch",
|
|
"BranchConditional",
|
|
"Switch",
|
|
"Kill",
|
|
"Return",
|
|
"ReturnValue",
|
|
"Unreachable",
|
|
"LifetimeStart",
|
|
"LifetimeStop",
|
|
"#258",
|
|
"GroupAsyncCopy",
|
|
"GroupWaitEvents",
|
|
"GroupAll",
|
|
"GroupAny",
|
|
"GroupBroadcast",
|
|
"GroupIAdd",
|
|
"GroupFAdd",
|
|
"GroupFMin",
|
|
"GroupUMin",
|
|
"GroupSMin",
|
|
"GroupFMax",
|
|
"GroupUMax",
|
|
"GroupSMax",
|
|
"#272",
|
|
"#273",
|
|
"ReadPipe",
|
|
"WritePipe",
|
|
"ReservedReadPipe",
|
|
"ReservedWritePipe",
|
|
"ReserveReadPipePackets",
|
|
"ReserveWritePipePackets",
|
|
"CommitReadPipe",
|
|
"CommitWritePipe",
|
|
"IsValidReserveId",
|
|
"GetNumPipePackets",
|
|
"GetMaxPipePackets",
|
|
"GroupReserveReadPipePackets",
|
|
"GroupReserveWritePipePackets",
|
|
"GroupCommitReadPipe",
|
|
"GroupCommitWritePipe",
|
|
"#289",
|
|
"#290",
|
|
"EnqueueMarker",
|
|
"EnqueueKernel",
|
|
"GetKernelNDrangeSubGroupCount",
|
|
"GetKernelNDrangeMaxSubGroupSize",
|
|
"GetKernelWorkGroupSize",
|
|
"GetKernelPreferredWorkGroupSizeMultiple",
|
|
"RetainEvent",
|
|
"ReleaseEvent",
|
|
"CreateUserEvent",
|
|
"IsValidEvent",
|
|
"SetUserEventStatus",
|
|
"CaptureEventProfilingInfo",
|
|
"GetDefaultQueue",
|
|
"BuildNDRange",
|
|
"ImageSparseSampleImplicitLod",
|
|
"ImageSparseSampleExplicitLod",
|
|
"ImageSparseSampleDrefImplicitLod",
|
|
"ImageSparseSampleDrefExplicitLod",
|
|
"ImageSparseSampleProjImplicitLod",
|
|
"ImageSparseSampleProjExplicitLod",
|
|
"ImageSparseSampleProjDrefImplicitLod",
|
|
"ImageSparseSampleProjDrefExplicitLod",
|
|
"ImageSparseFetch",
|
|
"ImageSparseGather",
|
|
"ImageSparseDrefGather",
|
|
"ImageSparseTexelsResident",
|
|
"NoLine",
|
|
"AtomicFlagTestAndSet",
|
|
"AtomicFlagClear",
|
|
"ImageSparseRead",
|
|
"SizeOf",
|
|
"TypePipeStorage",
|
|
"ConstantPipeStorage",
|
|
"CreatePipeFromPipeStorage",
|
|
"GetKernelLocalSizeForSubgroupCount",
|
|
"GetKernelMaxNumSubgroups",
|
|
"TypeNamedBarrier",
|
|
"NamedBarrierInitialize",
|
|
"MemoryNamedBarrier",
|
|
"ModuleProcessed",
|
|
"ExecutionModeId",
|
|
"DecorateId",
|
|
"GroupNonUniformElect",
|
|
"GroupNonUniformAll",
|
|
"GroupNonUniformAny",
|
|
"GroupNonUniformAllEqual",
|
|
"GroupNonUniformBroadcast",
|
|
"GroupNonUniformBroadcastFirst",
|
|
"GroupNonUniformBallot",
|
|
"GroupNonUniformInverseBallot",
|
|
"GroupNonUniformBallotBitExtract",
|
|
"GroupNonUniformBallotBitCount",
|
|
"GroupNonUniformBallotFindLSB",
|
|
"GroupNonUniformBallotFindMSB",
|
|
"GroupNonUniformShuffle",
|
|
"GroupNonUniformShuffleXor",
|
|
"GroupNonUniformShuffleUp",
|
|
"GroupNonUniformShuffleDown",
|
|
"GroupNonUniformIAdd",
|
|
"GroupNonUniformFAdd",
|
|
"GroupNonUniformIMul",
|
|
"GroupNonUniformFMul",
|
|
"GroupNonUniformSMin",
|
|
"GroupNonUniformUMin",
|
|
"GroupNonUniformFMin",
|
|
"GroupNonUniformSMax",
|
|
"GroupNonUniformUMax",
|
|
"GroupNonUniformFMax",
|
|
"GroupNonUniformBitwiseAnd",
|
|
"GroupNonUniformBitwiseOr",
|
|
"GroupNonUniformBitwiseXor",
|
|
"GroupNonUniformLogicalAnd",
|
|
"GroupNonUniformLogicalOr",
|
|
"GroupNonUniformLogicalXor",
|
|
"GroupNonUniformQuadBroadcast",
|
|
"GroupNonUniformQuadSwap",
|
|
};
|
|
static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpNames) == kKnownOpsCount, "kSpirvOpNames table mismatch with known SpvOps");
|
|
|
|
|
|
struct OpData
|
|
{
|
|
uint8_t hasResult; // does it have result ID?
|
|
uint8_t hasType; // does it have type ID?
|
|
uint8_t deltaFromResult; // How many words after (optional) type+result to write out as deltas from result?
|
|
uint8_t varrest; // should the rest of words be written in varint encoding?
|
|
};
|
|
static const OpData kSpirvOpData[] =
|
|
{
|
|
{0, 0, 0, 0}, // Nop
|
|
{1, 1, 0, 0}, // Undef
|
|
{0, 0, 0, 0}, // SourceContinued
|
|
{0, 0, 0, 1}, // Source
|
|
{0, 0, 0, 0}, // SourceExtension
|
|
{0, 0, 0, 0}, // Name
|
|
{0, 0, 0, 0}, // MemberName
|
|
{0, 0, 0, 0}, // String
|
|
{0, 0, 0, 1}, // Line
|
|
{1, 1, 0, 0}, // #9
|
|
{0, 0, 0, 0}, // Extension
|
|
{1, 0, 0, 0}, // ExtInstImport
|
|
{1, 1, 0, 1}, // ExtInst
|
|
{1, 1, 2, 1}, // VectorShuffleCompact - new in SMOLV
|
|
{0, 0, 0, 1}, // MemoryModel
|
|
{0, 0, 0, 1}, // EntryPoint
|
|
{0, 0, 0, 1}, // ExecutionMode
|
|
{0, 0, 0, 1}, // Capability
|
|
{1, 1, 0, 0}, // #18
|
|
{1, 0, 0, 1}, // TypeVoid
|
|
{1, 0, 0, 1}, // TypeBool
|
|
{1, 0, 0, 1}, // TypeInt
|
|
{1, 0, 0, 1}, // TypeFloat
|
|
{1, 0, 0, 1}, // TypeVector
|
|
{1, 0, 0, 1}, // TypeMatrix
|
|
{1, 0, 0, 1}, // TypeImage
|
|
{1, 0, 0, 1}, // TypeSampler
|
|
{1, 0, 0, 1}, // TypeSampledImage
|
|
{1, 0, 0, 1}, // TypeArray
|
|
{1, 0, 0, 1}, // TypeRuntimeArray
|
|
{1, 0, 0, 1}, // TypeStruct
|
|
{1, 0, 0, 1}, // TypeOpaque
|
|
{1, 0, 0, 1}, // TypePointer
|
|
{1, 0, 0, 1}, // TypeFunction
|
|
{1, 0, 0, 1}, // TypeEvent
|
|
{1, 0, 0, 1}, // TypeDeviceEvent
|
|
{1, 0, 0, 1}, // TypeReserveId
|
|
{1, 0, 0, 1}, // TypeQueue
|
|
{1, 0, 0, 1}, // TypePipe
|
|
{0, 0, 0, 1}, // TypeForwardPointer
|
|
{1, 1, 0, 0}, // #40
|
|
{1, 1, 0, 0}, // ConstantTrue
|
|
{1, 1, 0, 0}, // ConstantFalse
|
|
{1, 1, 0, 0}, // Constant
|
|
{1, 1, 9, 0}, // ConstantComposite
|
|
{1, 1, 0, 1}, // ConstantSampler
|
|
{1, 1, 0, 0}, // ConstantNull
|
|
{1, 1, 0, 0}, // #47
|
|
{1, 1, 0, 0}, // SpecConstantTrue
|
|
{1, 1, 0, 0}, // SpecConstantFalse
|
|
{1, 1, 0, 0}, // SpecConstant
|
|
{1, 1, 9, 0}, // SpecConstantComposite
|
|
{1, 1, 0, 0}, // SpecConstantOp
|
|
{1, 1, 0, 0}, // #53
|
|
{1, 1, 0, 1}, // Function
|
|
{1, 1, 0, 0}, // FunctionParameter
|
|
{0, 0, 0, 0}, // FunctionEnd
|
|
{1, 1, 9, 0}, // FunctionCall
|
|
{1, 1, 0, 0}, // #58
|
|
{1, 1, 0, 1}, // Variable
|
|
{1, 1, 0, 0}, // ImageTexelPointer
|
|
{1, 1, 1, 1}, // Load
|
|
{0, 0, 2, 1}, // Store
|
|
{0, 0, 0, 0}, // CopyMemory
|
|
{0, 0, 0, 0}, // CopyMemorySized
|
|
{1, 1, 0, 1}, // AccessChain
|
|
{1, 1, 0, 0}, // InBoundsAccessChain
|
|
{1, 1, 0, 0}, // PtrAccessChain
|
|
{1, 1, 0, 0}, // ArrayLength
|
|
{1, 1, 0, 0}, // GenericPtrMemSemantics
|
|
{1, 1, 0, 0}, // InBoundsPtrAccessChain
|
|
{0, 0, 0, 1}, // Decorate
|
|
{0, 0, 0, 1}, // MemberDecorate
|
|
{1, 0, 0, 0}, // DecorationGroup
|
|
{0, 0, 0, 0}, // GroupDecorate
|
|
{0, 0, 0, 0}, // GroupMemberDecorate
|
|
{1, 1, 0, 0}, // #76
|
|
{1, 1, 1, 1}, // VectorExtractDynamic
|
|
{1, 1, 2, 1}, // VectorInsertDynamic
|
|
{1, 1, 2, 1}, // VectorShuffle
|
|
{1, 1, 9, 0}, // CompositeConstruct
|
|
{1, 1, 1, 1}, // CompositeExtract
|
|
{1, 1, 2, 1}, // CompositeInsert
|
|
{1, 1, 1, 0}, // CopyObject
|
|
{1, 1, 0, 0}, // Transpose
|
|
{1, 1, 0, 0}, // #85
|
|
{1, 1, 0, 0}, // SampledImage
|
|
{1, 1, 2, 1}, // ImageSampleImplicitLod
|
|
{1, 1, 2, 1}, // ImageSampleExplicitLod
|
|
{1, 1, 3, 1}, // ImageSampleDrefImplicitLod
|
|
{1, 1, 3, 1}, // ImageSampleDrefExplicitLod
|
|
{1, 1, 2, 1}, // ImageSampleProjImplicitLod
|
|
{1, 1, 2, 1}, // ImageSampleProjExplicitLod
|
|
{1, 1, 3, 1}, // ImageSampleProjDrefImplicitLod
|
|
{1, 1, 3, 1}, // ImageSampleProjDrefExplicitLod
|
|
{1, 1, 2, 1}, // ImageFetch
|
|
{1, 1, 3, 1}, // ImageGather
|
|
{1, 1, 3, 1}, // ImageDrefGather
|
|
{1, 1, 2, 1}, // ImageRead
|
|
{0, 0, 3, 1}, // ImageWrite
|
|
{1, 1, 1, 0}, // Image
|
|
{1, 1, 1, 0}, // ImageQueryFormat
|
|
{1, 1, 1, 0}, // ImageQueryOrder
|
|
{1, 1, 2, 0}, // ImageQuerySizeLod
|
|
{1, 1, 1, 0}, // ImageQuerySize
|
|
{1, 1, 2, 0}, // ImageQueryLod
|
|
{1, 1, 1, 0}, // ImageQueryLevels
|
|
{1, 1, 1, 0}, // ImageQuerySamples
|
|
{1, 1, 0, 0}, // #108
|
|
{1, 1, 1, 0}, // ConvertFToU
|
|
{1, 1, 1, 0}, // ConvertFToS
|
|
{1, 1, 1, 0}, // ConvertSToF
|
|
{1, 1, 1, 0}, // ConvertUToF
|
|
{1, 1, 1, 0}, // UConvert
|
|
{1, 1, 1, 0}, // SConvert
|
|
{1, 1, 1, 0}, // FConvert
|
|
{1, 1, 1, 0}, // QuantizeToF16
|
|
{1, 1, 1, 0}, // ConvertPtrToU
|
|
{1, 1, 1, 0}, // SatConvertSToU
|
|
{1, 1, 1, 0}, // SatConvertUToS
|
|
{1, 1, 1, 0}, // ConvertUToPtr
|
|
{1, 1, 1, 0}, // PtrCastToGeneric
|
|
{1, 1, 1, 0}, // GenericCastToPtr
|
|
{1, 1, 1, 1}, // GenericCastToPtrExplicit
|
|
{1, 1, 1, 0}, // Bitcast
|
|
{1, 1, 0, 0}, // #125
|
|
{1, 1, 1, 0}, // SNegate
|
|
{1, 1, 1, 0}, // FNegate
|
|
{1, 1, 2, 0}, // IAdd
|
|
{1, 1, 2, 0}, // FAdd
|
|
{1, 1, 2, 0}, // ISub
|
|
{1, 1, 2, 0}, // FSub
|
|
{1, 1, 2, 0}, // IMul
|
|
{1, 1, 2, 0}, // FMul
|
|
{1, 1, 2, 0}, // UDiv
|
|
{1, 1, 2, 0}, // SDiv
|
|
{1, 1, 2, 0}, // FDiv
|
|
{1, 1, 2, 0}, // UMod
|
|
{1, 1, 2, 0}, // SRem
|
|
{1, 1, 2, 0}, // SMod
|
|
{1, 1, 2, 0}, // FRem
|
|
{1, 1, 2, 0}, // FMod
|
|
{1, 1, 2, 0}, // VectorTimesScalar
|
|
{1, 1, 2, 0}, // MatrixTimesScalar
|
|
{1, 1, 2, 0}, // VectorTimesMatrix
|
|
{1, 1, 2, 0}, // MatrixTimesVector
|
|
{1, 1, 2, 0}, // MatrixTimesMatrix
|
|
{1, 1, 2, 0}, // OuterProduct
|
|
{1, 1, 2, 0}, // Dot
|
|
{1, 1, 2, 0}, // IAddCarry
|
|
{1, 1, 2, 0}, // ISubBorrow
|
|
{1, 1, 2, 0}, // UMulExtended
|
|
{1, 1, 2, 0}, // SMulExtended
|
|
{1, 1, 0, 0}, // #153
|
|
{1, 1, 1, 0}, // Any
|
|
{1, 1, 1, 0}, // All
|
|
{1, 1, 1, 0}, // IsNan
|
|
{1, 1, 1, 0}, // IsInf
|
|
{1, 1, 1, 0}, // IsFinite
|
|
{1, 1, 1, 0}, // IsNormal
|
|
{1, 1, 1, 0}, // SignBitSet
|
|
{1, 1, 2, 0}, // LessOrGreater
|
|
{1, 1, 2, 0}, // Ordered
|
|
{1, 1, 2, 0}, // Unordered
|
|
{1, 1, 2, 0}, // LogicalEqual
|
|
{1, 1, 2, 0}, // LogicalNotEqual
|
|
{1, 1, 2, 0}, // LogicalOr
|
|
{1, 1, 2, 0}, // LogicalAnd
|
|
{1, 1, 1, 0}, // LogicalNot
|
|
{1, 1, 3, 0}, // Select
|
|
{1, 1, 2, 0}, // IEqual
|
|
{1, 1, 2, 0}, // INotEqual
|
|
{1, 1, 2, 0}, // UGreaterThan
|
|
{1, 1, 2, 0}, // SGreaterThan
|
|
{1, 1, 2, 0}, // UGreaterThanEqual
|
|
{1, 1, 2, 0}, // SGreaterThanEqual
|
|
{1, 1, 2, 0}, // ULessThan
|
|
{1, 1, 2, 0}, // SLessThan
|
|
{1, 1, 2, 0}, // ULessThanEqual
|
|
{1, 1, 2, 0}, // SLessThanEqual
|
|
{1, 1, 2, 0}, // FOrdEqual
|
|
{1, 1, 2, 0}, // FUnordEqual
|
|
{1, 1, 2, 0}, // FOrdNotEqual
|
|
{1, 1, 2, 0}, // FUnordNotEqual
|
|
{1, 1, 2, 0}, // FOrdLessThan
|
|
{1, 1, 2, 0}, // FUnordLessThan
|
|
{1, 1, 2, 0}, // FOrdGreaterThan
|
|
{1, 1, 2, 0}, // FUnordGreaterThan
|
|
{1, 1, 2, 0}, // FOrdLessThanEqual
|
|
{1, 1, 2, 0}, // FUnordLessThanEqual
|
|
{1, 1, 2, 0}, // FOrdGreaterThanEqual
|
|
{1, 1, 2, 0}, // FUnordGreaterThanEqual
|
|
{1, 1, 0, 0}, // #192
|
|
{1, 1, 0, 0}, // #193
|
|
{1, 1, 2, 0}, // ShiftRightLogical
|
|
{1, 1, 2, 0}, // ShiftRightArithmetic
|
|
{1, 1, 2, 0}, // ShiftLeftLogical
|
|
{1, 1, 2, 0}, // BitwiseOr
|
|
{1, 1, 2, 0}, // BitwiseXor
|
|
{1, 1, 2, 0}, // BitwiseAnd
|
|
{1, 1, 1, 0}, // Not
|
|
{1, 1, 4, 0}, // BitFieldInsert
|
|
{1, 1, 3, 0}, // BitFieldSExtract
|
|
{1, 1, 3, 0}, // BitFieldUExtract
|
|
{1, 1, 1, 0}, // BitReverse
|
|
{1, 1, 1, 0}, // BitCount
|
|
{1, 1, 0, 0}, // #206
|
|
{1, 1, 0, 0}, // DPdx
|
|
{1, 1, 0, 0}, // DPdy
|
|
{1, 1, 0, 0}, // Fwidth
|
|
{1, 1, 0, 0}, // DPdxFine
|
|
{1, 1, 0, 0}, // DPdyFine
|
|
{1, 1, 0, 0}, // FwidthFine
|
|
{1, 1, 0, 0}, // DPdxCoarse
|
|
{1, 1, 0, 0}, // DPdyCoarse
|
|
{1, 1, 0, 0}, // FwidthCoarse
|
|
{1, 1, 0, 0}, // #216
|
|
{1, 1, 0, 0}, // #217
|
|
{0, 0, 0, 0}, // EmitVertex
|
|
{0, 0, 0, 0}, // EndPrimitive
|
|
{0, 0, 0, 0}, // EmitStreamVertex
|
|
{0, 0, 0, 0}, // EndStreamPrimitive
|
|
{1, 1, 0, 0}, // #222
|
|
{1, 1, 0, 0}, // #223
|
|
{0, 0, 3, 0}, // ControlBarrier
|
|
{0, 0, 2, 0}, // MemoryBarrier
|
|
{1, 1, 0, 0}, // #226
|
|
{1, 1, 0, 0}, // AtomicLoad
|
|
{0, 0, 0, 0}, // AtomicStore
|
|
{1, 1, 0, 0}, // AtomicExchange
|
|
{1, 1, 0, 0}, // AtomicCompareExchange
|
|
{1, 1, 0, 0}, // AtomicCompareExchangeWeak
|
|
{1, 1, 0, 0}, // AtomicIIncrement
|
|
{1, 1, 0, 0}, // AtomicIDecrement
|
|
{1, 1, 0, 0}, // AtomicIAdd
|
|
{1, 1, 0, 0}, // AtomicISub
|
|
{1, 1, 0, 0}, // AtomicSMin
|
|
{1, 1, 0, 0}, // AtomicUMin
|
|
{1, 1, 0, 0}, // AtomicSMax
|
|
{1, 1, 0, 0}, // AtomicUMax
|
|
{1, 1, 0, 0}, // AtomicAnd
|
|
{1, 1, 0, 0}, // AtomicOr
|
|
{1, 1, 0, 0}, // AtomicXor
|
|
{1, 1, 0, 0}, // #243
|
|
{1, 1, 0, 0}, // #244
|
|
{1, 1, 0, 0}, // Phi
|
|
{0, 0, 2, 1}, // LoopMerge
|
|
{0, 0, 1, 1}, // SelectionMerge
|
|
{1, 0, 0, 0}, // Label
|
|
{0, 0, 1, 0}, // Branch
|
|
{0, 0, 3, 1}, // BranchConditional
|
|
{0, 0, 0, 0}, // Switch
|
|
{0, 0, 0, 0}, // Kill
|
|
{0, 0, 0, 0}, // Return
|
|
{0, 0, 0, 0}, // ReturnValue
|
|
{0, 0, 0, 0}, // Unreachable
|
|
{0, 0, 0, 0}, // LifetimeStart
|
|
{0, 0, 0, 0}, // LifetimeStop
|
|
{1, 1, 0, 0}, // #258
|
|
{1, 1, 0, 0}, // GroupAsyncCopy
|
|
{0, 0, 0, 0}, // GroupWaitEvents
|
|
{1, 1, 0, 0}, // GroupAll
|
|
{1, 1, 0, 0}, // GroupAny
|
|
{1, 1, 0, 0}, // GroupBroadcast
|
|
{1, 1, 0, 0}, // GroupIAdd
|
|
{1, 1, 0, 0}, // GroupFAdd
|
|
{1, 1, 0, 0}, // GroupFMin
|
|
{1, 1, 0, 0}, // GroupUMin
|
|
{1, 1, 0, 0}, // GroupSMin
|
|
{1, 1, 0, 0}, // GroupFMax
|
|
{1, 1, 0, 0}, // GroupUMax
|
|
{1, 1, 0, 0}, // GroupSMax
|
|
{1, 1, 0, 0}, // #272
|
|
{1, 1, 0, 0}, // #273
|
|
{1, 1, 0, 0}, // ReadPipe
|
|
{1, 1, 0, 0}, // WritePipe
|
|
{1, 1, 0, 0}, // ReservedReadPipe
|
|
{1, 1, 0, 0}, // ReservedWritePipe
|
|
{1, 1, 0, 0}, // ReserveReadPipePackets
|
|
{1, 1, 0, 0}, // ReserveWritePipePackets
|
|
{0, 0, 0, 0}, // CommitReadPipe
|
|
{0, 0, 0, 0}, // CommitWritePipe
|
|
{1, 1, 0, 0}, // IsValidReserveId
|
|
{1, 1, 0, 0}, // GetNumPipePackets
|
|
{1, 1, 0, 0}, // GetMaxPipePackets
|
|
{1, 1, 0, 0}, // GroupReserveReadPipePackets
|
|
{1, 1, 0, 0}, // GroupReserveWritePipePackets
|
|
{0, 0, 0, 0}, // GroupCommitReadPipe
|
|
{0, 0, 0, 0}, // GroupCommitWritePipe
|
|
{1, 1, 0, 0}, // #289
|
|
{1, 1, 0, 0}, // #290
|
|
{1, 1, 0, 0}, // EnqueueMarker
|
|
{1, 1, 0, 0}, // EnqueueKernel
|
|
{1, 1, 0, 0}, // GetKernelNDrangeSubGroupCount
|
|
{1, 1, 0, 0}, // GetKernelNDrangeMaxSubGroupSize
|
|
{1, 1, 0, 0}, // GetKernelWorkGroupSize
|
|
{1, 1, 0, 0}, // GetKernelPreferredWorkGroupSizeMultiple
|
|
{0, 0, 0, 0}, // RetainEvent
|
|
{0, 0, 0, 0}, // ReleaseEvent
|
|
{1, 1, 0, 0}, // CreateUserEvent
|
|
{1, 1, 0, 0}, // IsValidEvent
|
|
{0, 0, 0, 0}, // SetUserEventStatus
|
|
{0, 0, 0, 0}, // CaptureEventProfilingInfo
|
|
{1, 1, 0, 0}, // GetDefaultQueue
|
|
{1, 1, 0, 0}, // BuildNDRange
|
|
{1, 1, 2, 1}, // ImageSparseSampleImplicitLod
|
|
{1, 1, 2, 1}, // ImageSparseSampleExplicitLod
|
|
{1, 1, 3, 1}, // ImageSparseSampleDrefImplicitLod
|
|
{1, 1, 3, 1}, // ImageSparseSampleDrefExplicitLod
|
|
{1, 1, 2, 1}, // ImageSparseSampleProjImplicitLod
|
|
{1, 1, 2, 1}, // ImageSparseSampleProjExplicitLod
|
|
{1, 1, 3, 1}, // ImageSparseSampleProjDrefImplicitLod
|
|
{1, 1, 3, 1}, // ImageSparseSampleProjDrefExplicitLod
|
|
{1, 1, 2, 1}, // ImageSparseFetch
|
|
{1, 1, 3, 1}, // ImageSparseGather
|
|
{1, 1, 3, 1}, // ImageSparseDrefGather
|
|
{1, 1, 1, 0}, // ImageSparseTexelsResident
|
|
{0, 0, 0, 0}, // NoLine
|
|
{1, 1, 0, 0}, // AtomicFlagTestAndSet
|
|
{0, 0, 0, 0}, // AtomicFlagClear
|
|
{1, 1, 0, 0}, // ImageSparseRead
|
|
{1, 1, 0, 0}, // SizeOf
|
|
{1, 1, 0, 0}, // TypePipeStorage
|
|
{1, 1, 0, 0}, // ConstantPipeStorage
|
|
{1, 1, 0, 0}, // CreatePipeFromPipeStorage
|
|
{1, 1, 0, 0}, // GetKernelLocalSizeForSubgroupCount
|
|
{1, 1, 0, 0}, // GetKernelMaxNumSubgroups
|
|
{1, 1, 0, 0}, // TypeNamedBarrier
|
|
{1, 1, 0, 1}, // NamedBarrierInitialize
|
|
{0, 0, 2, 1}, // MemoryNamedBarrier
|
|
{1, 1, 0, 0}, // ModuleProcessed
|
|
{0, 0, 0, 1}, // ExecutionModeId
|
|
{0, 0, 0, 1}, // DecorateId
|
|
{1, 1, 1, 1}, // GroupNonUniformElect
|
|
{1, 1, 1, 1}, // GroupNonUniformAll
|
|
{1, 1, 1, 1}, // GroupNonUniformAny
|
|
{1, 1, 1, 1}, // GroupNonUniformAllEqual
|
|
{1, 1, 1, 1}, // GroupNonUniformBroadcast
|
|
{1, 1, 1, 1}, // GroupNonUniformBroadcastFirst
|
|
{1, 1, 1, 1}, // GroupNonUniformBallot
|
|
{1, 1, 1, 1}, // GroupNonUniformInverseBallot
|
|
{1, 1, 1, 1}, // GroupNonUniformBallotBitExtract
|
|
{1, 1, 1, 1}, // GroupNonUniformBallotBitCount
|
|
{1, 1, 1, 1}, // GroupNonUniformBallotFindLSB
|
|
{1, 1, 1, 1}, // GroupNonUniformBallotFindMSB
|
|
{1, 1, 1, 1}, // GroupNonUniformShuffle
|
|
{1, 1, 1, 1}, // GroupNonUniformShuffleXor
|
|
{1, 1, 1, 1}, // GroupNonUniformShuffleUp
|
|
{1, 1, 1, 1}, // GroupNonUniformShuffleDown
|
|
{1, 1, 1, 1}, // GroupNonUniformIAdd
|
|
{1, 1, 1, 1}, // GroupNonUniformFAdd
|
|
{1, 1, 1, 1}, // GroupNonUniformIMul
|
|
{1, 1, 1, 1}, // GroupNonUniformFMul
|
|
{1, 1, 1, 1}, // GroupNonUniformSMin
|
|
{1, 1, 1, 1}, // GroupNonUniformUMin
|
|
{1, 1, 1, 1}, // GroupNonUniformFMin
|
|
{1, 1, 1, 1}, // GroupNonUniformSMax
|
|
{1, 1, 1, 1}, // GroupNonUniformUMax
|
|
{1, 1, 1, 1}, // GroupNonUniformFMax
|
|
{1, 1, 1, 1}, // GroupNonUniformBitwiseAnd
|
|
{1, 1, 1, 1}, // GroupNonUniformBitwiseOr
|
|
{1, 1, 1, 1}, // GroupNonUniformBitwiseXor
|
|
{1, 1, 1, 1}, // GroupNonUniformLogicalAnd
|
|
{1, 1, 1, 1}, // GroupNonUniformLogicalOr
|
|
{1, 1, 1, 1}, // GroupNonUniformLogicalXor
|
|
{1, 1, 1, 1}, // GroupNonUniformQuadBroadcast
|
|
{1, 1, 1, 1}, // GroupNonUniformQuadSwap
|
|
};
|
|
static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpData) == kKnownOpsCount, "kSpirvOpData table mismatch with known SpvOps");
|
|
|
|
// 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)
|
|
{
|
|
if (version == 0)
|
|
return SpvOpModuleProcessed+1;
|
|
if (version == 1) // 2020 February, version 1 added ExecutionModeId..GroupNonUniformQuadSwap
|
|
return SpvOpGroupNonUniformQuadSwap+1;
|
|
return 0;
|
|
}
|
|
|
|
static bool smolv_OpHasResult(SpvOp op, int opsCount)
|
|
{
|
|
if (op < 0 || op >= opsCount)
|
|
return false;
|
|
return kSpirvOpData[op].hasResult != 0;
|
|
}
|
|
|
|
static bool smolv_OpHasType(SpvOp op, int opsCount)
|
|
{
|
|
if (op < 0 || op >= opsCount)
|
|
return false;
|
|
return kSpirvOpData[op].hasType != 0;
|
|
}
|
|
|
|
static int smolv_OpDeltaFromResult(SpvOp op, int opsCount)
|
|
{
|
|
if (op < 0 || op >= opsCount)
|
|
return 0;
|
|
return kSpirvOpData[op].deltaFromResult;
|
|
}
|
|
|
|
static bool smolv_OpVarRest(SpvOp op, int opsCount)
|
|
{
|
|
if (op < 0 || op >= opsCount)
|
|
return false;
|
|
return kSpirvOpData[op].varrest != 0;
|
|
}
|
|
|
|
static bool smolv_OpDebugInfo(SpvOp op, int opsCount)
|
|
{
|
|
return
|
|
op == SpvOpSourceContinued ||
|
|
op == SpvOpSource ||
|
|
op == SpvOpSourceExtension ||
|
|
op == SpvOpName ||
|
|
op == SpvOpMemberName ||
|
|
op == SpvOpString ||
|
|
op == SpvOpLine ||
|
|
op == SpvOpNoLine ||
|
|
op == SpvOpModuleProcessed;
|
|
}
|
|
|
|
|
|
static int smolv_DecorationExtraOps(int dec)
|
|
{
|
|
if (dec == 0 || (dec >= 2 && dec <= 5)) // RelaxedPrecision, Block..ColMajor
|
|
return 0;
|
|
if (dec >= 29 && dec <= 37) // Stream..XfbStride
|
|
return 1;
|
|
return -1; // unknown, encode length
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
|
|
static bool smolv_CheckGenericHeader(const uint32_t* words, size_t wordCount, uint32_t expectedMagic, uint32_t versionMask)
|
|
{
|
|
if (!words)
|
|
return false;
|
|
if (wordCount < 5)
|
|
return false;
|
|
|
|
uint32_t headerMagic = words[0];
|
|
if (headerMagic != expectedMagic)
|
|
return false;
|
|
uint32_t headerVersion = words[1] & versionMask;
|
|
if (headerVersion < 0x00010000 || headerVersion > 0x00010500)
|
|
return false; // only support 1.0 through 1.5
|
|
|
|
return true;
|
|
}
|
|
|
|
static const int kSpirVHeaderMagic = 0x07230203;
|
|
static const int kSmolHeaderMagic = 0x534D4F4C; // "SMOL"
|
|
|
|
static const int kSmolCurrEncodingVersion = 1;
|
|
|
|
static bool smolv_CheckSpirVHeader(const uint32_t* words, size_t wordCount)
|
|
{
|
|
//@TODO: if SPIR-V header magic was reversed, that means the file got written
|
|
// in a "big endian" order. Need to byteswap all words then.
|
|
return smolv_CheckGenericHeader(words, wordCount, kSpirVHeaderMagic, 0xFFFFFFFF);
|
|
}
|
|
static bool smolv_CheckSmolHeader(const uint8_t* bytes, size_t byteCount)
|
|
{
|
|
if (!smolv_CheckGenericHeader((const uint32_t*)bytes, byteCount/4, kSmolHeaderMagic, 0x00FFFFFF))
|
|
return false;
|
|
if (byteCount < 24) // one more word past header to store decoded length
|
|
return false;
|
|
// SMOL-V version
|
|
int smolVersion = ((const uint32_t*)bytes)[1] >> 24;
|
|
if (smolVersion < 0 || smolVersion > kSmolCurrEncodingVersion)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
static void smolv_Write4(smolv::ByteArray& arr, uint32_t v)
|
|
{
|
|
arr.push_back(v & 0xFF);
|
|
arr.push_back((v >> 8) & 0xFF);
|
|
arr.push_back((v >> 16) & 0xFF);
|
|
arr.push_back(v >> 24);
|
|
}
|
|
|
|
static void smolv_Write4(uint8_t*& buf, uint32_t v)
|
|
{
|
|
memcpy(buf, &v, 4);
|
|
buf += 4;
|
|
}
|
|
|
|
|
|
static bool smolv_Read4(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outv)
|
|
{
|
|
if (data + 4 > dataEnd)
|
|
return false;
|
|
outv = (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
|
data += 4;
|
|
return true;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
// 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)
|
|
{
|
|
while (v > 127)
|
|
{
|
|
arr.push_back((v & 127) | 128);
|
|
v >>= 7;
|
|
}
|
|
arr.push_back(v & 127);
|
|
}
|
|
|
|
static bool smolv_ReadVarint(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outVal)
|
|
{
|
|
uint32_t v = 0;
|
|
uint32_t shift = 0;
|
|
while (data < dataEnd)
|
|
{
|
|
uint8_t b = *data;
|
|
v |= (b & 127) << shift;
|
|
shift += 7;
|
|
data++;
|
|
if (!(b & 128))
|
|
break;
|
|
}
|
|
outVal = v;
|
|
return true; //@TODO: report failures
|
|
}
|
|
|
|
static uint32_t smolv_ZigEncode(int32_t i)
|
|
{
|
|
return (uint32_t(i) << 1) ^ (i >> 31);
|
|
}
|
|
|
|
static int32_t smolv_ZigDecode(uint32_t u)
|
|
{
|
|
return (u & 1) ? ((u >> 1) ^ ~0) : (u >> 1);
|
|
}
|
|
|
|
|
|
// 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)
|
|
{
|
|
# define _SMOLV_SWAP_OP(op1,op2) if (op==op1) return op2; if (op==op2) return op1
|
|
_SMOLV_SWAP_OP(SpvOpDecorate,SpvOpNop); // 0: 24%
|
|
_SMOLV_SWAP_OP(SpvOpLoad,SpvOpUndef); // 1: 17%
|
|
_SMOLV_SWAP_OP(SpvOpStore,SpvOpSourceContinued); // 2: 9%
|
|
_SMOLV_SWAP_OP(SpvOpAccessChain,SpvOpSource); // 3: 7.2%
|
|
_SMOLV_SWAP_OP(SpvOpVectorShuffle,SpvOpSourceExtension); // 4: 5.0%
|
|
// Name - already small enum value - 5: 4.4%
|
|
// MemberName - already small enum value - 6: 2.9%
|
|
_SMOLV_SWAP_OP(SpvOpMemberDecorate,SpvOpString); // 7: 4.0%
|
|
_SMOLV_SWAP_OP(SpvOpLabel,SpvOpLine); // 8: 0.9%
|
|
_SMOLV_SWAP_OP(SpvOpVariable,(SpvOp)9); // 9: 3.9%
|
|
_SMOLV_SWAP_OP(SpvOpFMul,SpvOpExtension); // 10: 3.9%
|
|
_SMOLV_SWAP_OP(SpvOpFAdd,SpvOpExtInstImport); // 11: 2.5%
|
|
// ExtInst - already small enum value - 12: 1.2%
|
|
// VectorShuffleCompact - already small enum value - used for compact shuffle encoding
|
|
_SMOLV_SWAP_OP(SpvOpTypePointer,SpvOpMemoryModel); // 14: 2.2%
|
|
_SMOLV_SWAP_OP(SpvOpFNegate,SpvOpEntryPoint); // 15: 1.1%
|
|
# undef _SMOLV_SWAP_OP
|
|
return 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)
|
|
{
|
|
len--;
|
|
if (op == SpvOpVectorShuffle) len -= 4;
|
|
if (op == SpvOpVectorShuffleCompact) len -= 4;
|
|
if (op == SpvOpDecorate) len -= 2;
|
|
if (op == SpvOpLoad) len -= 3;
|
|
if (op == SpvOpAccessChain) len -= 3;
|
|
return len;
|
|
}
|
|
|
|
static uint32_t smolv_DecodeLen(SpvOp op, uint32_t len)
|
|
{
|
|
len++;
|
|
if (op == SpvOpVectorShuffle) len += 4;
|
|
if (op == SpvOpVectorShuffleCompact) len += 4;
|
|
if (op == SpvOpDecorate) len += 2;
|
|
if (op == SpvOpLoad) len += 3;
|
|
if (op == SpvOpAccessChain) len += 3;
|
|
return 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)
|
|
{
|
|
len = smolv_EncodeLen(op, len);
|
|
// SPIR-V length field is 16 bits; if we get a larger value that means something
|
|
// was wrong, e.g. a vector shuffle instruction with less than 4 words (and our
|
|
// adjustment to common lengths in smolv_EncodeLen wrapped around)
|
|
if (len > 0xFFFF)
|
|
return false;
|
|
op = smolv_RemapOp(op);
|
|
uint32_t oplen = ((len >> 4) << 20) | ((op >> 4) << 8) | ((len & 0xF) << 4) | (op & 0xF);
|
|
smolv_WriteVarint(arr, oplen);
|
|
return true;
|
|
}
|
|
|
|
static bool smolv_ReadLengthOp(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outLen, SpvOp& outOp)
|
|
{
|
|
uint32_t val;
|
|
if (!smolv_ReadVarint(data, dataEnd, val))
|
|
return false;
|
|
outLen = ((val >> 20) << 4) | ((val >> 4) & 0xF);
|
|
outOp = (SpvOp)(((val >> 4) & 0xFFF0) | (val & 0xF));
|
|
|
|
outOp = smolv_RemapOp(outOp);
|
|
outLen = smolv_DecodeLen(outOp, outLen);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
#define _SMOLV_READ_OP(len, words, op) \
|
|
uint32_t len = words[0] >> 16; \
|
|
if (len < 1) return false; /* malformed instruction, length needs to be at least 1 */ \
|
|
if (words + len > wordsEnd) return false; /* malformed instruction, goes past end of data */ \
|
|
SpvOp op = (SpvOp)(words[0] & 0xFFFF)
|
|
|
|
|
|
bool smolv::Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags, StripOpNameFilterFunc stripFilter)
|
|
{
|
|
const size_t wordCount = spirvSize / 4;
|
|
if (wordCount * 4 != spirvSize)
|
|
return false;
|
|
const uint32_t* words = (const uint32_t*)spirvData;
|
|
const uint32_t* wordsEnd = words + wordCount;
|
|
if (!smolv_CheckSpirVHeader(words, wordCount))
|
|
return false;
|
|
|
|
// reserve space in output (typical compression is to about 30%; reserve half of input space)
|
|
outSmolv.reserve(outSmolv.size() + spirvSize/2);
|
|
|
|
// header (matches SPIR-V one, except different magic)
|
|
smolv_Write4(outSmolv, kSmolHeaderMagic);
|
|
smolv_Write4(outSmolv, (words[1] & 0x00FFFFFF) + (kSmolCurrEncodingVersion<<24)); // SPIR-V version (_XXX) + SMOL-V version (X___)
|
|
smolv_Write4(outSmolv, words[2]); // generator
|
|
smolv_Write4(outSmolv, words[3]); // bound
|
|
smolv_Write4(outSmolv, words[4]); // schema
|
|
|
|
const size_t headerSpirvSizeOffset = outSmolv.size(); // size field may get updated later if stripping is enabled
|
|
smolv_Write4(outSmolv, (uint32_t)spirvSize); // space needed to decode (i.e. original SPIR-V size)
|
|
|
|
size_t strippedSpirvWordCount = wordCount;
|
|
uint32_t prevResult = 0;
|
|
uint32_t prevDecorate = 0;
|
|
|
|
const int knownOpsCount = smolv_GetKnownOpsCount(kSmolCurrEncodingVersion);
|
|
|
|
words += 5;
|
|
while (words < wordsEnd)
|
|
{
|
|
_SMOLV_READ_OP(instrLen, words, op);
|
|
|
|
if ((flags & kEncodeFlagStripDebugInfo) && smolv_OpDebugInfo(op, knownOpsCount))
|
|
{
|
|
if (!stripFilter || op != SpvOpName || !stripFilter(reinterpret_cast<const char*>(&words[2])))
|
|
{
|
|
strippedSpirvWordCount -= instrLen;
|
|
words += instrLen;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// A usual case of vector shuffle, with less than 4 components, each with a value
|
|
// in [0..3] range: encode it in a more compact form, with the swizzle pattern in one byte.
|
|
// Turn this into a VectorShuffleCompact instruction, that takes up unused slot in Ops.
|
|
uint32_t swizzle = 0;
|
|
if (op == SpvOpVectorShuffle && instrLen <= 9)
|
|
{
|
|
uint32_t swz0 = instrLen > 5 ? words[5] : 0;
|
|
uint32_t swz1 = instrLen > 6 ? words[6] : 0;
|
|
uint32_t swz2 = instrLen > 7 ? words[7] : 0;
|
|
uint32_t swz3 = instrLen > 8 ? words[8] : 0;
|
|
if (swz0 < 4 && swz1 < 4 && swz2 < 4 && swz3 < 4)
|
|
{
|
|
op = SpvOpVectorShuffleCompact;
|
|
swizzle = (swz0 << 6) | (swz1 << 4) | (swz2 << 2) | (swz3);
|
|
}
|
|
}
|
|
|
|
// length + opcode
|
|
if (!smolv_WriteLengthOp(outSmolv, instrLen, op))
|
|
return false;
|
|
|
|
size_t ioffs = 1;
|
|
// write type as varint, if we have it
|
|
if (smolv_OpHasType(op, knownOpsCount))
|
|
{
|
|
if (ioffs >= instrLen)
|
|
return false;
|
|
smolv_WriteVarint(outSmolv, words[ioffs]);
|
|
ioffs++;
|
|
}
|
|
// write result as delta+zig+varint, if we have it
|
|
if (smolv_OpHasResult(op, knownOpsCount))
|
|
{
|
|
if (ioffs >= instrLen)
|
|
return false;
|
|
uint32_t v = words[ioffs];
|
|
smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevResult)); // some deltas are negative, use zig
|
|
prevResult = v;
|
|
ioffs++;
|
|
}
|
|
|
|
// Decorate & MemberDecorate: IDs relative to previous decorate
|
|
if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
|
|
{
|
|
if (ioffs >= instrLen)
|
|
return false;
|
|
uint32_t v = words[ioffs];
|
|
smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevDecorate)); // spirv-remapped deltas often negative, use zig
|
|
prevDecorate = v;
|
|
ioffs++;
|
|
}
|
|
|
|
// MemberDecorate special encoding: whole row of MemberDecorate instructions is often referring
|
|
// to the same type and linearly increasing member indices. Scan ahead to see how many we have,
|
|
// and encode whole bunch as one.
|
|
if (op == SpvOpMemberDecorate)
|
|
{
|
|
// scan ahead until we reach end, non-member-decoration or different type
|
|
const uint32_t decorationType = words[ioffs-1];
|
|
const uint32_t* memberWords = words;
|
|
uint32_t prevIndex = 0;
|
|
uint32_t prevOffset = 0;
|
|
// write a byte on how many we have encoded as a bunch
|
|
size_t countLocation = outSmolv.size();
|
|
outSmolv.push_back(0);
|
|
int count = 0;
|
|
while (memberWords < wordsEnd && count < 255)
|
|
{
|
|
_SMOLV_READ_OP(memberLen, memberWords, memberOp);
|
|
if (memberOp != SpvOpMemberDecorate)
|
|
break;
|
|
if (memberLen < 4)
|
|
return false; // invalid input
|
|
if (memberWords[1] != decorationType)
|
|
break;
|
|
|
|
// write member index as delta from previous
|
|
uint32_t memberIndex = memberWords[2];
|
|
smolv_WriteVarint(outSmolv, memberIndex - prevIndex);
|
|
prevIndex = memberIndex;
|
|
|
|
// decoration (and length if not common/known)
|
|
uint32_t memberDec = memberWords[3];
|
|
smolv_WriteVarint(outSmolv, memberDec);
|
|
const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
|
|
if (knownExtraOps == -1)
|
|
smolv_WriteVarint(outSmolv, memberLen-4);
|
|
else if (unsigned(knownExtraOps) + 4 != memberLen)
|
|
return false; // invalid input
|
|
|
|
// Offset decorations are most often linearly increasing, so encode as deltas
|
|
if (memberDec == 35) // Offset
|
|
{
|
|
if (memberLen != 5)
|
|
return false;
|
|
smolv_WriteVarint(outSmolv, memberWords[4]-prevOffset);
|
|
prevOffset = memberWords[4];
|
|
}
|
|
else
|
|
{
|
|
// write rest of decorations as varint
|
|
for (uint32_t i = 4; i < memberLen; ++i)
|
|
smolv_WriteVarint(outSmolv, memberWords[i]);
|
|
}
|
|
|
|
memberWords += memberLen;
|
|
++count;
|
|
}
|
|
outSmolv[countLocation] = uint8_t(count);
|
|
words = memberWords;
|
|
continue;
|
|
}
|
|
|
|
// Write out this many IDs, encoding them relative+zigzag to result ID
|
|
int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
|
|
for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
|
|
{
|
|
if (ioffs >= instrLen)
|
|
return false;
|
|
uint32_t delta = prevResult - words[ioffs];
|
|
// some deltas are negative (often on branches, or if program was processed by spirv-remap),
|
|
// so use zig encoding
|
|
smolv_WriteVarint(outSmolv, smolv_ZigEncode(delta));
|
|
}
|
|
|
|
if (op == SpvOpVectorShuffleCompact)
|
|
{
|
|
// compact vector shuffle, just write out single swizzle byte
|
|
outSmolv.push_back(uint8_t(swizzle));
|
|
ioffs = instrLen;
|
|
}
|
|
else if (smolv_OpVarRest(op, knownOpsCount))
|
|
{
|
|
// write out rest of words with variable encoding (expected to be small integers)
|
|
for (; ioffs < instrLen; ++ioffs)
|
|
smolv_WriteVarint(outSmolv, words[ioffs]);
|
|
}
|
|
else
|
|
{
|
|
// write out rest of words without any encoding
|
|
for (; ioffs < instrLen; ++ioffs)
|
|
smolv_Write4(outSmolv, words[ioffs]);
|
|
}
|
|
|
|
words += instrLen;
|
|
}
|
|
|
|
if (strippedSpirvWordCount != wordCount)
|
|
{
|
|
uint8_t* headerSpirvSize = &outSmolv[headerSpirvSizeOffset];
|
|
smolv_Write4(headerSpirvSize, (uint32_t)strippedSpirvWordCount * 4);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
size_t smolv::GetDecodedBufferSize(const void* smolvData, size_t smolvSize)
|
|
{
|
|
if (!smolv_CheckSmolHeader((const uint8_t*)smolvData, smolvSize))
|
|
return 0;
|
|
const uint32_t* words = (const uint32_t*)smolvData;
|
|
return words[5];
|
|
}
|
|
|
|
|
|
bool smolv::Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags)
|
|
{
|
|
// check header, and whether we have enough output buffer space
|
|
const size_t neededBufferSize = GetDecodedBufferSize(smolvData, smolvSize);
|
|
if (neededBufferSize == 0)
|
|
return false; // invalid SMOL-V
|
|
if (spirvOutputBufferSize < neededBufferSize)
|
|
return false; // not enough space in output buffer
|
|
if (spirvOutputBuffer == NULL)
|
|
return false; // output buffer is null
|
|
|
|
const uint8_t* bytes = (const uint8_t*)smolvData;
|
|
const uint8_t* bytesEnd = bytes + smolvSize;
|
|
|
|
uint8_t* outSpirv = (uint8_t*)spirvOutputBuffer;
|
|
|
|
uint32_t val;
|
|
int smolVersion = 0;
|
|
|
|
// header
|
|
smolv_Write4(outSpirv, kSpirVHeaderMagic); bytes += 4;
|
|
smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24; val &= 0x00FFFFFF; smolv_Write4(outSpirv, val); // version
|
|
smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // generator
|
|
smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // bound
|
|
smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // schema
|
|
bytes += 4; // decode buffer size
|
|
|
|
// there are two SMOL-V encoding versions, both not indicating anything in their header version field:
|
|
// one that is called "before zero" here (2016-08-31 code). Support decoding that one only by presence
|
|
// of this special flag.
|
|
const bool beforeZeroVersion = smolVersion == 0 && (flags & kDecodeFlagUse20160831AsZeroVersion) != 0;
|
|
|
|
const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion);
|
|
|
|
uint32_t prevResult = 0;
|
|
uint32_t prevDecorate = 0;
|
|
|
|
while (bytes < bytesEnd)
|
|
{
|
|
// read length + opcode
|
|
uint32_t instrLen;
|
|
SpvOp op;
|
|
if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op))
|
|
return false;
|
|
const bool wasSwizzle = (op == SpvOpVectorShuffleCompact);
|
|
if (wasSwizzle)
|
|
op = SpvOpVectorShuffle;
|
|
smolv_Write4(outSpirv, (instrLen << 16) | op);
|
|
|
|
size_t ioffs = 1;
|
|
|
|
// read type as varint, if we have it
|
|
if (smolv_OpHasType(op, knownOpsCount))
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
smolv_Write4(outSpirv, val);
|
|
ioffs++;
|
|
}
|
|
// read result as delta+varint, if we have it
|
|
if (smolv_OpHasResult(op, knownOpsCount))
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
val = prevResult + smolv_ZigDecode(val);
|
|
smolv_Write4(outSpirv, val);
|
|
prevResult = val;
|
|
ioffs++;
|
|
}
|
|
|
|
// Decorate: IDs relative to previous decorate
|
|
if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
// "before zero" version did not use zig encoding for the value
|
|
val = prevDecorate + (beforeZeroVersion ? val : smolv_ZigDecode(val));
|
|
smolv_Write4(outSpirv, val);
|
|
prevDecorate = val;
|
|
ioffs++;
|
|
}
|
|
|
|
// MemberDecorate special decoding
|
|
if (op == SpvOpMemberDecorate && !beforeZeroVersion)
|
|
{
|
|
if (bytes >= bytesEnd)
|
|
return false; // broken input
|
|
int count = *bytes++;
|
|
int prevIndex = 0;
|
|
int prevOffset = 0;
|
|
for (int m = 0; m < count; ++m)
|
|
{
|
|
// read member index
|
|
uint32_t memberIndex;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false;
|
|
memberIndex += prevIndex;
|
|
prevIndex = memberIndex;
|
|
|
|
// decoration (and length if not common/known)
|
|
uint32_t memberDec;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false;
|
|
const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
|
|
uint32_t memberLen;
|
|
if (knownExtraOps == -1)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false;
|
|
memberLen += 4;
|
|
}
|
|
else
|
|
memberLen = 4 + knownExtraOps;
|
|
|
|
// write SPIR-V op+length (unless it's first member decoration, in which case it was written before)
|
|
if (m != 0)
|
|
{
|
|
smolv_Write4(outSpirv, (memberLen << 16) | op);
|
|
smolv_Write4(outSpirv, prevDecorate);
|
|
}
|
|
smolv_Write4(outSpirv, memberIndex);
|
|
smolv_Write4(outSpirv, memberDec);
|
|
// Special case for Offset decorations
|
|
if (memberDec == 35) // Offset
|
|
{
|
|
if (memberLen != 5)
|
|
return false;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
val += prevOffset;
|
|
smolv_Write4(outSpirv, val);
|
|
prevOffset = val;
|
|
}
|
|
else
|
|
{
|
|
for (uint32_t i = 4; i < memberLen; ++i)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
smolv_Write4(outSpirv, val);
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Read this many IDs, that are relative to result ID
|
|
int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
|
|
// "before zero" version only used zig encoding for IDs of several ops; after
|
|
// that ops got zig encoding for their IDs
|
|
bool zigDecodeVals = true;
|
|
if (beforeZeroVersion)
|
|
{
|
|
if (op != SpvOpControlBarrier && op != SpvOpMemoryBarrier && op != SpvOpLoopMerge && op != SpvOpSelectionMerge && op != SpvOpBranch && op != SpvOpBranchConditional && op != SpvOpMemoryNamedBarrier)
|
|
zigDecodeVals = false;
|
|
}
|
|
for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
if (zigDecodeVals)
|
|
val = smolv_ZigDecode(val);
|
|
smolv_Write4(outSpirv, prevResult - val);
|
|
}
|
|
|
|
if (wasSwizzle && instrLen <= 9)
|
|
{
|
|
uint32_t swizzle = *bytes++;
|
|
if (instrLen > 5) smolv_Write4(outSpirv, (swizzle >> 6) & 3);
|
|
if (instrLen > 6) smolv_Write4(outSpirv, (swizzle >> 4) & 3);
|
|
if (instrLen > 7) smolv_Write4(outSpirv, (swizzle >> 2) & 3);
|
|
if (instrLen > 8) smolv_Write4(outSpirv, swizzle & 3);
|
|
}
|
|
else if (smolv_OpVarRest(op, knownOpsCount))
|
|
{
|
|
// read rest of words with variable encoding
|
|
for (; ioffs < instrLen; ++ioffs)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
smolv_Write4(outSpirv, val);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// read rest of words without any encoding
|
|
for (; ioffs < instrLen; ++ioffs)
|
|
{
|
|
if (!smolv_Read4(bytes, bytesEnd, val)) return false;
|
|
smolv_Write4(outSpirv, val);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((uint8_t*)spirvOutputBuffer + neededBufferSize != outSpirv)
|
|
return false; // something went wrong during decoding? we should have decoded to exact output size
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
// Calculating instruction count / space stats on SPIR-V and SMOL-V
|
|
|
|
|
|
struct smolv::Stats
|
|
{
|
|
Stats() { memset(this, 0, sizeof(*this)); }
|
|
size_t opCounts[kKnownOpsCount];
|
|
size_t opSizes[kKnownOpsCount];
|
|
size_t smolOpSizes[kKnownOpsCount];
|
|
size_t varintCountsOp[6];
|
|
size_t varintCountsType[6];
|
|
size_t varintCountsRes[6];
|
|
size_t varintCountsOther[6];
|
|
size_t totalOps;
|
|
size_t totalSize;
|
|
size_t totalSizeSmol;
|
|
size_t inputCount;
|
|
};
|
|
|
|
|
|
smolv::Stats* smolv::StatsCreate()
|
|
{
|
|
return new Stats();
|
|
}
|
|
|
|
void smolv::StatsDelete(smolv::Stats *s)
|
|
{
|
|
delete s;
|
|
}
|
|
|
|
|
|
bool smolv::StatsCalculate(smolv::Stats* stats, const void* spirvData, size_t spirvSize)
|
|
{
|
|
if (!stats)
|
|
return false;
|
|
|
|
const size_t wordCount = spirvSize / 4;
|
|
if (wordCount * 4 != spirvSize)
|
|
return false;
|
|
const uint32_t* words = (const uint32_t*)spirvData;
|
|
const uint32_t* wordsEnd = words + wordCount;
|
|
if (!smolv_CheckSpirVHeader(words, wordCount))
|
|
return false;
|
|
words += 5;
|
|
|
|
stats->inputCount++;
|
|
stats->totalSize += wordCount;
|
|
|
|
while (words < wordsEnd)
|
|
{
|
|
_SMOLV_READ_OP(instrLen, words, op);
|
|
|
|
if (op < kKnownOpsCount)
|
|
{
|
|
stats->opCounts[op]++;
|
|
stats->opSizes[op] += instrLen;
|
|
}
|
|
words += instrLen;
|
|
stats->totalOps++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool smolv::StatsCalculateSmol(smolv::Stats* stats, const void* smolvData, size_t smolvSize)
|
|
{
|
|
if (!stats)
|
|
return false;
|
|
|
|
// debugging helper to dump all encoded bytes to stdout, keep at "if 0"
|
|
# if 0
|
|
# define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() { \
|
|
printf("Op %-22s ", op < kKnownOpsCount ? kSpirvOpNames[op] : "???"); \
|
|
for (const uint8_t* b = instrBegin; b < bytes; ++b) \
|
|
printf("%02x ", *b); \
|
|
printf("\n"); \
|
|
}
|
|
# else
|
|
# define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() {}
|
|
# endif
|
|
|
|
const uint8_t* bytes = (const uint8_t*)smolvData;
|
|
const uint8_t* bytesEnd = bytes + smolvSize;
|
|
if (!smolv_CheckSmolHeader(bytes, smolvSize))
|
|
return false;
|
|
|
|
uint32_t val;
|
|
int smolVersion;
|
|
bytes += 4;
|
|
smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24;
|
|
const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion);
|
|
bytes += 16;
|
|
|
|
stats->totalSizeSmol += smolvSize;
|
|
|
|
while (bytes < bytesEnd)
|
|
{
|
|
const uint8_t* instrBegin = bytes;
|
|
const uint8_t* varBegin;
|
|
|
|
// read length + opcode
|
|
uint32_t instrLen;
|
|
SpvOp op;
|
|
varBegin = bytes;
|
|
if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op))
|
|
return false;
|
|
const bool wasSwizzle = (op == SpvOpVectorShuffleCompact);
|
|
if (wasSwizzle)
|
|
op = SpvOpVectorShuffle;
|
|
stats->varintCountsOp[bytes-varBegin]++;
|
|
|
|
size_t ioffs = 1;
|
|
if (smolv_OpHasType(op, knownOpsCount))
|
|
{
|
|
varBegin = bytes;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
stats->varintCountsType[bytes-varBegin]++;
|
|
ioffs++;
|
|
}
|
|
if (smolv_OpHasResult(op, knownOpsCount))
|
|
{
|
|
varBegin = bytes;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
stats->varintCountsRes[bytes-varBegin]++;
|
|
ioffs++;
|
|
}
|
|
|
|
if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
ioffs++;
|
|
}
|
|
// MemberDecorate special decoding
|
|
if (op == SpvOpMemberDecorate)
|
|
{
|
|
if (bytes >= bytesEnd)
|
|
return false; // broken input
|
|
int count = *bytes++;
|
|
for (int m = 0; m < count; ++m)
|
|
{
|
|
uint32_t memberIndex;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false;
|
|
uint32_t memberDec;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false;
|
|
const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
|
|
uint32_t memberLen;
|
|
if (knownExtraOps == -1)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false;
|
|
memberLen += 4;
|
|
}
|
|
else
|
|
memberLen = 4 + knownExtraOps;
|
|
for (uint32_t i = 4; i < memberLen; ++i)
|
|
{
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
}
|
|
}
|
|
stats->smolOpSizes[op] += bytes - instrBegin;
|
|
_SMOLV_DEBUG_PRINT_ENCODED_BYTES();
|
|
continue;
|
|
}
|
|
|
|
int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
|
|
for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
|
|
{
|
|
varBegin = bytes;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
stats->varintCountsRes[bytes-varBegin]++;
|
|
}
|
|
|
|
if (wasSwizzle && instrLen <= 9)
|
|
{
|
|
bytes++;
|
|
}
|
|
else if (smolv_OpVarRest(op, knownOpsCount))
|
|
{
|
|
for (; ioffs < instrLen; ++ioffs)
|
|
{
|
|
varBegin = bytes;
|
|
if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
|
|
stats->varintCountsOther[bytes-varBegin]++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (; ioffs < instrLen; ++ioffs)
|
|
{
|
|
if (!smolv_Read4(bytes, bytesEnd, val)) return false;
|
|
}
|
|
}
|
|
|
|
if (op < kKnownOpsCount)
|
|
{
|
|
stats->smolOpSizes[op] += bytes - instrBegin;
|
|
}
|
|
_SMOLV_DEBUG_PRINT_ENCODED_BYTES();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool CompareOpCounters (std::pair<SpvOp,size_t> a, std::pair<SpvOp,size_t> b)
|
|
{
|
|
return a.second > b.second;
|
|
}
|
|
|
|
void smolv::StatsPrint(const Stats* stats)
|
|
{
|
|
if (!stats)
|
|
return;
|
|
|
|
typedef std::pair<SpvOp,size_t> OpCounter;
|
|
OpCounter counts[kKnownOpsCount];
|
|
OpCounter sizes[kKnownOpsCount];
|
|
OpCounter sizesSmol[kKnownOpsCount];
|
|
for (int i = 0; i < kKnownOpsCount; ++i)
|
|
{
|
|
counts[i].first = (SpvOp)i;
|
|
counts[i].second = stats->opCounts[i];
|
|
sizes[i].first = (SpvOp)i;
|
|
sizes[i].second = stats->opSizes[i];
|
|
sizesSmol[i].first = (SpvOp)i;
|
|
sizesSmol[i].second = stats->smolOpSizes[i];
|
|
}
|
|
std::sort(counts, counts + kKnownOpsCount, CompareOpCounters);
|
|
std::sort(sizes, sizes + kKnownOpsCount, CompareOpCounters);
|
|
std::sort(sizesSmol, sizesSmol + kKnownOpsCount, CompareOpCounters);
|
|
|
|
printf("Stats for %i SPIR-V inputs, total size %i words (%.1fKB):\n", (int)stats->inputCount, (int)stats->totalSize, stats->totalSize * 4.0f / 1024.0f);
|
|
printf("Most occuring ops:\n");
|
|
for (int i = 0; i < 30; ++i)
|
|
{
|
|
SpvOp op = counts[i].first;
|
|
printf(" #%2i: %4i %-20s %4i (%4.1f%%)\n", i, op, kSpirvOpNames[op], (int)counts[i].second, (float)counts[i].second / (float)stats->totalOps * 100.0f);
|
|
}
|
|
printf("Largest total size of ops:\n");
|
|
for (int i = 0; i < 30; ++i)
|
|
{
|
|
SpvOp op = sizes[i].first;
|
|
printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n",
|
|
i,
|
|
kSpirvOpNames[op],
|
|
(int)sizes[i].second*4,
|
|
(float)sizes[i].second / (float)stats->totalSize * 100.0f,
|
|
(float)sizes[i].second*4 / (float)stats->opCounts[op]
|
|
);
|
|
}
|
|
printf("SMOL varint encoding counts per byte length:\n");
|
|
printf(" B: %6s %6s %6s %6s\n", "Op", "Type", "Result", "Other");
|
|
for (int i = 1; i < 6; ++i)
|
|
{
|
|
printf(" %i: %6i %6i %6i %6i\n", i, (int)stats->varintCountsOp[i], (int)stats->varintCountsType[i], (int)stats->varintCountsRes[i], (int)stats->varintCountsOther[i]);
|
|
}
|
|
printf("Largest total size of ops in SMOL:\n");
|
|
for (int i = 0; i < 30; ++i)
|
|
{
|
|
SpvOp op = sizesSmol[i].first;
|
|
printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n",
|
|
i,
|
|
kSpirvOpNames[op],
|
|
(int)sizesSmol[i].second,
|
|
(float)sizesSmol[i].second / (float)stats->totalSizeSmol * 100.0f,
|
|
(float)sizesSmol[i].second / (float)stats->opCounts[op]
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// 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.
|
|
// ------------------------------------------------------------------------------
|