VirtualBox

source: vbox/trunk/src/libs/dxvk-2.3.1/include/spirv/tools/buildHeaders/jsonToSpirv.cpp

最後變更 在這個檔案是 105107,由 vboxsync 提交於 9 月 前

libs/dxvk-2.3.1: Make it build, bugref:10716

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 36.2 KB
 
1// Copyright (c) 2014-2024 The Khronos Group Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and/or associated documentation files (the "Materials"),
5// to deal in the Materials without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Materials, and to permit persons to whom the
8// Materials are furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Materials.
12//
13// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
14// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
15// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
16//
17// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
23// IN THE MATERIALS.
24
25#include <assert.h>
26#include <string.h>
27#include <algorithm>
28#include <cstdlib>
29#include <iostream>
30#include <unordered_map>
31#include <unordered_set>
32#include <utility>
33#include <fstream>
34
35#include "jsoncpp/dist/json/json.h"
36
37#include "jsonToSpirv.h"
38
39namespace {
40// Returns true if the given string is a valid SPIR-V version.
41bool validSpirvVersionString(const std::string s) {
42 return
43 s == "1.0" ||
44 s == "1.1" ||
45 s == "1.2" ||
46 s == "1.3" ||
47 s == "1.4" ||
48 s == "1.5" ||
49 s == "1.6";
50}
51
52// Returns true if the given string is a valid version
53// specifier in the grammar file.
54bool validSpirvVersionStringSpecifier(const std::string s) {
55 return s == "None" || validSpirvVersionString(s);
56}
57} // anonymous namespace
58
59namespace spv {
60
61bool IsLegacyDoublyEnabledInstruction(const std::string& instruction) {
62 static std::unordered_set<std::string> allowed = {
63 "OpSubgroupBallotKHR",
64 "OpSubgroupFirstInvocationKHR",
65 "OpSubgroupAllKHR",
66 "OpSubgroupAnyKHR",
67 "OpSubgroupAllEqualKHR",
68 "OpSubgroupReadInvocationKHR",
69 "OpTraceRayKHR",
70 "OpExecuteCallableKHR",
71 "OpConvertUToAccelerationStructureKHR",
72 "OpIgnoreIntersectionKHR",
73 "OpTerminateRayKHR",
74 "OpTypeRayQueryKHR",
75 "OpRayQueryInitializeKHR",
76 "OpRayQueryTerminateKHR",
77 "OpRayQueryGenerateIntersectionKHR",
78 "OpRayQueryConfirmIntersectionKHR",
79 "OpRayQueryProceedKHR",
80 "OpRayQueryGetIntersectionTypeKHR",
81 "OpGroupIAddNonUniformAMD",
82 "OpGroupFAddNonUniformAMD",
83 "OpGroupFMinNonUniformAMD",
84 "OpGroupUMinNonUniformAMD",
85 "OpGroupSMinNonUniformAMD",
86 "OpGroupFMaxNonUniformAMD",
87 "OpGroupUMaxNonUniformAMD",
88 "OpGroupSMaxNonUniformAMD",
89 "OpFragmentMaskFetchAMD",
90 "OpFragmentFetchAMD",
91 "OpImageSampleFootprintNV",
92 "OpGroupNonUniformPartitionNV",
93 "OpWritePackedPrimitiveIndices4x8NV",
94 "OpReportIntersectionNV",
95 "OpReportIntersectionKHR",
96 "OpIgnoreIntersectionNV",
97 "OpTerminateRayNV",
98 "OpTraceNV",
99 "OpTraceMotionNV",
100 "OpTraceRayMotionNV",
101 "OpTypeAccelerationStructureNV",
102 "OpTypeAccelerationStructureKHR",
103 "OpExecuteCallableNV",
104 "OpTypeCooperativeMatrixNV",
105 "OpCooperativeMatrixLoadNV",
106 "OpCooperativeMatrixStoreNV",
107 "OpCooperativeMatrixMulAddNV",
108 "OpCooperativeMatrixLengthNV",
109 "OpBeginInvocationInterlockEXT",
110 "OpEndInvocationInterlockEXT",
111 "OpIsHelperInvocationEXT",
112 "OpConstantFunctionPointerINTEL",
113 "OpFunctionPointerCallINTEL",
114 "OpAssumeTrueKHR",
115 "OpExpectKHR",
116 "OpLoopControlINTEL",
117 "OpAliasDomainDeclINTEL",
118 "OpAliasScopeDeclINTEL",
119 "OpAliasScopeListDeclINTEL",
120 "OpReadPipeBlockingINTEL",
121 "OpWritePipeBlockingINTEL",
122 "OpFPGARegINTEL",
123 "OpRayQueryGetRayTMinKHR",
124 "OpRayQueryGetRayFlagsKHR",
125 "OpRayQueryGetIntersectionTKHR",
126 "OpRayQueryGetIntersectionInstanceCustomIndexKHR",
127 "OpRayQueryGetIntersectionInstanceIdKHR",
128 "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR",
129 "OpRayQueryGetIntersectionGeometryIndexKHR",
130 "OpRayQueryGetIntersectionPrimitiveIndexKHR",
131 "OpRayQueryGetIntersectionBarycentricsKHR",
132 "OpRayQueryGetIntersectionFrontFaceKHR",
133 "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR",
134 "OpRayQueryGetIntersectionObjectRayDirectionKHR",
135 "OpRayQueryGetIntersectionObjectRayOriginKHR",
136 "OpRayQueryGetWorldRayDirectionKHR",
137 "OpRayQueryGetWorldRayOriginKHR",
138 "OpRayQueryGetIntersectionObjectToWorldKHR",
139 "OpRayQueryGetIntersectionWorldToObjectKHR",
140 "OpAtomicFAddEXT",
141 };
142 return allowed.count(instruction) != 0;
143}
144
145bool EnumValue::IsValid(OperandClass oc, const std::string& context) const
146{
147 bool result = true;
148 if (firstVersion.empty()) {
149 std::cerr << "Error: " << context << " " << name << " \"version\" must be set, probably to \"None\"" << std::endl;
150 result = false;
151 } else if (!validSpirvVersionStringSpecifier(firstVersion)) {
152 std::cerr << "Error: " << context << " " << name << " \"version\" is invalid: " << firstVersion << std::endl;
153 result = false;
154 }
155 if (!lastVersion.empty() && !validSpirvVersionString(lastVersion)) {
156 std::cerr << "Error: " << context << " " << name << " \"lastVersion\" is invalid: " << lastVersion << std::endl;
157 result = false;
158 }
159
160 // When a feature is introduced by an extension, the firstVersion is set to
161 // "None". There are three cases:
162 // - A new capability should be guarded/enabled by the extension
163 // - A new instruction should be:
164 // - Guarded/enabled by a new capability.
165 // - Not enabled by *both* a capability and an extension.
166 // There are many existing instructions that are already like this,
167 // and we grandparent them as allowed.
168 // - Other enums fall into two cases:
169 // 1. The enum is part of a new operand kind introduced by the extension.
170 // In this case we rely on transitivity: The use of the operand occurs
171 // in a new instruction that itself is guarded; or as the operand of
172 // another operand that itself is (recursively) guarded.
173 // 2. The enum is a new case in an existing operand kind. This case
174 // should be guarded by a capability. However, we do not check this
175 // here. Checking it requires more context than we have here.
176 if (oc == OperandOpcode) {
177 const bool instruction_unusable =
178 (firstVersion == "None") && extensions.empty() && capabilities.empty();
179 if (instruction_unusable) {
180 std::cerr << "Error: " << context << " " << name << " is not usable: "
181 << "its version is set to \"None\", and it is not enabled by a "
182 << "capability or extension. Guard it with a capability."
183 << std::endl;
184 result = false;
185 }
186 // Complain if an instruction is not in any core version and also enabled by
187 // both an extension and a capability.
188 // It's important to check the "not in any core version" case, because,
189 // for example, OpTerminateInvocation is in SPIR-V 1.6 *and* enabled by an
190 // extension, and guarded by the Shader capability.
191 const bool instruction_doubly_enabled = (firstVersion == "None") &&
192 !extensions.empty() &&
193 !capabilities.empty();
194 if (instruction_doubly_enabled && !IsLegacyDoublyEnabledInstruction(name)) {
195 std::cerr << "Error: " << context << " " << name << " is doubly-enabled: "
196 << "it is enabled by both a capability and an extension. "
197 << "Guard it with a capability only." << std::endl;
198 result = false;
199 }
200 }
201 if (oc == OperandCapability) {
202 // If capability X lists capabilities Y and Z, then Y and Z are *enabled*
203 // when X is enabled. They are not *guards* on X's use.
204 // Only versions and extensions can guard a capability.
205 const bool capability_unusable =
206 (firstVersion == "None") && extensions.empty();
207 if (capability_unusable) {
208 std::cerr << "Error: " << context << " " << name << " is not usable: "
209 << "its version is set to \"None\", and it is not enabled by "
210 << "an extension. Guard it with an extension." << std::endl;
211 result = false;
212 }
213 }
214
215 return result;
216}
217
218// The set of objects that hold all the instruction/operand
219// parameterization information.
220InstructionValues InstructionDesc;
221
222// The ordered list (in printing order) of printing classes
223// (specification subsections).
224PrintingClasses InstructionPrintingClasses;
225
226// Note: There is no entry for OperandOpcode. Use InstructionDesc instead.
227EnumDefinition OperandClassParams[OperandOpcode];
228EnumValues SourceLanguageParams;
229EnumValues ExecutionModelParams;
230EnumValues AddressingParams;
231EnumValues MemoryParams;
232EnumValues ExecutionModeParams;
233EnumValues StorageParams;
234EnumValues SamplerAddressingModeParams;
235EnumValues SamplerFilterModeParams;
236EnumValues ImageFormatParams;
237EnumValues ImageChannelOrderParams;
238EnumValues ImageChannelDataTypeParams;
239EnumValues ImageOperandsParams;
240EnumValues FPFastMathParams;
241EnumValues FPRoundingModeParams;
242EnumValues FPDenormModeParams;
243EnumValues FPOperationModeParams;
244EnumValues QuantizationModesParams;
245EnumValues OverflowModesParams;
246EnumValues LinkageTypeParams;
247EnumValues DecorationParams;
248EnumValues BuiltInParams;
249EnumValues DimensionalityParams;
250EnumValues FuncParamAttrParams;
251EnumValues AccessQualifierParams;
252EnumValues GroupOperationParams;
253EnumValues LoopControlParams;
254EnumValues SelectionControlParams;
255EnumValues FunctionControlParams;
256EnumValues MemorySemanticsParams;
257EnumValues MemoryAccessParams;
258EnumValues ScopeParams;
259EnumValues KernelEnqueueFlagsParams;
260EnumValues KernelProfilingInfoParams;
261EnumValues CapabilityParams;
262EnumValues RayFlagsParams;
263EnumValues RayQueryIntersectionParams;
264EnumValues RayQueryCommittedIntersectionTypeParams;
265EnumValues RayQueryCandidateIntersectionTypeParams;
266EnumValues FragmentShadingRateParams;
267EnumValues PackedVectorFormatParams;
268EnumValues CooperativeMatrixOperandsParams;
269EnumValues CooperativeMatrixLayoutParams;
270EnumValues CooperativeMatrixUseParams;
271EnumValues InitializationModeQualifierParams;
272EnumValues HostAccessQualifierParams;
273EnumValues LoadCacheControlParams;
274EnumValues StoreCacheControlParams;
275EnumValues NamedMaximumNumberOfRegistersParams;
276EnumValues RawAccessChainOperandsParams;
277
278std::pair<bool, std::string> ReadFile(const std::string& path)
279{
280 std::ifstream fstream(path, std::ios::in);
281 if (fstream) {
282 std::string contents;
283 fstream.seekg(0, std::ios::end);
284 contents.reserve((unsigned int)fstream.tellg());
285 fstream.seekg(0, std::ios::beg);
286 contents.assign((std::istreambuf_iterator<char>(fstream)),
287 std::istreambuf_iterator<char>());
288 return std::make_pair(true, contents);
289 }
290 return std::make_pair(false, "");
291}
292
293struct ClassOptionality {
294 OperandClass type;
295 bool optional;
296};
297
298// Converts the |operandKind| and |quantifier| pair used to describe operands
299// in the JSON grammar to OperandClass and optionality used in this repo.
300ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, const std::string& quantifier)
301{
302 assert(quantifier.empty() || quantifier == "?" || quantifier == "*");
303
304 if (operandKind == "IdRef") {
305 if (quantifier.empty())
306 return {OperandId, false};
307 else if (quantifier == "?")
308 return {OperandId, true};
309 else
310 return {OperandVariableIds, false};
311 } else if (operandKind == "LiteralInteger") {
312 if (quantifier.empty())
313 return {OperandLiteralNumber, false};
314 if (quantifier == "?")
315 return {OperandOptionalLiteral, true};
316 else
317 return {OperandVariableLiterals, false};
318 } else if (operandKind == "LiteralString") {
319 if (quantifier.empty())
320 return {OperandLiteralString, false};
321 else if (quantifier == "?")
322 return {OperandLiteralString, true};
323 else {
324 return {OperandOptionalLiteralStrings, false};
325 }
326 } else if (operandKind == "PairLiteralIntegerIdRef") {
327 // Used by OpSwitch in the grammar
328 return {OperandVariableLiteralId, false};
329 } else if (operandKind == "PairIdRefLiteralInteger") {
330 // Used by OpGroupMemberDecorate in the grammar
331 return {OperandVariableIdLiteral, false};
332 } else if (operandKind == "PairIdRefIdRef") {
333 // Used by OpPhi in the grammar
334 return {OperandVariableIds, false};
335 } else {
336 OperandClass type = OperandNone;
337 if (operandKind == "IdMemorySemantics" || operandKind == "MemorySemantics") {
338 type = OperandMemorySemantics;
339 } else if (operandKind == "IdScope" || operandKind == "Scope") {
340 type = OperandScope;
341 } else if (operandKind == "LiteralExtInstInteger") {
342 type = OperandLiteralNumber;
343 } else if (operandKind == "LiteralSpecConstantOpInteger") {
344 type = OperandLiteralNumber;
345 } else if (operandKind == "LiteralContextDependentNumber") {
346 type = OperandAnySizeLiteralNumber;
347 } else if (operandKind == "LiteralFloat") {
348 type = OperandLiteralNumber;
349 } else if (operandKind == "SourceLanguage") {
350 type = OperandSource;
351 } else if (operandKind == "ExecutionModel") {
352 type = OperandExecutionModel;
353 } else if (operandKind == "AddressingModel") {
354 type = OperandAddressing;
355 } else if (operandKind == "MemoryModel") {
356 type = OperandMemory;
357 } else if (operandKind == "ExecutionMode") {
358 type = OperandExecutionMode;
359 } else if (operandKind == "StorageClass") {
360 type = OperandStorage;
361 } else if (operandKind == "Dim") {
362 type = OperandDimensionality;
363 } else if (operandKind == "SamplerAddressingMode") {
364 type = OperandSamplerAddressingMode;
365 } else if (operandKind == "SamplerFilterMode") {
366 type = OperandSamplerFilterMode;
367 } else if (operandKind == "ImageFormat") {
368 type = OperandSamplerImageFormat;
369 } else if (operandKind == "ImageChannelOrder") {
370 type = OperandImageChannelOrder;
371 } else if (operandKind == "ImageChannelDataType") {
372 type = OperandImageChannelDataType;
373 } else if (operandKind == "FPRoundingMode") {
374 type = OperandFPRoundingMode;
375 } else if (operandKind == "FPDenormMode") {
376 type = OperandFPDenormMode;
377 } else if (operandKind == "FPOperationMode") {
378 type = OperandFPOperationMode;
379 } else if (operandKind == "QuantizationModes") {
380 type = OperandQuantizationModes;
381 } else if (operandKind == "OverflowModes") {
382 type = OperandOverflowModes;
383 } else if (operandKind == "LinkageType") {
384 type = OperandLinkageType;
385 } else if (operandKind == "AccessQualifier") {
386 type = OperandAccessQualifier;
387 } else if (operandKind == "FunctionParameterAttribute") {
388 type = OperandFuncParamAttr;
389 } else if (operandKind == "Decoration") {
390 type = OperandDecoration;
391 } else if (operandKind == "BuiltIn") {
392 type = OperandBuiltIn;
393 } else if (operandKind == "GroupOperation") {
394 type = OperandGroupOperation;
395 } else if (operandKind == "KernelEnqueueFlags") {
396 type = OperandKernelEnqueueFlags;
397 } else if (operandKind == "KernelProfilingInfo") {
398 type = OperandKernelProfilingInfo;
399 } else if (operandKind == "Capability") {
400 type = OperandCapability;
401 } else if (operandKind == "ImageOperands") {
402 type = OperandImageOperands;
403 } else if (operandKind == "FPFastMathMode") {
404 type = OperandFPFastMath;
405 } else if (operandKind == "SelectionControl") {
406 type = OperandSelect;
407 } else if (operandKind == "LoopControl") {
408 type = OperandLoop;
409 } else if (operandKind == "FunctionControl") {
410 type = OperandFunction;
411 } else if (operandKind == "MemoryAccess") {
412 type = OperandMemoryOperands;
413 } else if (operandKind == "RayFlags") {
414 type = OperandRayFlags;
415 } else if (operandKind == "RayQueryIntersection") {
416 type = OperandRayQueryIntersection;
417 } else if (operandKind == "RayQueryCommittedIntersectionType") {
418 type = OperandRayQueryCommittedIntersectionType;
419 } else if (operandKind == "RayQueryCandidateIntersectionType") {
420 type = OperandRayQueryCandidateIntersectionType;
421 } else if (operandKind == "FragmentShadingRate") {
422 type = OperandFragmentShadingRate;
423 } else if (operandKind == "PackedVectorFormat") {
424 type = OperandPackedVectorFormat;
425 } else if (operandKind == "CooperativeMatrixOperands") {
426 type = OperandCooperativeMatrixOperands;
427 } else if (operandKind == "CooperativeMatrixLayout") {
428 type = OperandCooperativeMatrixLayout;
429 } else if (operandKind == "CooperativeMatrixUse") {
430 type = OperandCooperativeMatrixUse;
431 } else if (operandKind == "InitializationModeQualifier") {
432 type = OperandInitializationModeQualifier;
433 } else if (operandKind == "HostAccessQualifier") {
434 type = OperandHostAccessQualifier;
435 } else if (operandKind == "LoadCacheControl") {
436 type = OperandLoadCacheControl;
437 } else if (operandKind == "StoreCacheControl") {
438 type = OperandStoreCacheControl;
439 } else if (operandKind == "NamedMaximumNumberOfRegisters") {
440 type = OperandNamedMaximumNumberOfRegisters;
441 } else if (operandKind == "RawAccessChainOperands") {
442 type = OperandRawAccessChainOperands;
443 }
444
445 if (type == OperandNone) {
446 std::cerr << "Unhandled operand kind found: " << operandKind << std::endl;
447 exit(1);
448 }
449 return {type, !quantifier.empty()};
450 }
451}
452
453bool IsTypeOrResultId(const std::string& str, bool* isType, bool* isResult)
454{
455 if (str == "IdResultType")
456 return *isType = true;
457 if (str == "IdResult")
458 return *isResult = true;
459 return false;
460}
461
462// Given a number string, returns the position of the only bits set in the number.
463// So it requires the number is a power of two.
464unsigned int NumberStringToBit(const std::string& str)
465{
466 char* parseEnd;
467 unsigned int value = (unsigned int)std::strtol(str.c_str(), &parseEnd, 16);
468 assert(!(value & (value - 1)) && "input number is not a power of 2");
469 unsigned int bit = 0;
470 for (; value; value >>= 1) ++bit;
471 return bit;
472}
473
474void jsonToSpirv(const std::string& jsonPath, bool buildingHeaders)
475{
476 // only do this once.
477 static bool initialized = false;
478 if (initialized)
479 return;
480 initialized = true;
481
482 size_t errorCount = 0;
483
484 // Read the JSON grammar file.
485 bool fileReadOk = false;
486 std::string content;
487 std::tie(fileReadOk, content) = ReadFile(jsonPath);
488 if (!fileReadOk) {
489 std::cerr << "Failed to read JSON grammar file: "
490 << jsonPath << std::endl;
491 exit(1);
492 }
493
494 // Decode the JSON grammar file.
495 Json::Reader reader;
496 Json::Value root;
497 if (!reader.parse(content, root)) {
498 std::cerr << "Failed to parse JSON grammar:\n"
499 << reader.getFormattedErrorMessages();
500 exit(1);
501 }
502
503 // Layouts for all instructions.
504
505 // A lambda for returning capabilities from a JSON object as strings.
506 const auto getCaps = [](const Json::Value& object) {
507 EnumCaps result;
508 const auto& caps = object["capabilities"];
509 if (!caps.empty()) {
510 assert(caps.isArray());
511 for (const auto& cap : caps) {
512 result.emplace_back(cap.asString());
513 }
514 }
515 return result;
516 };
517
518 // A lambda for returning extensions from a JSON object as strings.
519 const auto getExts = [](const Json::Value& object) {
520 Extensions result;
521 const auto& exts = object["extensions"];
522 if (!exts.empty()) {
523 assert(exts.isArray());
524 for (const auto& ext : exts) {
525 result.emplace_back(ext.asString());
526 }
527 }
528 return result;
529 };
530
531 // set up the printing classes
532 std::unordered_set<std::string> tags; // short-lived local for error checking below
533 const Json::Value printingClasses = root["instruction_printing_class"];
534 for (const auto& printingClass : printingClasses) {
535 if (printingClass["tag"].asString().size() > 0)
536 tags.insert(printingClass["tag"].asString()); // just for error checking
537 else {
538 std::cerr << "Error: each instruction_printing_class requires a non-empty \"tag\"" << std::endl;
539 std::exit(1);
540 }
541 if (buildingHeaders || printingClass["tag"].asString() != "@exclude") {
542 InstructionPrintingClasses.push_back({printingClass["tag"].asString(),
543 printingClass["heading"].asString()});
544 }
545 }
546
547 // process the instructions
548 const Json::Value insts = root["instructions"];
549 unsigned maxOpcode = 0;
550 bool firstOpcode = true;
551 for (const auto& inst : insts) {
552 const auto printingClass = inst["class"].asString();
553 if (printingClass.size() == 0) {
554 std::cerr << "Error: " << inst["opname"].asString()
555 << " requires a non-empty printing \"class\" tag" << std::endl;
556 std::exit(1);
557 }
558 if (!buildingHeaders && printingClass == "@exclude")
559 continue;
560 if (tags.find(printingClass) == tags.end()) {
561 std::cerr << "Error: " << inst["opname"].asString()
562 << " requires a \"class\" declared as a \"tag\" in \"instruction printing_class\""
563 << std::endl;
564 std::exit(1);
565 }
566 const auto opcode = inst["opcode"].asUInt();
567 const std::string name = inst["opname"].asString();
568 if (firstOpcode) {
569 maxOpcode = opcode;
570 firstOpcode = false;
571 } else {
572 if (maxOpcode > opcode) {
573 std::cerr << "Error: " << name
574 << " is out of order. It follows the instruction with opcode " << maxOpcode
575 << std::endl;
576 std::exit(1);
577 } else {
578 maxOpcode = opcode;
579 }
580 }
581 EnumCaps caps = getCaps(inst);
582 std::string version = inst["version"].asString();
583 std::string lastVersion = inst["lastVersion"].asString();
584 Extensions exts = getExts(inst);
585 OperandParameters operands;
586 bool defResultId = false;
587 bool defTypeId = false;
588 for (const auto& operand : inst["operands"]) {
589 const std::string kind = operand["kind"].asString();
590 const std::string quantifier = operand.get("quantifier", "").asString();
591 const std::string doc = operand.get("name", "").asString();
592 if (!IsTypeOrResultId(kind, &defTypeId, &defResultId)) {
593 const auto p = ToOperandClassAndOptionality(kind, quantifier);
594 operands.push(p.type, doc, p.optional);
595 }
596 }
597 InstructionDesc.emplace_back(
598 std::move(EnumValue(opcode, name,
599 std::move(caps), std::move(version), std::move(lastVersion), std::move(exts),
600 std::move(operands))),
601 printingClass, defTypeId, defResultId);
602 if (!InstructionDesc.back().IsValid(OperandOpcode, "instruction")) {
603 errorCount++;
604 }
605 }
606
607 // Specific additional context-dependent operands
608
609 // Populate dest with EnumValue objects constructed from source.
610 const auto populateEnumValues = [&getCaps,&getExts,&errorCount](EnumValues* dest, const Json::Value& source, bool bitEnum) {
611 // A lambda for determining the numeric value to be used for a given
612 // enumerant in JSON form, and whether that value is a 0 in a bitfield.
613 auto getValue = [&bitEnum](const Json::Value& enumerant) {
614 std::pair<unsigned, bool> result{0u,false};
615 if (!bitEnum) {
616 result.first = enumerant["value"].asUInt();
617 } else {
618 const unsigned int bit = NumberStringToBit(enumerant["value"].asString());
619 if (bit == 0)
620 result.second = true;
621 else
622 result.first = bit - 1; // This is the *shift* amount.
623 }
624 return result;
625 };
626
627 unsigned maxValue = 0;
628 bool firstValue = true;
629 for (const auto& enumerant : source["enumerants"]) {
630 unsigned value;
631 bool skip_zero_in_bitfield;
632 std::tie(value, skip_zero_in_bitfield) = getValue(enumerant);
633 if (skip_zero_in_bitfield)
634 continue;
635 if (firstValue) {
636 maxValue = value;
637 firstValue = false;
638 } else {
639 if (maxValue > value) {
640 std::cerr << "Error: " << source["kind"] << " enumerant " << enumerant["enumerant"]
641 << " is out of order. It has value " << value
642 << " but follows the enumerant with value " << maxValue << std::endl;
643 std::exit(1);
644 } else {
645 maxValue = value;
646 }
647 }
648 EnumCaps caps(getCaps(enumerant));
649 std::string version = enumerant["version"].asString();
650 std::string lastVersion = enumerant["lastVersion"].asString();
651 Extensions exts(getExts(enumerant));
652 OperandParameters params;
653 const Json::Value& paramsJson = enumerant["parameters"];
654 if (!paramsJson.empty()) { // This enumerant has parameters.
655 assert(paramsJson.isArray());
656 for (const auto& param : paramsJson) {
657 const std::string kind = param["kind"].asString();
658 const std::string doc = param.get("name", "").asString();
659 const auto p = ToOperandClassAndOptionality(kind, ""); // All parameters are required!
660 params.push(p.type, doc);
661 }
662 }
663 dest->emplace_back(
664 value, enumerant["enumerant"].asString(),
665 std::move(caps), std::move(version), std::move(lastVersion), std::move(exts), std::move(params));
666 }
667 };
668
669 const auto establishOperandClass = [&populateEnumValues,&errorCount](
670 const std::string& enumName, spv::OperandClass operandClass,
671 spv::EnumValues* enumValues, const Json::Value& operandEnum, const std::string& category) {
672 assert(category == "BitEnum" || category == "ValueEnum");
673 bool bitEnum = (category == "BitEnum");
674 if (!operandEnum["version"].empty()) {
675 std::cerr << "Error: container for " << enumName << " operand_kind must not have a version field" << std::endl;
676 errorCount++;
677 }
678 populateEnumValues(enumValues, operandEnum, bitEnum);
679 const std::string errContext = "enum " + enumName;
680 for (const auto& e: *enumValues) {
681 if (!e.IsValid(operandClass, errContext)) {
682 errorCount++;
683 }
684 }
685 OperandClassParams[operandClass].set(enumName, enumValues, bitEnum);
686 };
687
688 const Json::Value operandEnums = root["operand_kinds"];
689 for (const auto& operandEnum : operandEnums) {
690 const std::string enumName = operandEnum["kind"].asString();
691 const std::string category = operandEnum["category"].asString();
692 if (enumName == "SourceLanguage") {
693 establishOperandClass(enumName, OperandSource, &SourceLanguageParams, operandEnum, category);
694 } else if (enumName == "Decoration") {
695 establishOperandClass(enumName, OperandDecoration, &DecorationParams, operandEnum, category);
696 } else if (enumName == "ExecutionMode") {
697 establishOperandClass(enumName, OperandExecutionMode, &ExecutionModeParams, operandEnum, category);
698 } else if (enumName == "Capability") {
699 establishOperandClass(enumName, OperandCapability, &CapabilityParams, operandEnum, category);
700 } else if (enumName == "AddressingModel") {
701 establishOperandClass(enumName, OperandAddressing, &AddressingParams, operandEnum, category);
702 } else if (enumName == "MemoryModel") {
703 establishOperandClass(enumName, OperandMemory, &MemoryParams, operandEnum, category);
704 } else if (enumName == "MemorySemantics") {
705 establishOperandClass(enumName, OperandMemorySemantics, &MemorySemanticsParams, operandEnum, category);
706 } else if (enumName == "ExecutionModel") {
707 establishOperandClass(enumName, OperandExecutionModel, &ExecutionModelParams, operandEnum, category);
708 } else if (enumName == "StorageClass") {
709 establishOperandClass(enumName, OperandStorage, &StorageParams, operandEnum, category);
710 } else if (enumName == "SamplerAddressingMode") {
711 establishOperandClass(enumName, OperandSamplerAddressingMode, &SamplerAddressingModeParams, operandEnum, category);
712 } else if (enumName == "SamplerFilterMode") {
713 establishOperandClass(enumName, OperandSamplerFilterMode, &SamplerFilterModeParams, operandEnum, category);
714 } else if (enumName == "ImageFormat") {
715 establishOperandClass(enumName, OperandSamplerImageFormat, &ImageFormatParams, operandEnum, category);
716 } else if (enumName == "ImageChannelOrder") {
717 establishOperandClass(enumName, OperandImageChannelOrder, &ImageChannelOrderParams, operandEnum, category);
718 } else if (enumName == "ImageChannelDataType") {
719 establishOperandClass(enumName, OperandImageChannelDataType, &ImageChannelDataTypeParams, operandEnum, category);
720 } else if (enumName == "ImageOperands") {
721 establishOperandClass(enumName, OperandImageOperands, &ImageOperandsParams, operandEnum, category);
722 } else if (enumName == "FPFastMathMode") {
723 establishOperandClass(enumName, OperandFPFastMath, &FPFastMathParams, operandEnum, category);
724 } else if (enumName == "FPRoundingMode") {
725 establishOperandClass(enumName, OperandFPRoundingMode, &FPRoundingModeParams, operandEnum, category);
726 } else if (enumName == "FPDenormMode") {
727 establishOperandClass(enumName, OperandFPDenormMode, &FPDenormModeParams, operandEnum, category);
728 } else if (enumName == "FPOperationMode") {
729 establishOperandClass(enumName, OperandFPOperationMode, &FPOperationModeParams, operandEnum, category);
730 } else if (enumName == "QuantizationModes") {
731 establishOperandClass(enumName, OperandQuantizationModes, &QuantizationModesParams, operandEnum, category);
732 } else if (enumName == "OverflowModes") {
733 establishOperandClass(enumName, OperandOverflowModes, &OverflowModesParams, operandEnum, category);
734 } else if (enumName == "LinkageType") {
735 establishOperandClass(enumName, OperandLinkageType, &LinkageTypeParams, operandEnum, category);
736 } else if (enumName == "FunctionParameterAttribute") {
737 establishOperandClass(enumName, OperandFuncParamAttr, &FuncParamAttrParams, operandEnum, category);
738 } else if (enumName == "AccessQualifier") {
739 establishOperandClass(enumName, OperandAccessQualifier, &AccessQualifierParams, operandEnum, category);
740 } else if (enumName == "BuiltIn") {
741 establishOperandClass(enumName, OperandBuiltIn, &BuiltInParams, operandEnum, category);
742 } else if (enumName == "SelectionControl") {
743 establishOperandClass(enumName, OperandSelect, &SelectionControlParams, operandEnum, category);
744 } else if (enumName == "LoopControl") {
745 establishOperandClass(enumName, OperandLoop, &LoopControlParams, operandEnum, category);
746 } else if (enumName == "FunctionControl") {
747 establishOperandClass(enumName, OperandFunction, &FunctionControlParams, operandEnum, category);
748 } else if (enumName == "Dim") {
749 establishOperandClass(enumName, OperandDimensionality, &DimensionalityParams, operandEnum, category);
750 } else if (enumName == "MemoryAccess") {
751 establishOperandClass(enumName, OperandMemoryOperands, &MemoryAccessParams, operandEnum, category);
752 } else if (enumName == "Scope") {
753 establishOperandClass(enumName, OperandScope, &ScopeParams, operandEnum, category);
754 } else if (enumName == "GroupOperation") {
755 establishOperandClass(enumName, OperandGroupOperation, &GroupOperationParams, operandEnum, category);
756 } else if (enumName == "KernelEnqueueFlags") {
757 establishOperandClass(enumName, OperandKernelEnqueueFlags, &KernelEnqueueFlagsParams, operandEnum, category);
758 } else if (enumName == "KernelProfilingInfo") {
759 establishOperandClass(enumName, OperandKernelProfilingInfo, &KernelProfilingInfoParams, operandEnum, category);
760 } else if (enumName == "RayFlags") {
761 establishOperandClass(enumName, OperandRayFlags, &RayFlagsParams, operandEnum, category);
762 } else if (enumName == "RayQueryIntersection") {
763 establishOperandClass(enumName, OperandRayQueryIntersection, &RayQueryIntersectionParams, operandEnum, category);
764 } else if (enumName == "RayQueryCommittedIntersectionType") {
765 establishOperandClass(enumName, OperandRayQueryCommittedIntersectionType, &RayQueryCommittedIntersectionTypeParams, operandEnum, category);
766 } else if (enumName == "RayQueryCandidateIntersectionType") {
767 establishOperandClass(enumName, OperandRayQueryCandidateIntersectionType, &RayQueryCandidateIntersectionTypeParams, operandEnum, category);
768 } else if (enumName == "FragmentShadingRate") {
769 establishOperandClass(enumName, OperandFragmentShadingRate, &FragmentShadingRateParams, operandEnum, category);
770 } else if (enumName == "PackedVectorFormat") {
771 establishOperandClass(enumName, OperandPackedVectorFormat, &PackedVectorFormatParams, operandEnum, category);
772 } else if (enumName == "CooperativeMatrixOperands") {
773 establishOperandClass(enumName, OperandCooperativeMatrixOperands, &CooperativeMatrixOperandsParams, operandEnum, category);
774 } else if (enumName == "CooperativeMatrixLayout") {
775 establishOperandClass(enumName, OperandCooperativeMatrixLayout, &CooperativeMatrixLayoutParams, operandEnum, category);
776 } else if (enumName == "CooperativeMatrixUse") {
777 establishOperandClass(enumName, OperandCooperativeMatrixUse, &CooperativeMatrixUseParams, operandEnum, category);
778 } else if (enumName == "InitializationModeQualifier") {
779 establishOperandClass(enumName, OperandInitializationModeQualifier, &InitializationModeQualifierParams, operandEnum, category);
780 } else if (enumName == "HostAccessQualifier") {
781 establishOperandClass(enumName, OperandHostAccessQualifier, &HostAccessQualifierParams, operandEnum, category);
782 } else if (enumName == "LoadCacheControl") {
783 establishOperandClass(enumName, OperandLoadCacheControl, &LoadCacheControlParams, operandEnum, category);
784 } else if (enumName == "StoreCacheControl") {
785 establishOperandClass(enumName, OperandStoreCacheControl, &StoreCacheControlParams, operandEnum, category);
786 } else if (enumName == "NamedMaximumNumberOfRegisters") {
787 establishOperandClass(enumName, OperandNamedMaximumNumberOfRegisters, &NamedMaximumNumberOfRegistersParams, operandEnum, category);
788 } else if (enumName == "RawAccessChainOperands") {
789 establishOperandClass(enumName, OperandRawAccessChainOperands, &RawAccessChainOperandsParams, operandEnum, category);
790 }
791 }
792
793 if (errorCount > 0) {
794 std::exit(1);
795 }
796}
797
798}; // end namespace spv
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette