| 1 | // smol-v - public domain - https://github.com/aras-p/smol-v |
| 2 | // authored 2016-2020 by Aras Pranckevicius |
| 3 | // no warranty implied; use at your own risk |
| 4 | // See end of file for license information. |
| 5 | |
| 6 | #include "smolv.h" |
| 7 | #include <stdint.h> |
| 8 | #include <vector> |
| 9 | #include <algorithm> |
| 10 | #include <cstdio> |
| 11 | #include <cstring> |
| 12 | |
| 13 | #if !defined(_MSC_VER) && __cplusplus < 201103L |
| 14 | #define static_assert(x,y) |
| 15 | #endif |
| 16 | |
| 17 | #define _SMOLV_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) |
| 18 | |
| 19 | // -------------------------------------------------------------------------------------------- |
| 20 | // Metadata about known SPIR-V operations |
| 21 | |
| 22 | enum SpvOp |
| 23 | { |
| 24 | SpvOpNop = 0, |
| 25 | SpvOpUndef = 1, |
| 26 | SpvOpSourceContinued = 2, |
| 27 | SpvOpSource = 3, |
| 28 | SpvOpSourceExtension = 4, |
| 29 | SpvOpName = 5, |
| 30 | SpvOpMemberName = 6, |
| 31 | SpvOpString = 7, |
| 32 | SpvOpLine = 8, |
| 33 | SpvOpExtension = 10, |
| 34 | SpvOpExtInstImport = 11, |
| 35 | SpvOpExtInst = 12, |
| 36 | SpvOpVectorShuffleCompact = 13, // not in SPIR-V, added for SMOL-V! |
| 37 | SpvOpMemoryModel = 14, |
| 38 | SpvOpEntryPoint = 15, |
| 39 | SpvOpExecutionMode = 16, |
| 40 | SpvOpCapability = 17, |
| 41 | SpvOpTypeVoid = 19, |
| 42 | SpvOpTypeBool = 20, |
| 43 | SpvOpTypeInt = 21, |
| 44 | SpvOpTypeFloat = 22, |
| 45 | SpvOpTypeVector = 23, |
| 46 | SpvOpTypeMatrix = 24, |
| 47 | SpvOpTypeImage = 25, |
| 48 | SpvOpTypeSampler = 26, |
| 49 | SpvOpTypeSampledImage = 27, |
| 50 | SpvOpTypeArray = 28, |
| 51 | SpvOpTypeRuntimeArray = 29, |
| 52 | SpvOpTypeStruct = 30, |
| 53 | SpvOpTypeOpaque = 31, |
| 54 | SpvOpTypePointer = 32, |
| 55 | SpvOpTypeFunction = 33, |
| 56 | SpvOpTypeEvent = 34, |
| 57 | SpvOpTypeDeviceEvent = 35, |
| 58 | SpvOpTypeReserveId = 36, |
| 59 | SpvOpTypeQueue = 37, |
| 60 | SpvOpTypePipe = 38, |
| 61 | SpvOpTypeForwardPointer = 39, |
| 62 | SpvOpConstantTrue = 41, |
| 63 | SpvOpConstantFalse = 42, |
| 64 | SpvOpConstant = 43, |
| 65 | SpvOpConstantComposite = 44, |
| 66 | SpvOpConstantSampler = 45, |
| 67 | SpvOpConstantNull = 46, |
| 68 | SpvOpSpecConstantTrue = 48, |
| 69 | SpvOpSpecConstantFalse = 49, |
| 70 | SpvOpSpecConstant = 50, |
| 71 | SpvOpSpecConstantComposite = 51, |
| 72 | SpvOpSpecConstantOp = 52, |
| 73 | SpvOpFunction = 54, |
| 74 | SpvOpFunctionParameter = 55, |
| 75 | SpvOpFunctionEnd = 56, |
| 76 | SpvOpFunctionCall = 57, |
| 77 | SpvOpVariable = 59, |
| 78 | SpvOpImageTexelPointer = 60, |
| 79 | SpvOpLoad = 61, |
| 80 | SpvOpStore = 62, |
| 81 | SpvOpCopyMemory = 63, |
| 82 | SpvOpCopyMemorySized = 64, |
| 83 | SpvOpAccessChain = 65, |
| 84 | SpvOpInBoundsAccessChain = 66, |
| 85 | SpvOpPtrAccessChain = 67, |
| 86 | SpvOpArrayLength = 68, |
| 87 | SpvOpGenericPtrMemSemantics = 69, |
| 88 | SpvOpInBoundsPtrAccessChain = 70, |
| 89 | SpvOpDecorate = 71, |
| 90 | SpvOpMemberDecorate = 72, |
| 91 | SpvOpDecorationGroup = 73, |
| 92 | SpvOpGroupDecorate = 74, |
| 93 | SpvOpGroupMemberDecorate = 75, |
| 94 | = 77, |
| 95 | SpvOpVectorInsertDynamic = 78, |
| 96 | SpvOpVectorShuffle = 79, |
| 97 | SpvOpCompositeConstruct = 80, |
| 98 | = 81, |
| 99 | SpvOpCompositeInsert = 82, |
| 100 | SpvOpCopyObject = 83, |
| 101 | SpvOpTranspose = 84, |
| 102 | SpvOpSampledImage = 86, |
| 103 | SpvOpImageSampleImplicitLod = 87, |
| 104 | SpvOpImageSampleExplicitLod = 88, |
| 105 | SpvOpImageSampleDrefImplicitLod = 89, |
| 106 | SpvOpImageSampleDrefExplicitLod = 90, |
| 107 | SpvOpImageSampleProjImplicitLod = 91, |
| 108 | SpvOpImageSampleProjExplicitLod = 92, |
| 109 | SpvOpImageSampleProjDrefImplicitLod = 93, |
| 110 | SpvOpImageSampleProjDrefExplicitLod = 94, |
| 111 | SpvOpImageFetch = 95, |
| 112 | SpvOpImageGather = 96, |
| 113 | SpvOpImageDrefGather = 97, |
| 114 | SpvOpImageRead = 98, |
| 115 | SpvOpImageWrite = 99, |
| 116 | SpvOpImage = 100, |
| 117 | SpvOpImageQueryFormat = 101, |
| 118 | SpvOpImageQueryOrder = 102, |
| 119 | SpvOpImageQuerySizeLod = 103, |
| 120 | SpvOpImageQuerySize = 104, |
| 121 | SpvOpImageQueryLod = 105, |
| 122 | SpvOpImageQueryLevels = 106, |
| 123 | SpvOpImageQuerySamples = 107, |
| 124 | SpvOpConvertFToU = 109, |
| 125 | SpvOpConvertFToS = 110, |
| 126 | SpvOpConvertSToF = 111, |
| 127 | SpvOpConvertUToF = 112, |
| 128 | SpvOpUConvert = 113, |
| 129 | SpvOpSConvert = 114, |
| 130 | SpvOpFConvert = 115, |
| 131 | SpvOpQuantizeToF16 = 116, |
| 132 | SpvOpConvertPtrToU = 117, |
| 133 | SpvOpSatConvertSToU = 118, |
| 134 | SpvOpSatConvertUToS = 119, |
| 135 | SpvOpConvertUToPtr = 120, |
| 136 | SpvOpPtrCastToGeneric = 121, |
| 137 | SpvOpGenericCastToPtr = 122, |
| 138 | SpvOpGenericCastToPtrExplicit = 123, |
| 139 | SpvOpBitcast = 124, |
| 140 | SpvOpSNegate = 126, |
| 141 | SpvOpFNegate = 127, |
| 142 | SpvOpIAdd = 128, |
| 143 | SpvOpFAdd = 129, |
| 144 | SpvOpISub = 130, |
| 145 | SpvOpFSub = 131, |
| 146 | SpvOpIMul = 132, |
| 147 | SpvOpFMul = 133, |
| 148 | SpvOpUDiv = 134, |
| 149 | SpvOpSDiv = 135, |
| 150 | SpvOpFDiv = 136, |
| 151 | SpvOpUMod = 137, |
| 152 | SpvOpSRem = 138, |
| 153 | SpvOpSMod = 139, |
| 154 | SpvOpFRem = 140, |
| 155 | SpvOpFMod = 141, |
| 156 | SpvOpVectorTimesScalar = 142, |
| 157 | SpvOpMatrixTimesScalar = 143, |
| 158 | SpvOpVectorTimesMatrix = 144, |
| 159 | SpvOpMatrixTimesVector = 145, |
| 160 | SpvOpMatrixTimesMatrix = 146, |
| 161 | SpvOpOuterProduct = 147, |
| 162 | SpvOpDot = 148, |
| 163 | SpvOpIAddCarry = 149, |
| 164 | SpvOpISubBorrow = 150, |
| 165 | SpvOpUMulExtended = 151, |
| 166 | SpvOpSMulExtended = 152, |
| 167 | SpvOpAny = 154, |
| 168 | SpvOpAll = 155, |
| 169 | SpvOpIsNan = 156, |
| 170 | SpvOpIsInf = 157, |
| 171 | SpvOpIsFinite = 158, |
| 172 | SpvOpIsNormal = 159, |
| 173 | SpvOpSignBitSet = 160, |
| 174 | SpvOpLessOrGreater = 161, |
| 175 | SpvOpOrdered = 162, |
| 176 | SpvOpUnordered = 163, |
| 177 | SpvOpLogicalEqual = 164, |
| 178 | SpvOpLogicalNotEqual = 165, |
| 179 | SpvOpLogicalOr = 166, |
| 180 | SpvOpLogicalAnd = 167, |
| 181 | SpvOpLogicalNot = 168, |
| 182 | SpvOpSelect = 169, |
| 183 | SpvOpIEqual = 170, |
| 184 | SpvOpINotEqual = 171, |
| 185 | SpvOpUGreaterThan = 172, |
| 186 | SpvOpSGreaterThan = 173, |
| 187 | SpvOpUGreaterThanEqual = 174, |
| 188 | SpvOpSGreaterThanEqual = 175, |
| 189 | SpvOpULessThan = 176, |
| 190 | SpvOpSLessThan = 177, |
| 191 | SpvOpULessThanEqual = 178, |
| 192 | SpvOpSLessThanEqual = 179, |
| 193 | SpvOpFOrdEqual = 180, |
| 194 | SpvOpFUnordEqual = 181, |
| 195 | SpvOpFOrdNotEqual = 182, |
| 196 | SpvOpFUnordNotEqual = 183, |
| 197 | SpvOpFOrdLessThan = 184, |
| 198 | SpvOpFUnordLessThan = 185, |
| 199 | SpvOpFOrdGreaterThan = 186, |
| 200 | SpvOpFUnordGreaterThan = 187, |
| 201 | SpvOpFOrdLessThanEqual = 188, |
| 202 | SpvOpFUnordLessThanEqual = 189, |
| 203 | SpvOpFOrdGreaterThanEqual = 190, |
| 204 | SpvOpFUnordGreaterThanEqual = 191, |
| 205 | SpvOpShiftRightLogical = 194, |
| 206 | SpvOpShiftRightArithmetic = 195, |
| 207 | SpvOpShiftLeftLogical = 196, |
| 208 | SpvOpBitwiseOr = 197, |
| 209 | SpvOpBitwiseXor = 198, |
| 210 | SpvOpBitwiseAnd = 199, |
| 211 | SpvOpNot = 200, |
| 212 | SpvOpBitFieldInsert = 201, |
| 213 | = 202, |
| 214 | = 203, |
| 215 | SpvOpBitReverse = 204, |
| 216 | SpvOpBitCount = 205, |
| 217 | SpvOpDPdx = 207, |
| 218 | SpvOpDPdy = 208, |
| 219 | SpvOpFwidth = 209, |
| 220 | SpvOpDPdxFine = 210, |
| 221 | SpvOpDPdyFine = 211, |
| 222 | SpvOpFwidthFine = 212, |
| 223 | SpvOpDPdxCoarse = 213, |
| 224 | SpvOpDPdyCoarse = 214, |
| 225 | SpvOpFwidthCoarse = 215, |
| 226 | SpvOpEmitVertex = 218, |
| 227 | SpvOpEndPrimitive = 219, |
| 228 | SpvOpEmitStreamVertex = 220, |
| 229 | SpvOpEndStreamPrimitive = 221, |
| 230 | SpvOpControlBarrier = 224, |
| 231 | SpvOpMemoryBarrier = 225, |
| 232 | SpvOpAtomicLoad = 227, |
| 233 | SpvOpAtomicStore = 228, |
| 234 | SpvOpAtomicExchange = 229, |
| 235 | SpvOpAtomicCompareExchange = 230, |
| 236 | SpvOpAtomicCompareExchangeWeak = 231, |
| 237 | SpvOpAtomicIIncrement = 232, |
| 238 | SpvOpAtomicIDecrement = 233, |
| 239 | SpvOpAtomicIAdd = 234, |
| 240 | SpvOpAtomicISub = 235, |
| 241 | SpvOpAtomicSMin = 236, |
| 242 | SpvOpAtomicUMin = 237, |
| 243 | SpvOpAtomicSMax = 238, |
| 244 | SpvOpAtomicUMax = 239, |
| 245 | SpvOpAtomicAnd = 240, |
| 246 | SpvOpAtomicOr = 241, |
| 247 | SpvOpAtomicXor = 242, |
| 248 | SpvOpPhi = 245, |
| 249 | SpvOpLoopMerge = 246, |
| 250 | SpvOpSelectionMerge = 247, |
| 251 | SpvOpLabel = 248, |
| 252 | SpvOpBranch = 249, |
| 253 | SpvOpBranchConditional = 250, |
| 254 | SpvOpSwitch = 251, |
| 255 | SpvOpKill = 252, |
| 256 | SpvOpReturn = 253, |
| 257 | SpvOpReturnValue = 254, |
| 258 | SpvOpUnreachable = 255, |
| 259 | SpvOpLifetimeStart = 256, |
| 260 | SpvOpLifetimeStop = 257, |
| 261 | SpvOpGroupAsyncCopy = 259, |
| 262 | SpvOpGroupWaitEvents = 260, |
| 263 | SpvOpGroupAll = 261, |
| 264 | SpvOpGroupAny = 262, |
| 265 | SpvOpGroupBroadcast = 263, |
| 266 | SpvOpGroupIAdd = 264, |
| 267 | SpvOpGroupFAdd = 265, |
| 268 | SpvOpGroupFMin = 266, |
| 269 | SpvOpGroupUMin = 267, |
| 270 | SpvOpGroupSMin = 268, |
| 271 | SpvOpGroupFMax = 269, |
| 272 | SpvOpGroupUMax = 270, |
| 273 | SpvOpGroupSMax = 271, |
| 274 | SpvOpReadPipe = 274, |
| 275 | SpvOpWritePipe = 275, |
| 276 | SpvOpReservedReadPipe = 276, |
| 277 | SpvOpReservedWritePipe = 277, |
| 278 | SpvOpReserveReadPipePackets = 278, |
| 279 | SpvOpReserveWritePipePackets = 279, |
| 280 | SpvOpCommitReadPipe = 280, |
| 281 | SpvOpCommitWritePipe = 281, |
| 282 | SpvOpIsValidReserveId = 282, |
| 283 | SpvOpGetNumPipePackets = 283, |
| 284 | SpvOpGetMaxPipePackets = 284, |
| 285 | SpvOpGroupReserveReadPipePackets = 285, |
| 286 | SpvOpGroupReserveWritePipePackets = 286, |
| 287 | SpvOpGroupCommitReadPipe = 287, |
| 288 | SpvOpGroupCommitWritePipe = 288, |
| 289 | SpvOpEnqueueMarker = 291, |
| 290 | SpvOpEnqueueKernel = 292, |
| 291 | SpvOpGetKernelNDrangeSubGroupCount = 293, |
| 292 | SpvOpGetKernelNDrangeMaxSubGroupSize = 294, |
| 293 | SpvOpGetKernelWorkGroupSize = 295, |
| 294 | SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296, |
| 295 | SpvOpRetainEvent = 297, |
| 296 | SpvOpReleaseEvent = 298, |
| 297 | SpvOpCreateUserEvent = 299, |
| 298 | SpvOpIsValidEvent = 300, |
| 299 | SpvOpSetUserEventStatus = 301, |
| 300 | SpvOpCaptureEventProfilingInfo = 302, |
| 301 | SpvOpGetDefaultQueue = 303, |
| 302 | SpvOpBuildNDRange = 304, |
| 303 | SpvOpImageSparseSampleImplicitLod = 305, |
| 304 | SpvOpImageSparseSampleExplicitLod = 306, |
| 305 | SpvOpImageSparseSampleDrefImplicitLod = 307, |
| 306 | SpvOpImageSparseSampleDrefExplicitLod = 308, |
| 307 | SpvOpImageSparseSampleProjImplicitLod = 309, |
| 308 | SpvOpImageSparseSampleProjExplicitLod = 310, |
| 309 | SpvOpImageSparseSampleProjDrefImplicitLod = 311, |
| 310 | SpvOpImageSparseSampleProjDrefExplicitLod = 312, |
| 311 | SpvOpImageSparseFetch = 313, |
| 312 | SpvOpImageSparseGather = 314, |
| 313 | SpvOpImageSparseDrefGather = 315, |
| 314 | SpvOpImageSparseTexelsResident = 316, |
| 315 | SpvOpNoLine = 317, |
| 316 | SpvOpAtomicFlagTestAndSet = 318, |
| 317 | SpvOpAtomicFlagClear = 319, |
| 318 | SpvOpImageSparseRead = 320, |
| 319 | SpvOpSizeOf = 321, |
| 320 | SpvOpTypePipeStorage = 322, |
| 321 | SpvOpConstantPipeStorage = 323, |
| 322 | SpvOpCreatePipeFromPipeStorage = 324, |
| 323 | SpvOpGetKernelLocalSizeForSubgroupCount = 325, |
| 324 | SpvOpGetKernelMaxNumSubgroups = 326, |
| 325 | SpvOpTypeNamedBarrier = 327, |
| 326 | SpvOpNamedBarrierInitialize = 328, |
| 327 | SpvOpMemoryNamedBarrier = 329, |
| 328 | SpvOpModuleProcessed = 330, |
| 329 | SpvOpExecutionModeId = 331, |
| 330 | SpvOpDecorateId = 332, |
| 331 | SpvOpGroupNonUniformElect = 333, |
| 332 | SpvOpGroupNonUniformAll = 334, |
| 333 | SpvOpGroupNonUniformAny = 335, |
| 334 | SpvOpGroupNonUniformAllEqual = 336, |
| 335 | SpvOpGroupNonUniformBroadcast = 337, |
| 336 | SpvOpGroupNonUniformBroadcastFirst = 338, |
| 337 | SpvOpGroupNonUniformBallot = 339, |
| 338 | SpvOpGroupNonUniformInverseBallot = 340, |
| 339 | = 341, |
| 340 | SpvOpGroupNonUniformBallotBitCount = 342, |
| 341 | SpvOpGroupNonUniformBallotFindLSB = 343, |
| 342 | SpvOpGroupNonUniformBallotFindMSB = 344, |
| 343 | SpvOpGroupNonUniformShuffle = 345, |
| 344 | SpvOpGroupNonUniformShuffleXor = 346, |
| 345 | SpvOpGroupNonUniformShuffleUp = 347, |
| 346 | SpvOpGroupNonUniformShuffleDown = 348, |
| 347 | SpvOpGroupNonUniformIAdd = 349, |
| 348 | SpvOpGroupNonUniformFAdd = 350, |
| 349 | SpvOpGroupNonUniformIMul = 351, |
| 350 | SpvOpGroupNonUniformFMul = 352, |
| 351 | SpvOpGroupNonUniformSMin = 353, |
| 352 | SpvOpGroupNonUniformUMin = 354, |
| 353 | SpvOpGroupNonUniformFMin = 355, |
| 354 | SpvOpGroupNonUniformSMax = 356, |
| 355 | SpvOpGroupNonUniformUMax = 357, |
| 356 | SpvOpGroupNonUniformFMax = 358, |
| 357 | SpvOpGroupNonUniformBitwiseAnd = 359, |
| 358 | SpvOpGroupNonUniformBitwiseOr = 360, |
| 359 | SpvOpGroupNonUniformBitwiseXor = 361, |
| 360 | SpvOpGroupNonUniformLogicalAnd = 362, |
| 361 | SpvOpGroupNonUniformLogicalOr = 363, |
| 362 | SpvOpGroupNonUniformLogicalXor = 364, |
| 363 | SpvOpGroupNonUniformQuadBroadcast = 365, |
| 364 | SpvOpGroupNonUniformQuadSwap = 366, |
| 365 | }; |
| 366 | static const int kKnownOpsCount = SpvOpGroupNonUniformQuadSwap+1; |
| 367 | |
| 368 | |
| 369 | static const char* kSpirvOpNames[] = |
| 370 | { |
| 371 | "Nop" , |
| 372 | "Undef" , |
| 373 | "SourceContinued" , |
| 374 | "Source" , |
| 375 | "SourceExtension" , |
| 376 | "Name" , |
| 377 | "MemberName" , |
| 378 | "String" , |
| 379 | "Line" , |
| 380 | "#9" , |
| 381 | "Extension" , |
| 382 | "ExtInstImport" , |
| 383 | "ExtInst" , |
| 384 | "VectorShuffleCompact" , |
| 385 | "MemoryModel" , |
| 386 | "EntryPoint" , |
| 387 | "ExecutionMode" , |
| 388 | "Capability" , |
| 389 | "#18" , |
| 390 | "TypeVoid" , |
| 391 | "TypeBool" , |
| 392 | "TypeInt" , |
| 393 | "TypeFloat" , |
| 394 | "TypeVector" , |
| 395 | "TypeMatrix" , |
| 396 | "TypeImage" , |
| 397 | "TypeSampler" , |
| 398 | "TypeSampledImage" , |
| 399 | "TypeArray" , |
| 400 | "TypeRuntimeArray" , |
| 401 | "TypeStruct" , |
| 402 | "TypeOpaque" , |
| 403 | "TypePointer" , |
| 404 | "TypeFunction" , |
| 405 | "TypeEvent" , |
| 406 | "TypeDeviceEvent" , |
| 407 | "TypeReserveId" , |
| 408 | "TypeQueue" , |
| 409 | "TypePipe" , |
| 410 | "TypeForwardPointer" , |
| 411 | "#40" , |
| 412 | "ConstantTrue" , |
| 413 | "ConstantFalse" , |
| 414 | "Constant" , |
| 415 | "ConstantComposite" , |
| 416 | "ConstantSampler" , |
| 417 | "ConstantNull" , |
| 418 | "#47" , |
| 419 | "SpecConstantTrue" , |
| 420 | "SpecConstantFalse" , |
| 421 | "SpecConstant" , |
| 422 | "SpecConstantComposite" , |
| 423 | "SpecConstantOp" , |
| 424 | "#53" , |
| 425 | "Function" , |
| 426 | "FunctionParameter" , |
| 427 | "FunctionEnd" , |
| 428 | "FunctionCall" , |
| 429 | "#58" , |
| 430 | "Variable" , |
| 431 | "ImageTexelPointer" , |
| 432 | "Load" , |
| 433 | "Store" , |
| 434 | "CopyMemory" , |
| 435 | "CopyMemorySized" , |
| 436 | "AccessChain" , |
| 437 | "InBoundsAccessChain" , |
| 438 | "PtrAccessChain" , |
| 439 | "ArrayLength" , |
| 440 | "GenericPtrMemSemantics" , |
| 441 | "InBoundsPtrAccessChain" , |
| 442 | "Decorate" , |
| 443 | "MemberDecorate" , |
| 444 | "DecorationGroup" , |
| 445 | "GroupDecorate" , |
| 446 | "GroupMemberDecorate" , |
| 447 | "#76" , |
| 448 | "VectorExtractDynamic" , |
| 449 | "VectorInsertDynamic" , |
| 450 | "VectorShuffle" , |
| 451 | "CompositeConstruct" , |
| 452 | "CompositeExtract" , |
| 453 | "CompositeInsert" , |
| 454 | "CopyObject" , |
| 455 | "Transpose" , |
| 456 | "#85" , |
| 457 | "SampledImage" , |
| 458 | "ImageSampleImplicitLod" , |
| 459 | "ImageSampleExplicitLod" , |
| 460 | "ImageSampleDrefImplicitLod" , |
| 461 | "ImageSampleDrefExplicitLod" , |
| 462 | "ImageSampleProjImplicitLod" , |
| 463 | "ImageSampleProjExplicitLod" , |
| 464 | "ImageSampleProjDrefImplicitLod" , |
| 465 | "ImageSampleProjDrefExplicitLod" , |
| 466 | "ImageFetch" , |
| 467 | "ImageGather" , |
| 468 | "ImageDrefGather" , |
| 469 | "ImageRead" , |
| 470 | "ImageWrite" , |
| 471 | "Image" , |
| 472 | "ImageQueryFormat" , |
| 473 | "ImageQueryOrder" , |
| 474 | "ImageQuerySizeLod" , |
| 475 | "ImageQuerySize" , |
| 476 | "ImageQueryLod" , |
| 477 | "ImageQueryLevels" , |
| 478 | "ImageQuerySamples" , |
| 479 | "#108" , |
| 480 | "ConvertFToU" , |
| 481 | "ConvertFToS" , |
| 482 | "ConvertSToF" , |
| 483 | "ConvertUToF" , |
| 484 | "UConvert" , |
| 485 | "SConvert" , |
| 486 | "FConvert" , |
| 487 | "QuantizeToF16" , |
| 488 | "ConvertPtrToU" , |
| 489 | "SatConvertSToU" , |
| 490 | "SatConvertUToS" , |
| 491 | "ConvertUToPtr" , |
| 492 | "PtrCastToGeneric" , |
| 493 | "GenericCastToPtr" , |
| 494 | "GenericCastToPtrExplicit" , |
| 495 | "Bitcast" , |
| 496 | "#125" , |
| 497 | "SNegate" , |
| 498 | "FNegate" , |
| 499 | "IAdd" , |
| 500 | "FAdd" , |
| 501 | "ISub" , |
| 502 | "FSub" , |
| 503 | "IMul" , |
| 504 | "FMul" , |
| 505 | "UDiv" , |
| 506 | "SDiv" , |
| 507 | "FDiv" , |
| 508 | "UMod" , |
| 509 | "SRem" , |
| 510 | "SMod" , |
| 511 | "FRem" , |
| 512 | "FMod" , |
| 513 | "VectorTimesScalar" , |
| 514 | "MatrixTimesScalar" , |
| 515 | "VectorTimesMatrix" , |
| 516 | "MatrixTimesVector" , |
| 517 | "MatrixTimesMatrix" , |
| 518 | "OuterProduct" , |
| 519 | "Dot" , |
| 520 | "IAddCarry" , |
| 521 | "ISubBorrow" , |
| 522 | "UMulExtended" , |
| 523 | "SMulExtended" , |
| 524 | "#153" , |
| 525 | "Any" , |
| 526 | "All" , |
| 527 | "IsNan" , |
| 528 | "IsInf" , |
| 529 | "IsFinite" , |
| 530 | "IsNormal" , |
| 531 | "SignBitSet" , |
| 532 | "LessOrGreater" , |
| 533 | "Ordered" , |
| 534 | "Unordered" , |
| 535 | "LogicalEqual" , |
| 536 | "LogicalNotEqual" , |
| 537 | "LogicalOr" , |
| 538 | "LogicalAnd" , |
| 539 | "LogicalNot" , |
| 540 | "Select" , |
| 541 | "IEqual" , |
| 542 | "INotEqual" , |
| 543 | "UGreaterThan" , |
| 544 | "SGreaterThan" , |
| 545 | "UGreaterThanEqual" , |
| 546 | "SGreaterThanEqual" , |
| 547 | "ULessThan" , |
| 548 | "SLessThan" , |
| 549 | "ULessThanEqual" , |
| 550 | "SLessThanEqual" , |
| 551 | "FOrdEqual" , |
| 552 | "FUnordEqual" , |
| 553 | "FOrdNotEqual" , |
| 554 | "FUnordNotEqual" , |
| 555 | "FOrdLessThan" , |
| 556 | "FUnordLessThan" , |
| 557 | "FOrdGreaterThan" , |
| 558 | "FUnordGreaterThan" , |
| 559 | "FOrdLessThanEqual" , |
| 560 | "FUnordLessThanEqual" , |
| 561 | "FOrdGreaterThanEqual" , |
| 562 | "FUnordGreaterThanEqual" , |
| 563 | "#192" , |
| 564 | "#193" , |
| 565 | "ShiftRightLogical" , |
| 566 | "ShiftRightArithmetic" , |
| 567 | "ShiftLeftLogical" , |
| 568 | "BitwiseOr" , |
| 569 | "BitwiseXor" , |
| 570 | "BitwiseAnd" , |
| 571 | "Not" , |
| 572 | "BitFieldInsert" , |
| 573 | "BitFieldSExtract" , |
| 574 | "BitFieldUExtract" , |
| 575 | "BitReverse" , |
| 576 | "BitCount" , |
| 577 | "#206" , |
| 578 | "DPdx" , |
| 579 | "DPdy" , |
| 580 | "Fwidth" , |
| 581 | "DPdxFine" , |
| 582 | "DPdyFine" , |
| 583 | "FwidthFine" , |
| 584 | "DPdxCoarse" , |
| 585 | "DPdyCoarse" , |
| 586 | "FwidthCoarse" , |
| 587 | "#216" , |
| 588 | "#217" , |
| 589 | "EmitVertex" , |
| 590 | "EndPrimitive" , |
| 591 | "EmitStreamVertex" , |
| 592 | "EndStreamPrimitive" , |
| 593 | "#222" , |
| 594 | "#223" , |
| 595 | "ControlBarrier" , |
| 596 | "MemoryBarrier" , |
| 597 | "#226" , |
| 598 | "AtomicLoad" , |
| 599 | "AtomicStore" , |
| 600 | "AtomicExchange" , |
| 601 | "AtomicCompareExchange" , |
| 602 | "AtomicCompareExchangeWeak" , |
| 603 | "AtomicIIncrement" , |
| 604 | "AtomicIDecrement" , |
| 605 | "AtomicIAdd" , |
| 606 | "AtomicISub" , |
| 607 | "AtomicSMin" , |
| 608 | "AtomicUMin" , |
| 609 | "AtomicSMax" , |
| 610 | "AtomicUMax" , |
| 611 | "AtomicAnd" , |
| 612 | "AtomicOr" , |
| 613 | "AtomicXor" , |
| 614 | "#243" , |
| 615 | "#244" , |
| 616 | "Phi" , |
| 617 | "LoopMerge" , |
| 618 | "SelectionMerge" , |
| 619 | "Label" , |
| 620 | "Branch" , |
| 621 | "BranchConditional" , |
| 622 | "Switch" , |
| 623 | "Kill" , |
| 624 | "Return" , |
| 625 | "ReturnValue" , |
| 626 | "Unreachable" , |
| 627 | "LifetimeStart" , |
| 628 | "LifetimeStop" , |
| 629 | "#258" , |
| 630 | "GroupAsyncCopy" , |
| 631 | "GroupWaitEvents" , |
| 632 | "GroupAll" , |
| 633 | "GroupAny" , |
| 634 | "GroupBroadcast" , |
| 635 | "GroupIAdd" , |
| 636 | "GroupFAdd" , |
| 637 | "GroupFMin" , |
| 638 | "GroupUMin" , |
| 639 | "GroupSMin" , |
| 640 | "GroupFMax" , |
| 641 | "GroupUMax" , |
| 642 | "GroupSMax" , |
| 643 | "#272" , |
| 644 | "#273" , |
| 645 | "ReadPipe" , |
| 646 | "WritePipe" , |
| 647 | "ReservedReadPipe" , |
| 648 | "ReservedWritePipe" , |
| 649 | "ReserveReadPipePackets" , |
| 650 | "ReserveWritePipePackets" , |
| 651 | "CommitReadPipe" , |
| 652 | "CommitWritePipe" , |
| 653 | "IsValidReserveId" , |
| 654 | "GetNumPipePackets" , |
| 655 | "GetMaxPipePackets" , |
| 656 | "GroupReserveReadPipePackets" , |
| 657 | "GroupReserveWritePipePackets" , |
| 658 | "GroupCommitReadPipe" , |
| 659 | "GroupCommitWritePipe" , |
| 660 | "#289" , |
| 661 | "#290" , |
| 662 | "EnqueueMarker" , |
| 663 | "EnqueueKernel" , |
| 664 | "GetKernelNDrangeSubGroupCount" , |
| 665 | "GetKernelNDrangeMaxSubGroupSize" , |
| 666 | "GetKernelWorkGroupSize" , |
| 667 | "GetKernelPreferredWorkGroupSizeMultiple" , |
| 668 | "RetainEvent" , |
| 669 | "ReleaseEvent" , |
| 670 | "CreateUserEvent" , |
| 671 | "IsValidEvent" , |
| 672 | "SetUserEventStatus" , |
| 673 | "CaptureEventProfilingInfo" , |
| 674 | "GetDefaultQueue" , |
| 675 | "BuildNDRange" , |
| 676 | "ImageSparseSampleImplicitLod" , |
| 677 | "ImageSparseSampleExplicitLod" , |
| 678 | "ImageSparseSampleDrefImplicitLod" , |
| 679 | "ImageSparseSampleDrefExplicitLod" , |
| 680 | "ImageSparseSampleProjImplicitLod" , |
| 681 | "ImageSparseSampleProjExplicitLod" , |
| 682 | "ImageSparseSampleProjDrefImplicitLod" , |
| 683 | "ImageSparseSampleProjDrefExplicitLod" , |
| 684 | "ImageSparseFetch" , |
| 685 | "ImageSparseGather" , |
| 686 | "ImageSparseDrefGather" , |
| 687 | "ImageSparseTexelsResident" , |
| 688 | "NoLine" , |
| 689 | "AtomicFlagTestAndSet" , |
| 690 | "AtomicFlagClear" , |
| 691 | "ImageSparseRead" , |
| 692 | "SizeOf" , |
| 693 | "TypePipeStorage" , |
| 694 | "ConstantPipeStorage" , |
| 695 | "CreatePipeFromPipeStorage" , |
| 696 | "GetKernelLocalSizeForSubgroupCount" , |
| 697 | "GetKernelMaxNumSubgroups" , |
| 698 | "TypeNamedBarrier" , |
| 699 | "NamedBarrierInitialize" , |
| 700 | "MemoryNamedBarrier" , |
| 701 | "ModuleProcessed" , |
| 702 | "ExecutionModeId" , |
| 703 | "DecorateId" , |
| 704 | "GroupNonUniformElect" , |
| 705 | "GroupNonUniformAll" , |
| 706 | "GroupNonUniformAny" , |
| 707 | "GroupNonUniformAllEqual" , |
| 708 | "GroupNonUniformBroadcast" , |
| 709 | "GroupNonUniformBroadcastFirst" , |
| 710 | "GroupNonUniformBallot" , |
| 711 | "GroupNonUniformInverseBallot" , |
| 712 | "GroupNonUniformBallotBitExtract" , |
| 713 | "GroupNonUniformBallotBitCount" , |
| 714 | "GroupNonUniformBallotFindLSB" , |
| 715 | "GroupNonUniformBallotFindMSB" , |
| 716 | "GroupNonUniformShuffle" , |
| 717 | "GroupNonUniformShuffleXor" , |
| 718 | "GroupNonUniformShuffleUp" , |
| 719 | "GroupNonUniformShuffleDown" , |
| 720 | "GroupNonUniformIAdd" , |
| 721 | "GroupNonUniformFAdd" , |
| 722 | "GroupNonUniformIMul" , |
| 723 | "GroupNonUniformFMul" , |
| 724 | "GroupNonUniformSMin" , |
| 725 | "GroupNonUniformUMin" , |
| 726 | "GroupNonUniformFMin" , |
| 727 | "GroupNonUniformSMax" , |
| 728 | "GroupNonUniformUMax" , |
| 729 | "GroupNonUniformFMax" , |
| 730 | "GroupNonUniformBitwiseAnd" , |
| 731 | "GroupNonUniformBitwiseOr" , |
| 732 | "GroupNonUniformBitwiseXor" , |
| 733 | "GroupNonUniformLogicalAnd" , |
| 734 | "GroupNonUniformLogicalOr" , |
| 735 | "GroupNonUniformLogicalXor" , |
| 736 | "GroupNonUniformQuadBroadcast" , |
| 737 | "GroupNonUniformQuadSwap" , |
| 738 | }; |
| 739 | static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpNames) == kKnownOpsCount, "kSpirvOpNames table mismatch with known SpvOps" ); |
| 740 | |
| 741 | |
| 742 | struct OpData |
| 743 | { |
| 744 | uint8_t hasResult; // does it have result ID? |
| 745 | uint8_t hasType; // does it have type ID? |
| 746 | uint8_t deltaFromResult; // How many words after (optional) type+result to write out as deltas from result? |
| 747 | uint8_t varrest; // should the rest of words be written in varint encoding? |
| 748 | }; |
| 749 | static const OpData kSpirvOpData[] = |
| 750 | { |
| 751 | {0, 0, 0, 0}, // Nop |
| 752 | {1, 1, 0, 0}, // Undef |
| 753 | {0, 0, 0, 0}, // SourceContinued |
| 754 | {0, 0, 0, 1}, // Source |
| 755 | {0, 0, 0, 0}, // SourceExtension |
| 756 | {0, 0, 0, 0}, // Name |
| 757 | {0, 0, 0, 0}, // MemberName |
| 758 | {0, 0, 0, 0}, // String |
| 759 | {0, 0, 0, 1}, // Line |
| 760 | {1, 1, 0, 0}, // #9 |
| 761 | {0, 0, 0, 0}, // Extension |
| 762 | {1, 0, 0, 0}, // ExtInstImport |
| 763 | {1, 1, 0, 1}, // ExtInst |
| 764 | {1, 1, 2, 1}, // VectorShuffleCompact - new in SMOLV |
| 765 | {0, 0, 0, 1}, // MemoryModel |
| 766 | {0, 0, 0, 1}, // EntryPoint |
| 767 | {0, 0, 0, 1}, // ExecutionMode |
| 768 | {0, 0, 0, 1}, // Capability |
| 769 | {1, 1, 0, 0}, // #18 |
| 770 | {1, 0, 0, 1}, // TypeVoid |
| 771 | {1, 0, 0, 1}, // TypeBool |
| 772 | {1, 0, 0, 1}, // TypeInt |
| 773 | {1, 0, 0, 1}, // TypeFloat |
| 774 | {1, 0, 0, 1}, // TypeVector |
| 775 | {1, 0, 0, 1}, // TypeMatrix |
| 776 | {1, 0, 0, 1}, // TypeImage |
| 777 | {1, 0, 0, 1}, // TypeSampler |
| 778 | {1, 0, 0, 1}, // TypeSampledImage |
| 779 | {1, 0, 0, 1}, // TypeArray |
| 780 | {1, 0, 0, 1}, // TypeRuntimeArray |
| 781 | {1, 0, 0, 1}, // TypeStruct |
| 782 | {1, 0, 0, 1}, // TypeOpaque |
| 783 | {1, 0, 0, 1}, // TypePointer |
| 784 | {1, 0, 0, 1}, // TypeFunction |
| 785 | {1, 0, 0, 1}, // TypeEvent |
| 786 | {1, 0, 0, 1}, // TypeDeviceEvent |
| 787 | {1, 0, 0, 1}, // TypeReserveId |
| 788 | {1, 0, 0, 1}, // TypeQueue |
| 789 | {1, 0, 0, 1}, // TypePipe |
| 790 | {0, 0, 0, 1}, // TypeForwardPointer |
| 791 | {1, 1, 0, 0}, // #40 |
| 792 | {1, 1, 0, 0}, // ConstantTrue |
| 793 | {1, 1, 0, 0}, // ConstantFalse |
| 794 | {1, 1, 0, 0}, // Constant |
| 795 | {1, 1, 9, 0}, // ConstantComposite |
| 796 | {1, 1, 0, 1}, // ConstantSampler |
| 797 | {1, 1, 0, 0}, // ConstantNull |
| 798 | {1, 1, 0, 0}, // #47 |
| 799 | {1, 1, 0, 0}, // SpecConstantTrue |
| 800 | {1, 1, 0, 0}, // SpecConstantFalse |
| 801 | {1, 1, 0, 0}, // SpecConstant |
| 802 | {1, 1, 9, 0}, // SpecConstantComposite |
| 803 | {1, 1, 0, 0}, // SpecConstantOp |
| 804 | {1, 1, 0, 0}, // #53 |
| 805 | {1, 1, 0, 1}, // Function |
| 806 | {1, 1, 0, 0}, // FunctionParameter |
| 807 | {0, 0, 0, 0}, // FunctionEnd |
| 808 | {1, 1, 9, 0}, // FunctionCall |
| 809 | {1, 1, 0, 0}, // #58 |
| 810 | {1, 1, 0, 1}, // Variable |
| 811 | {1, 1, 0, 0}, // ImageTexelPointer |
| 812 | {1, 1, 1, 1}, // Load |
| 813 | {0, 0, 2, 1}, // Store |
| 814 | {0, 0, 0, 0}, // CopyMemory |
| 815 | {0, 0, 0, 0}, // CopyMemorySized |
| 816 | {1, 1, 0, 1}, // AccessChain |
| 817 | {1, 1, 0, 0}, // InBoundsAccessChain |
| 818 | {1, 1, 0, 0}, // PtrAccessChain |
| 819 | {1, 1, 0, 0}, // ArrayLength |
| 820 | {1, 1, 0, 0}, // GenericPtrMemSemantics |
| 821 | {1, 1, 0, 0}, // InBoundsPtrAccessChain |
| 822 | {0, 0, 0, 1}, // Decorate |
| 823 | {0, 0, 0, 1}, // MemberDecorate |
| 824 | {1, 0, 0, 0}, // DecorationGroup |
| 825 | {0, 0, 0, 0}, // GroupDecorate |
| 826 | {0, 0, 0, 0}, // GroupMemberDecorate |
| 827 | {1, 1, 0, 0}, // #76 |
| 828 | {1, 1, 1, 1}, // VectorExtractDynamic |
| 829 | {1, 1, 2, 1}, // VectorInsertDynamic |
| 830 | {1, 1, 2, 1}, // VectorShuffle |
| 831 | {1, 1, 9, 0}, // CompositeConstruct |
| 832 | {1, 1, 1, 1}, // CompositeExtract |
| 833 | {1, 1, 2, 1}, // CompositeInsert |
| 834 | {1, 1, 1, 0}, // CopyObject |
| 835 | {1, 1, 0, 0}, // Transpose |
| 836 | {1, 1, 0, 0}, // #85 |
| 837 | {1, 1, 0, 0}, // SampledImage |
| 838 | {1, 1, 2, 1}, // ImageSampleImplicitLod |
| 839 | {1, 1, 2, 1}, // ImageSampleExplicitLod |
| 840 | {1, 1, 3, 1}, // ImageSampleDrefImplicitLod |
| 841 | {1, 1, 3, 1}, // ImageSampleDrefExplicitLod |
| 842 | {1, 1, 2, 1}, // ImageSampleProjImplicitLod |
| 843 | {1, 1, 2, 1}, // ImageSampleProjExplicitLod |
| 844 | {1, 1, 3, 1}, // ImageSampleProjDrefImplicitLod |
| 845 | {1, 1, 3, 1}, // ImageSampleProjDrefExplicitLod |
| 846 | {1, 1, 2, 1}, // ImageFetch |
| 847 | {1, 1, 3, 1}, // ImageGather |
| 848 | {1, 1, 3, 1}, // ImageDrefGather |
| 849 | {1, 1, 2, 1}, // ImageRead |
| 850 | {0, 0, 3, 1}, // ImageWrite |
| 851 | {1, 1, 1, 0}, // Image |
| 852 | {1, 1, 1, 0}, // ImageQueryFormat |
| 853 | {1, 1, 1, 0}, // ImageQueryOrder |
| 854 | {1, 1, 2, 0}, // ImageQuerySizeLod |
| 855 | {1, 1, 1, 0}, // ImageQuerySize |
| 856 | {1, 1, 2, 0}, // ImageQueryLod |
| 857 | {1, 1, 1, 0}, // ImageQueryLevels |
| 858 | {1, 1, 1, 0}, // ImageQuerySamples |
| 859 | {1, 1, 0, 0}, // #108 |
| 860 | {1, 1, 1, 0}, // ConvertFToU |
| 861 | {1, 1, 1, 0}, // ConvertFToS |
| 862 | {1, 1, 1, 0}, // ConvertSToF |
| 863 | {1, 1, 1, 0}, // ConvertUToF |
| 864 | {1, 1, 1, 0}, // UConvert |
| 865 | {1, 1, 1, 0}, // SConvert |
| 866 | {1, 1, 1, 0}, // FConvert |
| 867 | {1, 1, 1, 0}, // QuantizeToF16 |
| 868 | {1, 1, 1, 0}, // ConvertPtrToU |
| 869 | {1, 1, 1, 0}, // SatConvertSToU |
| 870 | {1, 1, 1, 0}, // SatConvertUToS |
| 871 | {1, 1, 1, 0}, // ConvertUToPtr |
| 872 | {1, 1, 1, 0}, // PtrCastToGeneric |
| 873 | {1, 1, 1, 0}, // GenericCastToPtr |
| 874 | {1, 1, 1, 1}, // GenericCastToPtrExplicit |
| 875 | {1, 1, 1, 0}, // Bitcast |
| 876 | {1, 1, 0, 0}, // #125 |
| 877 | {1, 1, 1, 0}, // SNegate |
| 878 | {1, 1, 1, 0}, // FNegate |
| 879 | {1, 1, 2, 0}, // IAdd |
| 880 | {1, 1, 2, 0}, // FAdd |
| 881 | {1, 1, 2, 0}, // ISub |
| 882 | {1, 1, 2, 0}, // FSub |
| 883 | {1, 1, 2, 0}, // IMul |
| 884 | {1, 1, 2, 0}, // FMul |
| 885 | {1, 1, 2, 0}, // UDiv |
| 886 | {1, 1, 2, 0}, // SDiv |
| 887 | {1, 1, 2, 0}, // FDiv |
| 888 | {1, 1, 2, 0}, // UMod |
| 889 | {1, 1, 2, 0}, // SRem |
| 890 | {1, 1, 2, 0}, // SMod |
| 891 | {1, 1, 2, 0}, // FRem |
| 892 | {1, 1, 2, 0}, // FMod |
| 893 | {1, 1, 2, 0}, // VectorTimesScalar |
| 894 | {1, 1, 2, 0}, // MatrixTimesScalar |
| 895 | {1, 1, 2, 0}, // VectorTimesMatrix |
| 896 | {1, 1, 2, 0}, // MatrixTimesVector |
| 897 | {1, 1, 2, 0}, // MatrixTimesMatrix |
| 898 | {1, 1, 2, 0}, // OuterProduct |
| 899 | {1, 1, 2, 0}, // Dot |
| 900 | {1, 1, 2, 0}, // IAddCarry |
| 901 | {1, 1, 2, 0}, // ISubBorrow |
| 902 | {1, 1, 2, 0}, // UMulExtended |
| 903 | {1, 1, 2, 0}, // SMulExtended |
| 904 | {1, 1, 0, 0}, // #153 |
| 905 | {1, 1, 1, 0}, // Any |
| 906 | {1, 1, 1, 0}, // All |
| 907 | {1, 1, 1, 0}, // IsNan |
| 908 | {1, 1, 1, 0}, // IsInf |
| 909 | {1, 1, 1, 0}, // IsFinite |
| 910 | {1, 1, 1, 0}, // IsNormal |
| 911 | {1, 1, 1, 0}, // SignBitSet |
| 912 | {1, 1, 2, 0}, // LessOrGreater |
| 913 | {1, 1, 2, 0}, // Ordered |
| 914 | {1, 1, 2, 0}, // Unordered |
| 915 | {1, 1, 2, 0}, // LogicalEqual |
| 916 | {1, 1, 2, 0}, // LogicalNotEqual |
| 917 | {1, 1, 2, 0}, // LogicalOr |
| 918 | {1, 1, 2, 0}, // LogicalAnd |
| 919 | {1, 1, 1, 0}, // LogicalNot |
| 920 | {1, 1, 3, 0}, // Select |
| 921 | {1, 1, 2, 0}, // IEqual |
| 922 | {1, 1, 2, 0}, // INotEqual |
| 923 | {1, 1, 2, 0}, // UGreaterThan |
| 924 | {1, 1, 2, 0}, // SGreaterThan |
| 925 | {1, 1, 2, 0}, // UGreaterThanEqual |
| 926 | {1, 1, 2, 0}, // SGreaterThanEqual |
| 927 | {1, 1, 2, 0}, // ULessThan |
| 928 | {1, 1, 2, 0}, // SLessThan |
| 929 | {1, 1, 2, 0}, // ULessThanEqual |
| 930 | {1, 1, 2, 0}, // SLessThanEqual |
| 931 | {1, 1, 2, 0}, // FOrdEqual |
| 932 | {1, 1, 2, 0}, // FUnordEqual |
| 933 | {1, 1, 2, 0}, // FOrdNotEqual |
| 934 | {1, 1, 2, 0}, // FUnordNotEqual |
| 935 | {1, 1, 2, 0}, // FOrdLessThan |
| 936 | {1, 1, 2, 0}, // FUnordLessThan |
| 937 | {1, 1, 2, 0}, // FOrdGreaterThan |
| 938 | {1, 1, 2, 0}, // FUnordGreaterThan |
| 939 | {1, 1, 2, 0}, // FOrdLessThanEqual |
| 940 | {1, 1, 2, 0}, // FUnordLessThanEqual |
| 941 | {1, 1, 2, 0}, // FOrdGreaterThanEqual |
| 942 | {1, 1, 2, 0}, // FUnordGreaterThanEqual |
| 943 | {1, 1, 0, 0}, // #192 |
| 944 | {1, 1, 0, 0}, // #193 |
| 945 | {1, 1, 2, 0}, // ShiftRightLogical |
| 946 | {1, 1, 2, 0}, // ShiftRightArithmetic |
| 947 | {1, 1, 2, 0}, // ShiftLeftLogical |
| 948 | {1, 1, 2, 0}, // BitwiseOr |
| 949 | {1, 1, 2, 0}, // BitwiseXor |
| 950 | {1, 1, 2, 0}, // BitwiseAnd |
| 951 | {1, 1, 1, 0}, // Not |
| 952 | {1, 1, 4, 0}, // BitFieldInsert |
| 953 | {1, 1, 3, 0}, // BitFieldSExtract |
| 954 | {1, 1, 3, 0}, // BitFieldUExtract |
| 955 | {1, 1, 1, 0}, // BitReverse |
| 956 | {1, 1, 1, 0}, // BitCount |
| 957 | {1, 1, 0, 0}, // #206 |
| 958 | {1, 1, 0, 0}, // DPdx |
| 959 | {1, 1, 0, 0}, // DPdy |
| 960 | {1, 1, 0, 0}, // Fwidth |
| 961 | {1, 1, 0, 0}, // DPdxFine |
| 962 | {1, 1, 0, 0}, // DPdyFine |
| 963 | {1, 1, 0, 0}, // FwidthFine |
| 964 | {1, 1, 0, 0}, // DPdxCoarse |
| 965 | {1, 1, 0, 0}, // DPdyCoarse |
| 966 | {1, 1, 0, 0}, // FwidthCoarse |
| 967 | {1, 1, 0, 0}, // #216 |
| 968 | {1, 1, 0, 0}, // #217 |
| 969 | {0, 0, 0, 0}, // EmitVertex |
| 970 | {0, 0, 0, 0}, // EndPrimitive |
| 971 | {0, 0, 0, 0}, // EmitStreamVertex |
| 972 | {0, 0, 0, 0}, // EndStreamPrimitive |
| 973 | {1, 1, 0, 0}, // #222 |
| 974 | {1, 1, 0, 0}, // #223 |
| 975 | {0, 0, 3, 0}, // ControlBarrier |
| 976 | {0, 0, 2, 0}, // MemoryBarrier |
| 977 | {1, 1, 0, 0}, // #226 |
| 978 | {1, 1, 0, 0}, // AtomicLoad |
| 979 | {0, 0, 0, 0}, // AtomicStore |
| 980 | {1, 1, 0, 0}, // AtomicExchange |
| 981 | {1, 1, 0, 0}, // AtomicCompareExchange |
| 982 | {1, 1, 0, 0}, // AtomicCompareExchangeWeak |
| 983 | {1, 1, 0, 0}, // AtomicIIncrement |
| 984 | {1, 1, 0, 0}, // AtomicIDecrement |
| 985 | {1, 1, 0, 0}, // AtomicIAdd |
| 986 | {1, 1, 0, 0}, // AtomicISub |
| 987 | {1, 1, 0, 0}, // AtomicSMin |
| 988 | {1, 1, 0, 0}, // AtomicUMin |
| 989 | {1, 1, 0, 0}, // AtomicSMax |
| 990 | {1, 1, 0, 0}, // AtomicUMax |
| 991 | {1, 1, 0, 0}, // AtomicAnd |
| 992 | {1, 1, 0, 0}, // AtomicOr |
| 993 | {1, 1, 0, 0}, // AtomicXor |
| 994 | {1, 1, 0, 0}, // #243 |
| 995 | {1, 1, 0, 0}, // #244 |
| 996 | {1, 1, 0, 0}, // Phi |
| 997 | {0, 0, 2, 1}, // LoopMerge |
| 998 | {0, 0, 1, 1}, // SelectionMerge |
| 999 | {1, 0, 0, 0}, // Label |
| 1000 | {0, 0, 1, 0}, // Branch |
| 1001 | {0, 0, 3, 1}, // BranchConditional |
| 1002 | {0, 0, 0, 0}, // Switch |
| 1003 | {0, 0, 0, 0}, // Kill |
| 1004 | {0, 0, 0, 0}, // Return |
| 1005 | {0, 0, 0, 0}, // ReturnValue |
| 1006 | {0, 0, 0, 0}, // Unreachable |
| 1007 | {0, 0, 0, 0}, // LifetimeStart |
| 1008 | {0, 0, 0, 0}, // LifetimeStop |
| 1009 | {1, 1, 0, 0}, // #258 |
| 1010 | {1, 1, 0, 0}, // GroupAsyncCopy |
| 1011 | {0, 0, 0, 0}, // GroupWaitEvents |
| 1012 | {1, 1, 0, 0}, // GroupAll |
| 1013 | {1, 1, 0, 0}, // GroupAny |
| 1014 | {1, 1, 0, 0}, // GroupBroadcast |
| 1015 | {1, 1, 0, 0}, // GroupIAdd |
| 1016 | {1, 1, 0, 0}, // GroupFAdd |
| 1017 | {1, 1, 0, 0}, // GroupFMin |
| 1018 | {1, 1, 0, 0}, // GroupUMin |
| 1019 | {1, 1, 0, 0}, // GroupSMin |
| 1020 | {1, 1, 0, 0}, // GroupFMax |
| 1021 | {1, 1, 0, 0}, // GroupUMax |
| 1022 | {1, 1, 0, 0}, // GroupSMax |
| 1023 | {1, 1, 0, 0}, // #272 |
| 1024 | {1, 1, 0, 0}, // #273 |
| 1025 | {1, 1, 0, 0}, // ReadPipe |
| 1026 | {1, 1, 0, 0}, // WritePipe |
| 1027 | {1, 1, 0, 0}, // ReservedReadPipe |
| 1028 | {1, 1, 0, 0}, // ReservedWritePipe |
| 1029 | {1, 1, 0, 0}, // ReserveReadPipePackets |
| 1030 | {1, 1, 0, 0}, // ReserveWritePipePackets |
| 1031 | {0, 0, 0, 0}, // CommitReadPipe |
| 1032 | {0, 0, 0, 0}, // CommitWritePipe |
| 1033 | {1, 1, 0, 0}, // IsValidReserveId |
| 1034 | {1, 1, 0, 0}, // GetNumPipePackets |
| 1035 | {1, 1, 0, 0}, // GetMaxPipePackets |
| 1036 | {1, 1, 0, 0}, // GroupReserveReadPipePackets |
| 1037 | {1, 1, 0, 0}, // GroupReserveWritePipePackets |
| 1038 | {0, 0, 0, 0}, // GroupCommitReadPipe |
| 1039 | {0, 0, 0, 0}, // GroupCommitWritePipe |
| 1040 | {1, 1, 0, 0}, // #289 |
| 1041 | {1, 1, 0, 0}, // #290 |
| 1042 | {1, 1, 0, 0}, // EnqueueMarker |
| 1043 | {1, 1, 0, 0}, // EnqueueKernel |
| 1044 | {1, 1, 0, 0}, // GetKernelNDrangeSubGroupCount |
| 1045 | {1, 1, 0, 0}, // GetKernelNDrangeMaxSubGroupSize |
| 1046 | {1, 1, 0, 0}, // GetKernelWorkGroupSize |
| 1047 | {1, 1, 0, 0}, // GetKernelPreferredWorkGroupSizeMultiple |
| 1048 | {0, 0, 0, 0}, // RetainEvent |
| 1049 | {0, 0, 0, 0}, // ReleaseEvent |
| 1050 | {1, 1, 0, 0}, // CreateUserEvent |
| 1051 | {1, 1, 0, 0}, // IsValidEvent |
| 1052 | {0, 0, 0, 0}, // SetUserEventStatus |
| 1053 | {0, 0, 0, 0}, // CaptureEventProfilingInfo |
| 1054 | {1, 1, 0, 0}, // GetDefaultQueue |
| 1055 | {1, 1, 0, 0}, // BuildNDRange |
| 1056 | {1, 1, 2, 1}, // ImageSparseSampleImplicitLod |
| 1057 | {1, 1, 2, 1}, // ImageSparseSampleExplicitLod |
| 1058 | {1, 1, 3, 1}, // ImageSparseSampleDrefImplicitLod |
| 1059 | {1, 1, 3, 1}, // ImageSparseSampleDrefExplicitLod |
| 1060 | {1, 1, 2, 1}, // ImageSparseSampleProjImplicitLod |
| 1061 | {1, 1, 2, 1}, // ImageSparseSampleProjExplicitLod |
| 1062 | {1, 1, 3, 1}, // ImageSparseSampleProjDrefImplicitLod |
| 1063 | {1, 1, 3, 1}, // ImageSparseSampleProjDrefExplicitLod |
| 1064 | {1, 1, 2, 1}, // ImageSparseFetch |
| 1065 | {1, 1, 3, 1}, // ImageSparseGather |
| 1066 | {1, 1, 3, 1}, // ImageSparseDrefGather |
| 1067 | {1, 1, 1, 0}, // ImageSparseTexelsResident |
| 1068 | {0, 0, 0, 0}, // NoLine |
| 1069 | {1, 1, 0, 0}, // AtomicFlagTestAndSet |
| 1070 | {0, 0, 0, 0}, // AtomicFlagClear |
| 1071 | {1, 1, 0, 0}, // ImageSparseRead |
| 1072 | {1, 1, 0, 0}, // SizeOf |
| 1073 | {1, 1, 0, 0}, // TypePipeStorage |
| 1074 | {1, 1, 0, 0}, // ConstantPipeStorage |
| 1075 | {1, 1, 0, 0}, // CreatePipeFromPipeStorage |
| 1076 | {1, 1, 0, 0}, // GetKernelLocalSizeForSubgroupCount |
| 1077 | {1, 1, 0, 0}, // GetKernelMaxNumSubgroups |
| 1078 | {1, 1, 0, 0}, // TypeNamedBarrier |
| 1079 | {1, 1, 0, 1}, // NamedBarrierInitialize |
| 1080 | {0, 0, 2, 1}, // MemoryNamedBarrier |
| 1081 | {1, 1, 0, 0}, // ModuleProcessed |
| 1082 | {0, 0, 0, 1}, // ExecutionModeId |
| 1083 | {0, 0, 0, 1}, // DecorateId |
| 1084 | {1, 1, 1, 1}, // GroupNonUniformElect |
| 1085 | {1, 1, 1, 1}, // GroupNonUniformAll |
| 1086 | {1, 1, 1, 1}, // GroupNonUniformAny |
| 1087 | {1, 1, 1, 1}, // GroupNonUniformAllEqual |
| 1088 | {1, 1, 1, 1}, // GroupNonUniformBroadcast |
| 1089 | {1, 1, 1, 1}, // GroupNonUniformBroadcastFirst |
| 1090 | {1, 1, 1, 1}, // GroupNonUniformBallot |
| 1091 | {1, 1, 1, 1}, // GroupNonUniformInverseBallot |
| 1092 | {1, 1, 1, 1}, // GroupNonUniformBallotBitExtract |
| 1093 | {1, 1, 1, 1}, // GroupNonUniformBallotBitCount |
| 1094 | {1, 1, 1, 1}, // GroupNonUniformBallotFindLSB |
| 1095 | {1, 1, 1, 1}, // GroupNonUniformBallotFindMSB |
| 1096 | {1, 1, 1, 1}, // GroupNonUniformShuffle |
| 1097 | {1, 1, 1, 1}, // GroupNonUniformShuffleXor |
| 1098 | {1, 1, 1, 1}, // GroupNonUniformShuffleUp |
| 1099 | {1, 1, 1, 1}, // GroupNonUniformShuffleDown |
| 1100 | {1, 1, 1, 1}, // GroupNonUniformIAdd |
| 1101 | {1, 1, 1, 1}, // GroupNonUniformFAdd |
| 1102 | {1, 1, 1, 1}, // GroupNonUniformIMul |
| 1103 | {1, 1, 1, 1}, // GroupNonUniformFMul |
| 1104 | {1, 1, 1, 1}, // GroupNonUniformSMin |
| 1105 | {1, 1, 1, 1}, // GroupNonUniformUMin |
| 1106 | {1, 1, 1, 1}, // GroupNonUniformFMin |
| 1107 | {1, 1, 1, 1}, // GroupNonUniformSMax |
| 1108 | {1, 1, 1, 1}, // GroupNonUniformUMax |
| 1109 | {1, 1, 1, 1}, // GroupNonUniformFMax |
| 1110 | {1, 1, 1, 1}, // GroupNonUniformBitwiseAnd |
| 1111 | {1, 1, 1, 1}, // GroupNonUniformBitwiseOr |
| 1112 | {1, 1, 1, 1}, // GroupNonUniformBitwiseXor |
| 1113 | {1, 1, 1, 1}, // GroupNonUniformLogicalAnd |
| 1114 | {1, 1, 1, 1}, // GroupNonUniformLogicalOr |
| 1115 | {1, 1, 1, 1}, // GroupNonUniformLogicalXor |
| 1116 | {1, 1, 1, 1}, // GroupNonUniformQuadBroadcast |
| 1117 | {1, 1, 1, 1}, // GroupNonUniformQuadSwap |
| 1118 | }; |
| 1119 | static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpData) == kKnownOpsCount, "kSpirvOpData table mismatch with known SpvOps" ); |
| 1120 | |
| 1121 | // Instruction encoding depends on the table that describes the various SPIR-V opcodes. |
| 1122 | // Whenever we change or expand the table, we need to bump up the SMOL-V version, and make |
| 1123 | // sure that we can still decode files encoded by an older version. |
| 1124 | static int smolv_GetKnownOpsCount(int version) |
| 1125 | { |
| 1126 | if (version == 0) |
| 1127 | return SpvOpModuleProcessed+1; |
| 1128 | if (version == 1) // 2020 February, version 1 added ExecutionModeId..GroupNonUniformQuadSwap |
| 1129 | return SpvOpGroupNonUniformQuadSwap+1; |
| 1130 | return 0; |
| 1131 | } |
| 1132 | |
| 1133 | static bool smolv_OpHasResult(SpvOp op, int opsCount) |
| 1134 | { |
| 1135 | if (op < 0 || op >= opsCount) |
| 1136 | return false; |
| 1137 | return kSpirvOpData[op].hasResult != 0; |
| 1138 | } |
| 1139 | |
| 1140 | static bool smolv_OpHasType(SpvOp op, int opsCount) |
| 1141 | { |
| 1142 | if (op < 0 || op >= opsCount) |
| 1143 | return false; |
| 1144 | return kSpirvOpData[op].hasType != 0; |
| 1145 | } |
| 1146 | |
| 1147 | static int smolv_OpDeltaFromResult(SpvOp op, int opsCount) |
| 1148 | { |
| 1149 | if (op < 0 || op >= opsCount) |
| 1150 | return 0; |
| 1151 | return kSpirvOpData[op].deltaFromResult; |
| 1152 | } |
| 1153 | |
| 1154 | static bool smolv_OpVarRest(SpvOp op, int opsCount) |
| 1155 | { |
| 1156 | if (op < 0 || op >= opsCount) |
| 1157 | return false; |
| 1158 | return kSpirvOpData[op].varrest != 0; |
| 1159 | } |
| 1160 | |
| 1161 | static bool smolv_OpDebugInfo(SpvOp op, int opsCount) |
| 1162 | { |
| 1163 | return |
| 1164 | op == SpvOpSourceContinued || |
| 1165 | op == SpvOpSource || |
| 1166 | op == SpvOpSourceExtension || |
| 1167 | op == SpvOpName || |
| 1168 | op == SpvOpMemberName || |
| 1169 | op == SpvOpString || |
| 1170 | op == SpvOpLine || |
| 1171 | op == SpvOpNoLine || |
| 1172 | op == SpvOpModuleProcessed; |
| 1173 | } |
| 1174 | |
| 1175 | |
| 1176 | static int (int dec) |
| 1177 | { |
| 1178 | if (dec == 0 || (dec >= 2 && dec <= 5)) // RelaxedPrecision, Block..ColMajor |
| 1179 | return 0; |
| 1180 | if (dec >= 29 && dec <= 37) // Stream..XfbStride |
| 1181 | return 1; |
| 1182 | return -1; // unknown, encode length |
| 1183 | } |
| 1184 | |
| 1185 | |
| 1186 | // -------------------------------------------------------------------------------------------- |
| 1187 | |
| 1188 | |
| 1189 | static bool (const uint32_t* words, size_t wordCount, uint32_t expectedMagic, uint32_t versionMask) |
| 1190 | { |
| 1191 | if (!words) |
| 1192 | return false; |
| 1193 | if (wordCount < 5) |
| 1194 | return false; |
| 1195 | |
| 1196 | uint32_t = words[0]; |
| 1197 | if (headerMagic != expectedMagic) |
| 1198 | return false; |
| 1199 | uint32_t = words[1] & versionMask; |
| 1200 | if (headerVersion < 0x00010000 || headerVersion > 0x00010500) |
| 1201 | return false; // only support 1.0 through 1.5 |
| 1202 | |
| 1203 | return true; |
| 1204 | } |
| 1205 | |
| 1206 | static const int = 0x07230203; |
| 1207 | static const int = 0x534D4F4C; // "SMOL" |
| 1208 | |
| 1209 | static const int kSmolCurrEncodingVersion = 1; |
| 1210 | |
| 1211 | static bool (const uint32_t* words, size_t wordCount) |
| 1212 | { |
| 1213 | //@TODO: if SPIR-V header magic was reversed, that means the file got written |
| 1214 | // in a "big endian" order. Need to byteswap all words then. |
| 1215 | return smolv_CheckGenericHeader(words, wordCount, kSpirVHeaderMagic, 0xFFFFFFFF); |
| 1216 | } |
| 1217 | static bool (const uint8_t* bytes, size_t byteCount) |
| 1218 | { |
| 1219 | if (!smolv_CheckGenericHeader((const uint32_t*)bytes, byteCount/4, kSmolHeaderMagic, 0x00FFFFFF)) |
| 1220 | return false; |
| 1221 | if (byteCount < 24) // one more word past header to store decoded length |
| 1222 | return false; |
| 1223 | // SMOL-V version |
| 1224 | int smolVersion = ((const uint32_t*)bytes)[1] >> 24; |
| 1225 | if (smolVersion < 0 || smolVersion > kSmolCurrEncodingVersion) |
| 1226 | return false; |
| 1227 | return true; |
| 1228 | } |
| 1229 | |
| 1230 | |
| 1231 | static void smolv_Write4(smolv::ByteArray& arr, uint32_t v) |
| 1232 | { |
| 1233 | arr.push_back(v & 0xFF); |
| 1234 | arr.push_back((v >> 8) & 0xFF); |
| 1235 | arr.push_back((v >> 16) & 0xFF); |
| 1236 | arr.push_back(v >> 24); |
| 1237 | } |
| 1238 | |
| 1239 | static void smolv_Write4(uint8_t*& buf, uint32_t v) |
| 1240 | { |
| 1241 | memcpy(buf, &v, 4); |
| 1242 | buf += 4; |
| 1243 | } |
| 1244 | |
| 1245 | |
| 1246 | static bool smolv_Read4(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outv) |
| 1247 | { |
| 1248 | if (data + 4 > dataEnd) |
| 1249 | return false; |
| 1250 | outv = (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); |
| 1251 | data += 4; |
| 1252 | return true; |
| 1253 | } |
| 1254 | |
| 1255 | |
| 1256 | // -------------------------------------------------------------------------------------------- |
| 1257 | |
| 1258 | // Variable-length integer encoding for unsigned integers. In each byte: |
| 1259 | // - highest bit set if more bytes follow, cleared if this is last byte. |
| 1260 | // - other 7 bits are the actual value payload. |
| 1261 | // Takes 1-5 bytes to encode an integer (values between 0 and 127 take one byte, etc.). |
| 1262 | |
| 1263 | static void smolv_WriteVarint(smolv::ByteArray& arr, uint32_t v) |
| 1264 | { |
| 1265 | while (v > 127) |
| 1266 | { |
| 1267 | arr.push_back((v & 127) | 128); |
| 1268 | v >>= 7; |
| 1269 | } |
| 1270 | arr.push_back(v & 127); |
| 1271 | } |
| 1272 | |
| 1273 | static bool smolv_ReadVarint(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outVal) |
| 1274 | { |
| 1275 | uint32_t v = 0; |
| 1276 | uint32_t shift = 0; |
| 1277 | while (data < dataEnd) |
| 1278 | { |
| 1279 | uint8_t b = *data; |
| 1280 | v |= (b & 127) << shift; |
| 1281 | shift += 7; |
| 1282 | data++; |
| 1283 | if (!(b & 128)) |
| 1284 | break; |
| 1285 | } |
| 1286 | outVal = v; |
| 1287 | return true; //@TODO: report failures |
| 1288 | } |
| 1289 | |
| 1290 | static uint32_t smolv_ZigEncode(int32_t i) |
| 1291 | { |
| 1292 | return (uint32_t(i) << 1) ^ (i >> 31); |
| 1293 | } |
| 1294 | |
| 1295 | static int32_t smolv_ZigDecode(uint32_t u) |
| 1296 | { |
| 1297 | return (u & 1) ? ((u >> 1) ^ ~0) : (u >> 1); |
| 1298 | } |
| 1299 | |
| 1300 | |
| 1301 | // Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in < 16 range, for |
| 1302 | // more compact varint encoding. This basically swaps rarely used op values that are < 16 with the |
| 1303 | // ones that are common. |
| 1304 | |
| 1305 | static SpvOp smolv_RemapOp(SpvOp op) |
| 1306 | { |
| 1307 | # define _SMOLV_SWAP_OP(op1,op2) if (op==op1) return op2; if (op==op2) return op1 |
| 1308 | _SMOLV_SWAP_OP(SpvOpDecorate,SpvOpNop); // 0: 24% |
| 1309 | _SMOLV_SWAP_OP(SpvOpLoad,SpvOpUndef); // 1: 17% |
| 1310 | _SMOLV_SWAP_OP(SpvOpStore,SpvOpSourceContinued); // 2: 9% |
| 1311 | _SMOLV_SWAP_OP(SpvOpAccessChain,SpvOpSource); // 3: 7.2% |
| 1312 | _SMOLV_SWAP_OP(SpvOpVectorShuffle,SpvOpSourceExtension); // 4: 5.0% |
| 1313 | // Name - already small enum value - 5: 4.4% |
| 1314 | // MemberName - already small enum value - 6: 2.9% |
| 1315 | _SMOLV_SWAP_OP(SpvOpMemberDecorate,SpvOpString); // 7: 4.0% |
| 1316 | _SMOLV_SWAP_OP(SpvOpLabel,SpvOpLine); // 8: 0.9% |
| 1317 | _SMOLV_SWAP_OP(SpvOpVariable,(SpvOp)9); // 9: 3.9% |
| 1318 | _SMOLV_SWAP_OP(SpvOpFMul,SpvOpExtension); // 10: 3.9% |
| 1319 | _SMOLV_SWAP_OP(SpvOpFAdd,SpvOpExtInstImport); // 11: 2.5% |
| 1320 | // ExtInst - already small enum value - 12: 1.2% |
| 1321 | // VectorShuffleCompact - already small enum value - used for compact shuffle encoding |
| 1322 | _SMOLV_SWAP_OP(SpvOpTypePointer,SpvOpMemoryModel); // 14: 2.2% |
| 1323 | _SMOLV_SWAP_OP(SpvOpFNegate,SpvOpEntryPoint); // 15: 1.1% |
| 1324 | # undef _SMOLV_SWAP_OP |
| 1325 | return op; |
| 1326 | } |
| 1327 | |
| 1328 | |
| 1329 | // For most compact varint encoding of common instructions, the instruction length should come out |
| 1330 | // into 3 bits (be <8). SPIR-V instruction lengths are always at least 1, and for some other |
| 1331 | // instructions they are guaranteed to be some other minimum length. Adjust the length before encoding, |
| 1332 | // and after decoding accordingly. |
| 1333 | |
| 1334 | static uint32_t smolv_EncodeLen(SpvOp op, uint32_t len) |
| 1335 | { |
| 1336 | len--; |
| 1337 | if (op == SpvOpVectorShuffle) len -= 4; |
| 1338 | if (op == SpvOpVectorShuffleCompact) len -= 4; |
| 1339 | if (op == SpvOpDecorate) len -= 2; |
| 1340 | if (op == SpvOpLoad) len -= 3; |
| 1341 | if (op == SpvOpAccessChain) len -= 3; |
| 1342 | return len; |
| 1343 | } |
| 1344 | |
| 1345 | static uint32_t smolv_DecodeLen(SpvOp op, uint32_t len) |
| 1346 | { |
| 1347 | len++; |
| 1348 | if (op == SpvOpVectorShuffle) len += 4; |
| 1349 | if (op == SpvOpVectorShuffleCompact) len += 4; |
| 1350 | if (op == SpvOpDecorate) len += 2; |
| 1351 | if (op == SpvOpLoad) len += 3; |
| 1352 | if (op == SpvOpAccessChain) len += 3; |
| 1353 | return len; |
| 1354 | } |
| 1355 | |
| 1356 | |
| 1357 | // Shuffling bits of length + opcode to be more compact in varint encoding in typical cases: |
| 1358 | // 0x LLLL OOOO is how SPIR-V encodes it (L=length, O=op), we shuffle into: |
| 1359 | // 0x LLLO OOLO, so that common case (op<16, len<8) is encoded into one byte. |
| 1360 | |
| 1361 | static bool smolv_WriteLengthOp(smolv::ByteArray& arr, uint32_t len, SpvOp op) |
| 1362 | { |
| 1363 | len = smolv_EncodeLen(op, len); |
| 1364 | // SPIR-V length field is 16 bits; if we get a larger value that means something |
| 1365 | // was wrong, e.g. a vector shuffle instruction with less than 4 words (and our |
| 1366 | // adjustment to common lengths in smolv_EncodeLen wrapped around) |
| 1367 | if (len > 0xFFFF) |
| 1368 | return false; |
| 1369 | op = smolv_RemapOp(op); |
| 1370 | uint32_t oplen = ((len >> 4) << 20) | ((op >> 4) << 8) | ((len & 0xF) << 4) | (op & 0xF); |
| 1371 | smolv_WriteVarint(arr, oplen); |
| 1372 | return true; |
| 1373 | } |
| 1374 | |
| 1375 | static bool smolv_ReadLengthOp(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outLen, SpvOp& outOp) |
| 1376 | { |
| 1377 | uint32_t val; |
| 1378 | if (!smolv_ReadVarint(data, dataEnd, val)) |
| 1379 | return false; |
| 1380 | outLen = ((val >> 20) << 4) | ((val >> 4) & 0xF); |
| 1381 | outOp = (SpvOp)(((val >> 4) & 0xFFF0) | (val & 0xF)); |
| 1382 | |
| 1383 | outOp = smolv_RemapOp(outOp); |
| 1384 | outLen = smolv_DecodeLen(outOp, outLen); |
| 1385 | return true; |
| 1386 | } |
| 1387 | |
| 1388 | |
| 1389 | |
| 1390 | #define _SMOLV_READ_OP(len, words, op) \ |
| 1391 | uint32_t len = words[0] >> 16; \ |
| 1392 | if (len < 1) return false; /* malformed instruction, length needs to be at least 1 */ \ |
| 1393 | if (words + len > wordsEnd) return false; /* malformed instruction, goes past end of data */ \ |
| 1394 | SpvOp op = (SpvOp)(words[0] & 0xFFFF) |
| 1395 | |
| 1396 | |
| 1397 | bool smolv::Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags, StripOpNameFilterFunc stripFilter) |
| 1398 | { |
| 1399 | const size_t wordCount = spirvSize / 4; |
| 1400 | if (wordCount * 4 != spirvSize) |
| 1401 | return false; |
| 1402 | const uint32_t* words = (const uint32_t*)spirvData; |
| 1403 | const uint32_t* wordsEnd = words + wordCount; |
| 1404 | if (!smolv_CheckSpirVHeader(words, wordCount)) |
| 1405 | return false; |
| 1406 | |
| 1407 | // reserve space in output (typical compression is to about 30%; reserve half of input space) |
| 1408 | outSmolv.reserve(outSmolv.size() + spirvSize/2); |
| 1409 | |
| 1410 | // header (matches SPIR-V one, except different magic) |
| 1411 | smolv_Write4(outSmolv, kSmolHeaderMagic); |
| 1412 | smolv_Write4(outSmolv, (words[1] & 0x00FFFFFF) + (kSmolCurrEncodingVersion<<24)); // SPIR-V version (_XXX) + SMOL-V version (X___) |
| 1413 | smolv_Write4(outSmolv, words[2]); // generator |
| 1414 | smolv_Write4(outSmolv, words[3]); // bound |
| 1415 | smolv_Write4(outSmolv, words[4]); // schema |
| 1416 | |
| 1417 | const size_t = outSmolv.size(); // size field may get updated later if stripping is enabled |
| 1418 | smolv_Write4(outSmolv, (uint32_t)spirvSize); // space needed to decode (i.e. original SPIR-V size) |
| 1419 | |
| 1420 | size_t strippedSpirvWordCount = wordCount; |
| 1421 | uint32_t prevResult = 0; |
| 1422 | uint32_t prevDecorate = 0; |
| 1423 | |
| 1424 | const int knownOpsCount = smolv_GetKnownOpsCount(kSmolCurrEncodingVersion); |
| 1425 | |
| 1426 | words += 5; |
| 1427 | while (words < wordsEnd) |
| 1428 | { |
| 1429 | _SMOLV_READ_OP(instrLen, words, op); |
| 1430 | |
| 1431 | if ((flags & kEncodeFlagStripDebugInfo) && smolv_OpDebugInfo(op, knownOpsCount)) |
| 1432 | { |
| 1433 | if (!stripFilter || op != SpvOpName || !stripFilter(reinterpret_cast<const char*>(&words[2]))) |
| 1434 | { |
| 1435 | strippedSpirvWordCount -= instrLen; |
| 1436 | words += instrLen; |
| 1437 | continue; |
| 1438 | } |
| 1439 | } |
| 1440 | |
| 1441 | // A usual case of vector shuffle, with less than 4 components, each with a value |
| 1442 | // in [0..3] range: encode it in a more compact form, with the swizzle pattern in one byte. |
| 1443 | // Turn this into a VectorShuffleCompact instruction, that takes up unused slot in Ops. |
| 1444 | uint32_t swizzle = 0; |
| 1445 | if (op == SpvOpVectorShuffle && instrLen <= 9) |
| 1446 | { |
| 1447 | uint32_t swz0 = instrLen > 5 ? words[5] : 0; |
| 1448 | uint32_t swz1 = instrLen > 6 ? words[6] : 0; |
| 1449 | uint32_t swz2 = instrLen > 7 ? words[7] : 0; |
| 1450 | uint32_t swz3 = instrLen > 8 ? words[8] : 0; |
| 1451 | if (swz0 < 4 && swz1 < 4 && swz2 < 4 && swz3 < 4) |
| 1452 | { |
| 1453 | op = SpvOpVectorShuffleCompact; |
| 1454 | swizzle = (swz0 << 6) | (swz1 << 4) | (swz2 << 2) | (swz3); |
| 1455 | } |
| 1456 | } |
| 1457 | |
| 1458 | // length + opcode |
| 1459 | if (!smolv_WriteLengthOp(outSmolv, instrLen, op)) |
| 1460 | return false; |
| 1461 | |
| 1462 | size_t ioffs = 1; |
| 1463 | // write type as varint, if we have it |
| 1464 | if (smolv_OpHasType(op, knownOpsCount)) |
| 1465 | { |
| 1466 | if (ioffs >= instrLen) |
| 1467 | return false; |
| 1468 | smolv_WriteVarint(outSmolv, words[ioffs]); |
| 1469 | ioffs++; |
| 1470 | } |
| 1471 | // write result as delta+zig+varint, if we have it |
| 1472 | if (smolv_OpHasResult(op, knownOpsCount)) |
| 1473 | { |
| 1474 | if (ioffs >= instrLen) |
| 1475 | return false; |
| 1476 | uint32_t v = words[ioffs]; |
| 1477 | smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevResult)); // some deltas are negative, use zig |
| 1478 | prevResult = v; |
| 1479 | ioffs++; |
| 1480 | } |
| 1481 | |
| 1482 | // Decorate & MemberDecorate: IDs relative to previous decorate |
| 1483 | if (op == SpvOpDecorate || op == SpvOpMemberDecorate) |
| 1484 | { |
| 1485 | if (ioffs >= instrLen) |
| 1486 | return false; |
| 1487 | uint32_t v = words[ioffs]; |
| 1488 | smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevDecorate)); // spirv-remapped deltas often negative, use zig |
| 1489 | prevDecorate = v; |
| 1490 | ioffs++; |
| 1491 | } |
| 1492 | |
| 1493 | // MemberDecorate special encoding: whole row of MemberDecorate instructions is often referring |
| 1494 | // to the same type and linearly increasing member indices. Scan ahead to see how many we have, |
| 1495 | // and encode whole bunch as one. |
| 1496 | if (op == SpvOpMemberDecorate) |
| 1497 | { |
| 1498 | // scan ahead until we reach end, non-member-decoration or different type |
| 1499 | const uint32_t decorationType = words[ioffs-1]; |
| 1500 | const uint32_t* memberWords = words; |
| 1501 | uint32_t prevIndex = 0; |
| 1502 | uint32_t prevOffset = 0; |
| 1503 | // write a byte on how many we have encoded as a bunch |
| 1504 | size_t countLocation = outSmolv.size(); |
| 1505 | outSmolv.push_back(0); |
| 1506 | int count = 0; |
| 1507 | while (memberWords < wordsEnd && count < 255) |
| 1508 | { |
| 1509 | _SMOLV_READ_OP(memberLen, memberWords, memberOp); |
| 1510 | if (memberOp != SpvOpMemberDecorate) |
| 1511 | break; |
| 1512 | if (memberLen < 4) |
| 1513 | return false; // invalid input |
| 1514 | if (memberWords[1] != decorationType) |
| 1515 | break; |
| 1516 | |
| 1517 | // write member index as delta from previous |
| 1518 | uint32_t memberIndex = memberWords[2]; |
| 1519 | smolv_WriteVarint(outSmolv, memberIndex - prevIndex); |
| 1520 | prevIndex = memberIndex; |
| 1521 | |
| 1522 | // decoration (and length if not common/known) |
| 1523 | uint32_t memberDec = memberWords[3]; |
| 1524 | smolv_WriteVarint(outSmolv, memberDec); |
| 1525 | const int = smolv_DecorationExtraOps(memberDec); |
| 1526 | if (knownExtraOps == -1) |
| 1527 | smolv_WriteVarint(outSmolv, memberLen-4); |
| 1528 | else if (unsigned(knownExtraOps) + 4 != memberLen) |
| 1529 | return false; // invalid input |
| 1530 | |
| 1531 | // Offset decorations are most often linearly increasing, so encode as deltas |
| 1532 | if (memberDec == 35) // Offset |
| 1533 | { |
| 1534 | if (memberLen != 5) |
| 1535 | return false; |
| 1536 | smolv_WriteVarint(outSmolv, memberWords[4]-prevOffset); |
| 1537 | prevOffset = memberWords[4]; |
| 1538 | } |
| 1539 | else |
| 1540 | { |
| 1541 | // write rest of decorations as varint |
| 1542 | for (uint32_t i = 4; i < memberLen; ++i) |
| 1543 | smolv_WriteVarint(outSmolv, memberWords[i]); |
| 1544 | } |
| 1545 | |
| 1546 | memberWords += memberLen; |
| 1547 | ++count; |
| 1548 | } |
| 1549 | outSmolv[countLocation] = uint8_t(count); |
| 1550 | words = memberWords; |
| 1551 | continue; |
| 1552 | } |
| 1553 | |
| 1554 | // Write out this many IDs, encoding them relative+zigzag to result ID |
| 1555 | int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount); |
| 1556 | for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs) |
| 1557 | { |
| 1558 | if (ioffs >= instrLen) |
| 1559 | return false; |
| 1560 | uint32_t delta = prevResult - words[ioffs]; |
| 1561 | // some deltas are negative (often on branches, or if program was processed by spirv-remap), |
| 1562 | // so use zig encoding |
| 1563 | smolv_WriteVarint(outSmolv, smolv_ZigEncode(delta)); |
| 1564 | } |
| 1565 | |
| 1566 | if (op == SpvOpVectorShuffleCompact) |
| 1567 | { |
| 1568 | // compact vector shuffle, just write out single swizzle byte |
| 1569 | outSmolv.push_back(uint8_t(swizzle)); |
| 1570 | ioffs = instrLen; |
| 1571 | } |
| 1572 | else if (smolv_OpVarRest(op, knownOpsCount)) |
| 1573 | { |
| 1574 | // write out rest of words with variable encoding (expected to be small integers) |
| 1575 | for (; ioffs < instrLen; ++ioffs) |
| 1576 | smolv_WriteVarint(outSmolv, words[ioffs]); |
| 1577 | } |
| 1578 | else |
| 1579 | { |
| 1580 | // write out rest of words without any encoding |
| 1581 | for (; ioffs < instrLen; ++ioffs) |
| 1582 | smolv_Write4(outSmolv, words[ioffs]); |
| 1583 | } |
| 1584 | |
| 1585 | words += instrLen; |
| 1586 | } |
| 1587 | |
| 1588 | if (strippedSpirvWordCount != wordCount) |
| 1589 | { |
| 1590 | uint8_t* = &outSmolv[headerSpirvSizeOffset]; |
| 1591 | smolv_Write4(headerSpirvSize, (uint32_t)strippedSpirvWordCount * 4); |
| 1592 | } |
| 1593 | |
| 1594 | return true; |
| 1595 | } |
| 1596 | |
| 1597 | |
| 1598 | size_t smolv::GetDecodedBufferSize(const void* smolvData, size_t smolvSize) |
| 1599 | { |
| 1600 | if (!smolv_CheckSmolHeader((const uint8_t*)smolvData, smolvSize)) |
| 1601 | return 0; |
| 1602 | const uint32_t* words = (const uint32_t*)smolvData; |
| 1603 | return words[5]; |
| 1604 | } |
| 1605 | |
| 1606 | |
| 1607 | bool smolv::Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags) |
| 1608 | { |
| 1609 | // check header, and whether we have enough output buffer space |
| 1610 | const size_t neededBufferSize = GetDecodedBufferSize(smolvData, smolvSize); |
| 1611 | if (neededBufferSize == 0) |
| 1612 | return false; // invalid SMOL-V |
| 1613 | if (spirvOutputBufferSize < neededBufferSize) |
| 1614 | return false; // not enough space in output buffer |
| 1615 | if (spirvOutputBuffer == NULL) |
| 1616 | return false; // output buffer is null |
| 1617 | |
| 1618 | const uint8_t* bytes = (const uint8_t*)smolvData; |
| 1619 | const uint8_t* bytesEnd = bytes + smolvSize; |
| 1620 | |
| 1621 | uint8_t* outSpirv = (uint8_t*)spirvOutputBuffer; |
| 1622 | |
| 1623 | uint32_t val; |
| 1624 | int smolVersion = 0; |
| 1625 | |
| 1626 | // header |
| 1627 | smolv_Write4(outSpirv, kSpirVHeaderMagic); bytes += 4; |
| 1628 | smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24; val &= 0x00FFFFFF; smolv_Write4(outSpirv, val); // version |
| 1629 | smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // generator |
| 1630 | smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // bound |
| 1631 | smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // schema |
| 1632 | bytes += 4; // decode buffer size |
| 1633 | |
| 1634 | // there are two SMOL-V encoding versions, both not indicating anything in their header version field: |
| 1635 | // one that is called "before zero" here (2016-08-31 code). Support decoding that one only by presence |
| 1636 | // of this special flag. |
| 1637 | const bool beforeZeroVersion = smolVersion == 0 && (flags & kDecodeFlagUse20160831AsZeroVersion) != 0; |
| 1638 | |
| 1639 | const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion); |
| 1640 | |
| 1641 | uint32_t prevResult = 0; |
| 1642 | uint32_t prevDecorate = 0; |
| 1643 | |
| 1644 | while (bytes < bytesEnd) |
| 1645 | { |
| 1646 | // read length + opcode |
| 1647 | uint32_t instrLen; |
| 1648 | SpvOp op; |
| 1649 | if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op)) |
| 1650 | return false; |
| 1651 | const bool wasSwizzle = (op == SpvOpVectorShuffleCompact); |
| 1652 | if (wasSwizzle) |
| 1653 | op = SpvOpVectorShuffle; |
| 1654 | smolv_Write4(outSpirv, (instrLen << 16) | op); |
| 1655 | |
| 1656 | size_t ioffs = 1; |
| 1657 | |
| 1658 | // read type as varint, if we have it |
| 1659 | if (smolv_OpHasType(op, knownOpsCount)) |
| 1660 | { |
| 1661 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1662 | smolv_Write4(outSpirv, val); |
| 1663 | ioffs++; |
| 1664 | } |
| 1665 | // read result as delta+varint, if we have it |
| 1666 | if (smolv_OpHasResult(op, knownOpsCount)) |
| 1667 | { |
| 1668 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1669 | val = prevResult + smolv_ZigDecode(val); |
| 1670 | smolv_Write4(outSpirv, val); |
| 1671 | prevResult = val; |
| 1672 | ioffs++; |
| 1673 | } |
| 1674 | |
| 1675 | // Decorate: IDs relative to previous decorate |
| 1676 | if (op == SpvOpDecorate || op == SpvOpMemberDecorate) |
| 1677 | { |
| 1678 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1679 | // "before zero" version did not use zig encoding for the value |
| 1680 | val = prevDecorate + (beforeZeroVersion ? val : smolv_ZigDecode(val)); |
| 1681 | smolv_Write4(outSpirv, val); |
| 1682 | prevDecorate = val; |
| 1683 | ioffs++; |
| 1684 | } |
| 1685 | |
| 1686 | // MemberDecorate special decoding |
| 1687 | if (op == SpvOpMemberDecorate && !beforeZeroVersion) |
| 1688 | { |
| 1689 | if (bytes >= bytesEnd) |
| 1690 | return false; // broken input |
| 1691 | int count = *bytes++; |
| 1692 | int prevIndex = 0; |
| 1693 | int prevOffset = 0; |
| 1694 | for (int m = 0; m < count; ++m) |
| 1695 | { |
| 1696 | // read member index |
| 1697 | uint32_t memberIndex; |
| 1698 | if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false; |
| 1699 | memberIndex += prevIndex; |
| 1700 | prevIndex = memberIndex; |
| 1701 | |
| 1702 | // decoration (and length if not common/known) |
| 1703 | uint32_t memberDec; |
| 1704 | if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false; |
| 1705 | const int = smolv_DecorationExtraOps(memberDec); |
| 1706 | uint32_t memberLen; |
| 1707 | if (knownExtraOps == -1) |
| 1708 | { |
| 1709 | if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false; |
| 1710 | memberLen += 4; |
| 1711 | } |
| 1712 | else |
| 1713 | memberLen = 4 + knownExtraOps; |
| 1714 | |
| 1715 | // write SPIR-V op+length (unless it's first member decoration, in which case it was written before) |
| 1716 | if (m != 0) |
| 1717 | { |
| 1718 | smolv_Write4(outSpirv, (memberLen << 16) | op); |
| 1719 | smolv_Write4(outSpirv, prevDecorate); |
| 1720 | } |
| 1721 | smolv_Write4(outSpirv, memberIndex); |
| 1722 | smolv_Write4(outSpirv, memberDec); |
| 1723 | // Special case for Offset decorations |
| 1724 | if (memberDec == 35) // Offset |
| 1725 | { |
| 1726 | if (memberLen != 5) |
| 1727 | return false; |
| 1728 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1729 | val += prevOffset; |
| 1730 | smolv_Write4(outSpirv, val); |
| 1731 | prevOffset = val; |
| 1732 | } |
| 1733 | else |
| 1734 | { |
| 1735 | for (uint32_t i = 4; i < memberLen; ++i) |
| 1736 | { |
| 1737 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1738 | smolv_Write4(outSpirv, val); |
| 1739 | } |
| 1740 | } |
| 1741 | } |
| 1742 | continue; |
| 1743 | } |
| 1744 | |
| 1745 | // Read this many IDs, that are relative to result ID |
| 1746 | int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount); |
| 1747 | // "before zero" version only used zig encoding for IDs of several ops; after |
| 1748 | // that ops got zig encoding for their IDs |
| 1749 | bool zigDecodeVals = true; |
| 1750 | if (beforeZeroVersion) |
| 1751 | { |
| 1752 | if (op != SpvOpControlBarrier && op != SpvOpMemoryBarrier && op != SpvOpLoopMerge && op != SpvOpSelectionMerge && op != SpvOpBranch && op != SpvOpBranchConditional && op != SpvOpMemoryNamedBarrier) |
| 1753 | zigDecodeVals = false; |
| 1754 | } |
| 1755 | for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs) |
| 1756 | { |
| 1757 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1758 | if (zigDecodeVals) |
| 1759 | val = smolv_ZigDecode(val); |
| 1760 | smolv_Write4(outSpirv, prevResult - val); |
| 1761 | } |
| 1762 | |
| 1763 | if (wasSwizzle && instrLen <= 9) |
| 1764 | { |
| 1765 | uint32_t swizzle = *bytes++; |
| 1766 | if (instrLen > 5) smolv_Write4(outSpirv, (swizzle >> 6) & 3); |
| 1767 | if (instrLen > 6) smolv_Write4(outSpirv, (swizzle >> 4) & 3); |
| 1768 | if (instrLen > 7) smolv_Write4(outSpirv, (swizzle >> 2) & 3); |
| 1769 | if (instrLen > 8) smolv_Write4(outSpirv, swizzle & 3); |
| 1770 | } |
| 1771 | else if (smolv_OpVarRest(op, knownOpsCount)) |
| 1772 | { |
| 1773 | // read rest of words with variable encoding |
| 1774 | for (; ioffs < instrLen; ++ioffs) |
| 1775 | { |
| 1776 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1777 | smolv_Write4(outSpirv, val); |
| 1778 | } |
| 1779 | } |
| 1780 | else |
| 1781 | { |
| 1782 | // read rest of words without any encoding |
| 1783 | for (; ioffs < instrLen; ++ioffs) |
| 1784 | { |
| 1785 | if (!smolv_Read4(bytes, bytesEnd, val)) return false; |
| 1786 | smolv_Write4(outSpirv, val); |
| 1787 | } |
| 1788 | } |
| 1789 | } |
| 1790 | |
| 1791 | if ((uint8_t*)spirvOutputBuffer + neededBufferSize != outSpirv) |
| 1792 | return false; // something went wrong during decoding? we should have decoded to exact output size |
| 1793 | |
| 1794 | return true; |
| 1795 | } |
| 1796 | |
| 1797 | |
| 1798 | |
| 1799 | // -------------------------------------------------------------------------------------------- |
| 1800 | // Calculating instruction count / space stats on SPIR-V and SMOL-V |
| 1801 | |
| 1802 | |
| 1803 | struct smolv::Stats |
| 1804 | { |
| 1805 | Stats() { memset(this, 0, sizeof(*this)); } |
| 1806 | size_t opCounts[kKnownOpsCount]; |
| 1807 | size_t opSizes[kKnownOpsCount]; |
| 1808 | size_t smolOpSizes[kKnownOpsCount]; |
| 1809 | size_t varintCountsOp[6]; |
| 1810 | size_t varintCountsType[6]; |
| 1811 | size_t varintCountsRes[6]; |
| 1812 | size_t varintCountsOther[6]; |
| 1813 | size_t totalOps; |
| 1814 | size_t totalSize; |
| 1815 | size_t totalSizeSmol; |
| 1816 | size_t inputCount; |
| 1817 | }; |
| 1818 | |
| 1819 | |
| 1820 | smolv::Stats* smolv::StatsCreate() |
| 1821 | { |
| 1822 | return new Stats(); |
| 1823 | } |
| 1824 | |
| 1825 | void smolv::StatsDelete(smolv::Stats *s) |
| 1826 | { |
| 1827 | delete s; |
| 1828 | } |
| 1829 | |
| 1830 | |
| 1831 | bool smolv::StatsCalculate(smolv::Stats* stats, const void* spirvData, size_t spirvSize) |
| 1832 | { |
| 1833 | if (!stats) |
| 1834 | return false; |
| 1835 | |
| 1836 | const size_t wordCount = spirvSize / 4; |
| 1837 | if (wordCount * 4 != spirvSize) |
| 1838 | return false; |
| 1839 | const uint32_t* words = (const uint32_t*)spirvData; |
| 1840 | const uint32_t* wordsEnd = words + wordCount; |
| 1841 | if (!smolv_CheckSpirVHeader(words, wordCount)) |
| 1842 | return false; |
| 1843 | words += 5; |
| 1844 | |
| 1845 | stats->inputCount++; |
| 1846 | stats->totalSize += wordCount; |
| 1847 | |
| 1848 | while (words < wordsEnd) |
| 1849 | { |
| 1850 | _SMOLV_READ_OP(instrLen, words, op); |
| 1851 | |
| 1852 | if (op < kKnownOpsCount) |
| 1853 | { |
| 1854 | stats->opCounts[op]++; |
| 1855 | stats->opSizes[op] += instrLen; |
| 1856 | } |
| 1857 | words += instrLen; |
| 1858 | stats->totalOps++; |
| 1859 | } |
| 1860 | |
| 1861 | return true; |
| 1862 | } |
| 1863 | |
| 1864 | |
| 1865 | bool smolv::StatsCalculateSmol(smolv::Stats* stats, const void* smolvData, size_t smolvSize) |
| 1866 | { |
| 1867 | if (!stats) |
| 1868 | return false; |
| 1869 | |
| 1870 | // debugging helper to dump all encoded bytes to stdout, keep at "if 0" |
| 1871 | # if 0 |
| 1872 | # define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() { \ |
| 1873 | printf("Op %-22s ", op < kKnownOpsCount ? kSpirvOpNames[op] : "???"); \ |
| 1874 | for (const uint8_t* b = instrBegin; b < bytes; ++b) \ |
| 1875 | printf("%02x ", *b); \ |
| 1876 | printf("\n"); \ |
| 1877 | } |
| 1878 | # else |
| 1879 | # define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() {} |
| 1880 | # endif |
| 1881 | |
| 1882 | const uint8_t* bytes = (const uint8_t*)smolvData; |
| 1883 | const uint8_t* bytesEnd = bytes + smolvSize; |
| 1884 | if (!smolv_CheckSmolHeader(bytes, smolvSize)) |
| 1885 | return false; |
| 1886 | |
| 1887 | uint32_t val; |
| 1888 | int smolVersion; |
| 1889 | bytes += 4; |
| 1890 | smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24; |
| 1891 | const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion); |
| 1892 | bytes += 16; |
| 1893 | |
| 1894 | stats->totalSizeSmol += smolvSize; |
| 1895 | |
| 1896 | while (bytes < bytesEnd) |
| 1897 | { |
| 1898 | const uint8_t* instrBegin = bytes; |
| 1899 | const uint8_t* varBegin; |
| 1900 | |
| 1901 | // read length + opcode |
| 1902 | uint32_t instrLen; |
| 1903 | SpvOp op; |
| 1904 | varBegin = bytes; |
| 1905 | if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op)) |
| 1906 | return false; |
| 1907 | const bool wasSwizzle = (op == SpvOpVectorShuffleCompact); |
| 1908 | if (wasSwizzle) |
| 1909 | op = SpvOpVectorShuffle; |
| 1910 | stats->varintCountsOp[bytes-varBegin]++; |
| 1911 | |
| 1912 | size_t ioffs = 1; |
| 1913 | if (smolv_OpHasType(op, knownOpsCount)) |
| 1914 | { |
| 1915 | varBegin = bytes; |
| 1916 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1917 | stats->varintCountsType[bytes-varBegin]++; |
| 1918 | ioffs++; |
| 1919 | } |
| 1920 | if (smolv_OpHasResult(op, knownOpsCount)) |
| 1921 | { |
| 1922 | varBegin = bytes; |
| 1923 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1924 | stats->varintCountsRes[bytes-varBegin]++; |
| 1925 | ioffs++; |
| 1926 | } |
| 1927 | |
| 1928 | if (op == SpvOpDecorate || op == SpvOpMemberDecorate) |
| 1929 | { |
| 1930 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1931 | ioffs++; |
| 1932 | } |
| 1933 | // MemberDecorate special decoding |
| 1934 | if (op == SpvOpMemberDecorate) |
| 1935 | { |
| 1936 | if (bytes >= bytesEnd) |
| 1937 | return false; // broken input |
| 1938 | int count = *bytes++; |
| 1939 | for (int m = 0; m < count; ++m) |
| 1940 | { |
| 1941 | uint32_t memberIndex; |
| 1942 | if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false; |
| 1943 | uint32_t memberDec; |
| 1944 | if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false; |
| 1945 | const int = smolv_DecorationExtraOps(memberDec); |
| 1946 | uint32_t memberLen; |
| 1947 | if (knownExtraOps == -1) |
| 1948 | { |
| 1949 | if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false; |
| 1950 | memberLen += 4; |
| 1951 | } |
| 1952 | else |
| 1953 | memberLen = 4 + knownExtraOps; |
| 1954 | for (uint32_t i = 4; i < memberLen; ++i) |
| 1955 | { |
| 1956 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1957 | } |
| 1958 | } |
| 1959 | stats->smolOpSizes[op] += bytes - instrBegin; |
| 1960 | _SMOLV_DEBUG_PRINT_ENCODED_BYTES(); |
| 1961 | continue; |
| 1962 | } |
| 1963 | |
| 1964 | int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount); |
| 1965 | for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs) |
| 1966 | { |
| 1967 | varBegin = bytes; |
| 1968 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1969 | stats->varintCountsRes[bytes-varBegin]++; |
| 1970 | } |
| 1971 | |
| 1972 | if (wasSwizzle && instrLen <= 9) |
| 1973 | { |
| 1974 | bytes++; |
| 1975 | } |
| 1976 | else if (smolv_OpVarRest(op, knownOpsCount)) |
| 1977 | { |
| 1978 | for (; ioffs < instrLen; ++ioffs) |
| 1979 | { |
| 1980 | varBegin = bytes; |
| 1981 | if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false; |
| 1982 | stats->varintCountsOther[bytes-varBegin]++; |
| 1983 | } |
| 1984 | } |
| 1985 | else |
| 1986 | { |
| 1987 | for (; ioffs < instrLen; ++ioffs) |
| 1988 | { |
| 1989 | if (!smolv_Read4(bytes, bytesEnd, val)) return false; |
| 1990 | } |
| 1991 | } |
| 1992 | |
| 1993 | if (op < kKnownOpsCount) |
| 1994 | { |
| 1995 | stats->smolOpSizes[op] += bytes - instrBegin; |
| 1996 | } |
| 1997 | _SMOLV_DEBUG_PRINT_ENCODED_BYTES(); |
| 1998 | } |
| 1999 | |
| 2000 | return true; |
| 2001 | } |
| 2002 | |
| 2003 | static bool (std::pair<SpvOp,size_t> a, std::pair<SpvOp,size_t> b) |
| 2004 | { |
| 2005 | return a.second > b.second; |
| 2006 | } |
| 2007 | |
| 2008 | void smolv::StatsPrint(const Stats* stats) |
| 2009 | { |
| 2010 | if (!stats) |
| 2011 | return; |
| 2012 | |
| 2013 | typedef std::pair<SpvOp,size_t> OpCounter; |
| 2014 | OpCounter counts[kKnownOpsCount]; |
| 2015 | OpCounter sizes[kKnownOpsCount]; |
| 2016 | OpCounter sizesSmol[kKnownOpsCount]; |
| 2017 | for (int i = 0; i < kKnownOpsCount; ++i) |
| 2018 | { |
| 2019 | counts[i].first = (SpvOp)i; |
| 2020 | counts[i].second = stats->opCounts[i]; |
| 2021 | sizes[i].first = (SpvOp)i; |
| 2022 | sizes[i].second = stats->opSizes[i]; |
| 2023 | sizesSmol[i].first = (SpvOp)i; |
| 2024 | sizesSmol[i].second = stats->smolOpSizes[i]; |
| 2025 | } |
| 2026 | std::sort(counts, counts + kKnownOpsCount, CompareOpCounters); |
| 2027 | std::sort(sizes, sizes + kKnownOpsCount, CompareOpCounters); |
| 2028 | std::sort(sizesSmol, sizesSmol + kKnownOpsCount, CompareOpCounters); |
| 2029 | |
| 2030 | 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); |
| 2031 | printf("Most occuring ops:\n" ); |
| 2032 | for (int i = 0; i < 30; ++i) |
| 2033 | { |
| 2034 | SpvOp op = counts[i].first; |
| 2035 | 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); |
| 2036 | } |
| 2037 | printf("Largest total size of ops:\n" ); |
| 2038 | for (int i = 0; i < 30; ++i) |
| 2039 | { |
| 2040 | SpvOp op = sizes[i].first; |
| 2041 | printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n" , |
| 2042 | i, |
| 2043 | kSpirvOpNames[op], |
| 2044 | (int)sizes[i].second*4, |
| 2045 | (float)sizes[i].second / (float)stats->totalSize * 100.0f, |
| 2046 | (float)sizes[i].second*4 / (float)stats->opCounts[op] |
| 2047 | ); |
| 2048 | } |
| 2049 | printf("SMOL varint encoding counts per byte length:\n" ); |
| 2050 | printf(" B: %6s %6s %6s %6s\n" , "Op" , "Type" , "Result" , "Other" ); |
| 2051 | for (int i = 1; i < 6; ++i) |
| 2052 | { |
| 2053 | printf(" %i: %6i %6i %6i %6i\n" , i, (int)stats->varintCountsOp[i], (int)stats->varintCountsType[i], (int)stats->varintCountsRes[i], (int)stats->varintCountsOther[i]); |
| 2054 | } |
| 2055 | printf("Largest total size of ops in SMOL:\n" ); |
| 2056 | for (int i = 0; i < 30; ++i) |
| 2057 | { |
| 2058 | SpvOp op = sizesSmol[i].first; |
| 2059 | printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n" , |
| 2060 | i, |
| 2061 | kSpirvOpNames[op], |
| 2062 | (int)sizesSmol[i].second, |
| 2063 | (float)sizesSmol[i].second / (float)stats->totalSizeSmol * 100.0f, |
| 2064 | (float)sizesSmol[i].second / (float)stats->opCounts[op] |
| 2065 | ); |
| 2066 | } |
| 2067 | } |
| 2068 | |
| 2069 | |
| 2070 | // ------------------------------------------------------------------------------ |
| 2071 | // This software is available under 2 licenses -- choose whichever you prefer. |
| 2072 | // ------------------------------------------------------------------------------ |
| 2073 | // ALTERNATIVE A - MIT License |
| 2074 | // Copyright (c) 2016-2020 Aras Pranckevicius |
| 2075 | // Permission is hereby granted, free of charge, to any person obtaining a copy of |
| 2076 | // this software and associated documentation files (the "Software"), to deal in |
| 2077 | // the Software without restriction, including without limitation the rights to |
| 2078 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
| 2079 | // of the Software, and to permit persons to whom the Software is furnished to do |
| 2080 | // so, subject to the following conditions: |
| 2081 | // The above copyright notice and this permission notice shall be included in all |
| 2082 | // copies or substantial portions of the Software. |
| 2083 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 2084 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 2085 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 2086 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 2087 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 2088 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 2089 | // SOFTWARE. |
| 2090 | // ------------------------------------------------------------------------------ |
| 2091 | // ALTERNATIVE B - Public Domain (www.unlicense.org) |
| 2092 | // This is free and unencumbered software released into the public domain. |
| 2093 | // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this |
| 2094 | // software, either in source code form or as a compiled binary, for any purpose, |
| 2095 | // commercial or non-commercial, and by any means. |
| 2096 | // In jurisdictions that recognize copyright laws, the author or authors of this |
| 2097 | // software dedicate any and all copyright interest in the software to the public |
| 2098 | // domain. We make this dedication for the benefit of the public at large and to |
| 2099 | // the detriment of our heirs and successors. We intend this dedication to be an |
| 2100 | // overt act of relinquishment in perpetuity of all present and future rights to |
| 2101 | // this software under copyright law. |
| 2102 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 2103 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 2104 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 2105 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 2106 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 2107 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 2108 | // ------------------------------------------------------------------------------ |
| 2109 | |