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 | |