Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/misc/smolv.cpp
9903 views
1
// smol-v - public domain - https://github.com/aras-p/smol-v
2
// authored 2016-2024 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
SpvOpVectorExtractDynamic = 77,
95
SpvOpVectorInsertDynamic = 78,
96
SpvOpVectorShuffle = 79,
97
SpvOpCompositeConstruct = 80,
98
SpvOpCompositeExtract = 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
SpvOpBitFieldSExtract = 202,
214
SpvOpBitFieldUExtract = 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
SpvOpGroupNonUniformBallotBitExtract = 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 smolv_DecorationExtraOps(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 smolv_CheckGenericHeader(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 headerMagic = words[0];
1197
if (headerMagic != expectedMagic)
1198
return false;
1199
uint32_t headerVersion = words[1] & versionMask;
1200
if (headerVersion < 0x00010000 || headerVersion > 0x00010600)
1201
return false; // only support 1.0 through 1.6
1202
1203
return true;
1204
}
1205
1206
static const int kSpirVHeaderMagic = 0x07230203;
1207
static const int kSmolHeaderMagic = 0x534D4F4C; // "SMOL"
1208
1209
static const int kSmolCurrEncodingVersion = 1;
1210
1211
static bool smolv_CheckSpirVHeader(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 smolv_CheckSmolHeader(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 headerSpirvSizeOffset = 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 knownExtraOps = 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* headerSpirvSize = &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 knownExtraOps = 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 knownExtraOps = 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 CompareOpCounters (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-2024 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
2110