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