mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-25 04:50:04 +00:00
Initial support for SPV_KHR_integer_dot_product (#4327)
* Initial support for SPV_KHR_integer_dot_product - Adds new operand types for packed-vector-format - Moves ray tracing enums to the end - PackedVectorFormat is a new optional operand type, so it requires special handling in grammar table generation. - Add SPV_KHR_integer_dot_product to optimizer whitelists. - Pass-through validation: valid cases pass validation Validation errors are not checked. - Update SPIRV-Headers Patch by David Neto <dneto@google.com> Rebase and minor tweaks by Kevin Petit <kevin.petit@arm.com> Signed-off-by: David Neto <dneto@google.com> Signed-off-by: Kevin Petit <kevin.petit@arm.com> Change-Id: Icb41741cb7f0f1063e5541ce25e5ba6c02266d2c * format fixes Change-Id: I35c82ec27bded3d1b62373fa6daec3ffd91105a3
This commit is contained in:
parent
e992c96c89
commit
e065c482c6
2
DEPS
2
DEPS
@ -6,7 +6,7 @@ vars = {
|
|||||||
'effcee_revision': '2ec8f8738118cc483b67c04a759fee53496c5659',
|
'effcee_revision': '2ec8f8738118cc483b67c04a759fee53496c5659',
|
||||||
'googletest_revision': 'b7d472f1225c5a64943821d8483fecb469d3f382',
|
'googletest_revision': 'b7d472f1225c5a64943821d8483fecb469d3f382',
|
||||||
're2_revision': 'f8e389f3acdc2517562924239e2a188037393683',
|
're2_revision': 'f8e389f3acdc2517562924239e2a188037393683',
|
||||||
'spirv_headers_revision': '07f259e68af3a540038fa32df522554e74f53ed5',
|
'spirv_headers_revision': 'f95c3b3761ee1b1903f54ae69b526ed6f0edc3b9',
|
||||||
}
|
}
|
||||||
|
|
||||||
deps = {
|
deps = {
|
||||||
|
@ -113,6 +113,9 @@ typedef enum spv_endianness_t {
|
|||||||
// Sometimes we also need to be able to express the fact that an operand
|
// Sometimes we also need to be able to express the fact that an operand
|
||||||
// is a member of an optional tuple of values. In that case the first member
|
// is a member of an optional tuple of values. In that case the first member
|
||||||
// would be optional, and the subsequent members would be required.
|
// would be optional, and the subsequent members would be required.
|
||||||
|
//
|
||||||
|
// NOTE: Although we don't promise binary compatibility, as a courtesy, please
|
||||||
|
// add new enum values at the end.
|
||||||
typedef enum spv_operand_type_t {
|
typedef enum spv_operand_type_t {
|
||||||
// A sentinel value.
|
// A sentinel value.
|
||||||
SPV_OPERAND_TYPE_NONE = 0,
|
SPV_OPERAND_TYPE_NONE = 0,
|
||||||
@ -167,12 +170,8 @@ typedef enum spv_operand_type_t {
|
|||||||
SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS, // SPIR-V Sec 3.29
|
SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS, // SPIR-V Sec 3.29
|
||||||
SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO, // SPIR-V Sec 3.30
|
SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO, // SPIR-V Sec 3.30
|
||||||
SPV_OPERAND_TYPE_CAPABILITY, // SPIR-V Sec 3.31
|
SPV_OPERAND_TYPE_CAPABILITY, // SPIR-V Sec 3.31
|
||||||
SPV_OPERAND_TYPE_RAY_FLAGS, // SPIR-V Sec 3.RF
|
|
||||||
SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION, // SPIR-V Sec 3.RQIntersection
|
// NOTE: New concrete enum values should be added at the end.
|
||||||
SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE, // SPIR-V Sec
|
|
||||||
// 3.RQCommitted
|
|
||||||
SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE, // SPIR-V Sec
|
|
||||||
// 3.RQCandidate
|
|
||||||
|
|
||||||
// Set 5: Operands that are a single word bitmask.
|
// Set 5: Operands that are a single word bitmask.
|
||||||
// Sometimes a set bit indicates the instruction requires still more operands.
|
// Sometimes a set bit indicates the instruction requires still more operands.
|
||||||
@ -184,7 +183,10 @@ typedef enum spv_operand_type_t {
|
|||||||
SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26
|
SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26
|
||||||
SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR
|
SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR
|
||||||
|
|
||||||
// The remaining operand types are only used internally by the assembler.
|
// NOTE: New concrete enum values should be added at the end.
|
||||||
|
|
||||||
|
// The "optional" and "variable" operand types are only used internally by
|
||||||
|
// the assembler and the binary parser.
|
||||||
// There are two categories:
|
// There are two categories:
|
||||||
// Optional : expands to 0 or 1 operand, like ? in regular expressions.
|
// Optional : expands to 0 or 1 operand, like ? in regular expressions.
|
||||||
// Variable : expands to 0, 1 or many operands or pairs of operands.
|
// Variable : expands to 0, 1 or many operands or pairs of operands.
|
||||||
@ -269,6 +271,20 @@ typedef enum spv_operand_type_t {
|
|||||||
// A value enum from https://github.com/KhronosGroup/SPIRV-Headers/pull/177
|
// A value enum from https://github.com/KhronosGroup/SPIRV-Headers/pull/177
|
||||||
SPV_OPERAND_TYPE_OVERFLOW_MODES,
|
SPV_OPERAND_TYPE_OVERFLOW_MODES,
|
||||||
|
|
||||||
|
// Concrete operand types for the provisional Vulkan ray tracing feature.
|
||||||
|
SPV_OPERAND_TYPE_RAY_FLAGS, // SPIR-V Sec 3.RF
|
||||||
|
SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION, // SPIR-V Sec 3.RQIntersection
|
||||||
|
SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE, // SPIR-V Sec
|
||||||
|
// 3.RQCommitted
|
||||||
|
SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE, // SPIR-V Sec
|
||||||
|
// 3.RQCandidate
|
||||||
|
|
||||||
|
// Concrete operand types for integer dot product.
|
||||||
|
// Packed vector format
|
||||||
|
SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT, // SPIR-V Sec 3.x
|
||||||
|
// An optional packed vector format
|
||||||
|
SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT,
|
||||||
|
|
||||||
// This is a sentinel value, and does not represent an operand type.
|
// This is a sentinel value, and does not represent an operand type.
|
||||||
// It should come last.
|
// It should come last.
|
||||||
SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
|
SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
|
||||||
|
@ -659,12 +659,16 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
|||||||
case SPV_OPERAND_TYPE_FPDENORM_MODE:
|
case SPV_OPERAND_TYPE_FPDENORM_MODE:
|
||||||
case SPV_OPERAND_TYPE_FPOPERATION_MODE:
|
case SPV_OPERAND_TYPE_FPOPERATION_MODE:
|
||||||
case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
|
case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
|
||||||
case SPV_OPERAND_TYPE_OVERFLOW_MODES: {
|
case SPV_OPERAND_TYPE_OVERFLOW_MODES:
|
||||||
|
case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
|
||||||
|
case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: {
|
||||||
// A single word that is a plain enum value.
|
// A single word that is a plain enum value.
|
||||||
|
|
||||||
// Map an optional operand type to its corresponding concrete type.
|
// Map an optional operand type to its corresponding concrete type.
|
||||||
if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
|
if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
|
||||||
parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
|
parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
|
||||||
|
if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT)
|
||||||
|
parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT;
|
||||||
|
|
||||||
spv_operand_desc entry;
|
spv_operand_desc entry;
|
||||||
if (grammar_.lookupOperand(type, word, &entry)) {
|
if (grammar_.lookupOperand(type, word, &entry)) {
|
||||||
|
@ -347,7 +347,17 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst,
|
|||||||
EmitMaskOperand(operand.type, word);
|
EmitMaskOperand(operand.type, word);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false && "unhandled or invalid case");
|
if (spvOperandIsConcreteMask(operand.type)) {
|
||||||
|
EmitMaskOperand(operand.type, word);
|
||||||
|
} else if (spvOperandIsConcrete(operand.type)) {
|
||||||
|
spv_operand_desc entry;
|
||||||
|
if (grammar_.lookupOperand(operand.type, word, &entry))
|
||||||
|
assert(false && "should have caught this earlier");
|
||||||
|
stream_ << entry->name;
|
||||||
|
} else {
|
||||||
|
assert(false && "unhandled or invalid case");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ResetColor();
|
ResetColor();
|
||||||
}
|
}
|
||||||
|
@ -229,6 +229,9 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
|
|||||||
return "ray query committed intersection type";
|
return "ray query committed intersection type";
|
||||||
case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
|
case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
|
||||||
return "ray query candidate intersection type";
|
return "ray query candidate intersection type";
|
||||||
|
case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
|
||||||
|
case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
|
||||||
|
return "packed vector format";
|
||||||
case SPV_OPERAND_TYPE_IMAGE:
|
case SPV_OPERAND_TYPE_IMAGE:
|
||||||
case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
|
case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
|
||||||
return "image";
|
return "image";
|
||||||
@ -361,6 +364,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) {
|
|||||||
case SPV_OPERAND_TYPE_FPOPERATION_MODE:
|
case SPV_OPERAND_TYPE_FPOPERATION_MODE:
|
||||||
case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
|
case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
|
||||||
case SPV_OPERAND_TYPE_OVERFLOW_MODES:
|
case SPV_OPERAND_TYPE_OVERFLOW_MODES:
|
||||||
|
case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -396,6 +400,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) {
|
|||||||
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
||||||
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
|
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
|
||||||
case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
|
case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
|
||||||
|
case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
|
||||||
case SPV_OPERAND_TYPE_OPTIONAL_CIV:
|
case SPV_OPERAND_TYPE_OPTIONAL_CIV:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -998,6 +998,7 @@ void AggressiveDCEPass::InitExtensions() {
|
|||||||
"SPV_KHR_shader_clock",
|
"SPV_KHR_shader_clock",
|
||||||
"SPV_KHR_vulkan_memory_model",
|
"SPV_KHR_vulkan_memory_model",
|
||||||
"SPV_KHR_subgroup_uniform_control_flow",
|
"SPV_KHR_subgroup_uniform_control_flow",
|
||||||
|
"SPV_KHR_integer_dot_product",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,6 +419,7 @@ void LocalAccessChainConvertPass::InitExtensions() {
|
|||||||
"SPV_EXT_fragment_invocation_density",
|
"SPV_EXT_fragment_invocation_density",
|
||||||
"SPV_KHR_terminate_invocation",
|
"SPV_KHR_terminate_invocation",
|
||||||
"SPV_KHR_subgroup_uniform_control_flow",
|
"SPV_KHR_subgroup_uniform_control_flow",
|
||||||
|
"SPV_KHR_integer_dot_product",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +271,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
|
|||||||
"SPV_EXT_physical_storage_buffer",
|
"SPV_EXT_physical_storage_buffer",
|
||||||
"SPV_KHR_terminate_invocation",
|
"SPV_KHR_terminate_invocation",
|
||||||
"SPV_KHR_subgroup_uniform_control_flow",
|
"SPV_KHR_subgroup_uniform_control_flow",
|
||||||
|
"SPV_KHR_integer_dot_product",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +124,7 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() {
|
|||||||
"SPV_EXT_physical_storage_buffer",
|
"SPV_EXT_physical_storage_buffer",
|
||||||
"SPV_KHR_terminate_invocation",
|
"SPV_KHR_terminate_invocation",
|
||||||
"SPV_KHR_subgroup_uniform_control_flow",
|
"SPV_KHR_subgroup_uniform_control_flow",
|
||||||
|
"SPV_KHR_integer_dot_product",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
|
bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
|
||||||
|
@ -952,5 +952,71 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
{1, SpvExecutionModeSubgroupUniformControlFlowKHR})},
|
{1, SpvExecutionModeSubgroupUniformControlFlowKHR})},
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
// SPV_KHR_integer_dot_product
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
SPV_KHR_integer_dot_product, ExtensionRoundTripTest,
|
||||||
|
Combine(
|
||||||
|
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
|
||||||
|
SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
|
||||||
|
ValuesIn(std::vector<AssemblyCase>{
|
||||||
|
{"OpExtension \"SPV_KHR_integer_dot_product\"\n",
|
||||||
|
MakeInstruction(SpvOpExtension,
|
||||||
|
MakeVector("SPV_KHR_integer_dot_product"))},
|
||||||
|
{"OpCapability DotProductInputAllKHR\n",
|
||||||
|
MakeInstruction(SpvOpCapability,
|
||||||
|
{SpvCapabilityDotProductInputAllKHR})},
|
||||||
|
{"OpCapability DotProductInput4x8BitKHR\n",
|
||||||
|
MakeInstruction(SpvOpCapability,
|
||||||
|
{SpvCapabilityDotProductInput4x8BitKHR})},
|
||||||
|
{"OpCapability DotProductInput4x8BitPackedKHR\n",
|
||||||
|
MakeInstruction(SpvOpCapability,
|
||||||
|
{SpvCapabilityDotProductInput4x8BitPackedKHR})},
|
||||||
|
{"OpCapability DotProductKHR\n",
|
||||||
|
MakeInstruction(SpvOpCapability, {SpvCapabilityDotProductKHR})},
|
||||||
|
{"%2 = OpSDotKHR %1 %3 %4\n",
|
||||||
|
MakeInstruction(SpvOpSDotKHR, {1, 2, 3, 4})},
|
||||||
|
{"%2 = OpSDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
|
||||||
|
MakeInstruction(
|
||||||
|
SpvOpSDotKHR,
|
||||||
|
{1, 2, 3, 4,
|
||||||
|
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
|
||||||
|
{"%2 = OpUDotKHR %1 %3 %4\n",
|
||||||
|
MakeInstruction(SpvOpUDotKHR, {1, 2, 3, 4})},
|
||||||
|
{"%2 = OpUDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
|
||||||
|
MakeInstruction(
|
||||||
|
SpvOpUDotKHR,
|
||||||
|
{1, 2, 3, 4,
|
||||||
|
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
|
||||||
|
{"%2 = OpSUDotKHR %1 %3 %4\n",
|
||||||
|
MakeInstruction(SpvOpSUDotKHR, {1, 2, 3, 4})},
|
||||||
|
{"%2 = OpSUDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
|
||||||
|
MakeInstruction(
|
||||||
|
SpvOpSUDotKHR,
|
||||||
|
{1, 2, 3, 4,
|
||||||
|
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
|
||||||
|
{"%2 = OpSDotAccSatKHR %1 %3 %4 %5\n",
|
||||||
|
MakeInstruction(SpvOpSDotAccSatKHR, {1, 2, 3, 4, 5})},
|
||||||
|
{"%2 = OpSDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
|
||||||
|
MakeInstruction(
|
||||||
|
SpvOpSDotAccSatKHR,
|
||||||
|
{1, 2, 3, 4, 5,
|
||||||
|
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
|
||||||
|
{"%2 = OpUDotAccSatKHR %1 %3 %4 %5\n",
|
||||||
|
MakeInstruction(SpvOpUDotAccSatKHR, {1, 2, 3, 4, 5})},
|
||||||
|
{"%2 = OpUDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
|
||||||
|
MakeInstruction(
|
||||||
|
SpvOpUDotAccSatKHR,
|
||||||
|
{1, 2, 3, 4, 5,
|
||||||
|
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
|
||||||
|
{"%2 = OpSUDotAccSatKHR %1 %3 %4 %5\n",
|
||||||
|
MakeInstruction(SpvOpSUDotAccSatKHR, {1, 2, 3, 4, 5})},
|
||||||
|
{"%2 = OpSUDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
|
||||||
|
MakeInstruction(
|
||||||
|
SpvOpSUDotAccSatKHR,
|
||||||
|
{1, 2, 3, 4, 5,
|
||||||
|
SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
|
||||||
|
})));
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
@ -41,6 +41,7 @@ add_spvtools_unittest(TARGET val_abcde
|
|||||||
val_extension_spv_khr_expect_assume.cpp
|
val_extension_spv_khr_expect_assume.cpp
|
||||||
val_extension_spv_khr_linkonce_odr.cpp
|
val_extension_spv_khr_linkonce_odr.cpp
|
||||||
val_extension_spv_khr_subgroup_uniform_control_flow.cpp
|
val_extension_spv_khr_subgroup_uniform_control_flow.cpp
|
||||||
|
val_extension_spv_khr_integer_dot_product.cpp
|
||||||
val_extension_spv_khr_terminate_invocation.cpp
|
val_extension_spv_khr_terminate_invocation.cpp
|
||||||
val_ext_inst_test.cpp
|
val_ext_inst_test.cpp
|
||||||
${VAL_TEST_COMMON_SRCS}
|
${VAL_TEST_COMMON_SRCS}
|
||||||
|
1330
test/val/val_extension_spv_khr_integer_dot_product.cpp
Normal file
1330
test/val/val_extension_spv_khr_integer_dot_product.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -523,17 +523,17 @@ def generate_operand_kind_table(enums):
|
|||||||
enums = [generate_enum_operand_kind(e, exts) for e in enums]
|
enums = [generate_enum_operand_kind(e, exts) for e in enums]
|
||||||
exts_arrays = generate_extension_arrays(exts)
|
exts_arrays = generate_extension_arrays(exts)
|
||||||
|
|
||||||
# We have three operand kinds that requires their optional counterpart to
|
# We have a few operand kinds that require their optional counterpart to
|
||||||
# exist in the operand info table.
|
# exist in the operand info table.
|
||||||
three_optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess']
|
optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat']
|
||||||
three_optional_enums = [e for e in enums if e[0] in three_optional_enums]
|
optional_enums = [e for e in enums if e[0] in optional_enums]
|
||||||
enums.extend(three_optional_enums)
|
enums.extend(optional_enums)
|
||||||
|
|
||||||
enum_kinds, enum_names, enum_entries = zip(*enums)
|
enum_kinds, enum_names, enum_entries = zip(*enums)
|
||||||
# Mark the last three as optional ones.
|
# Mark the last few as optional ones.
|
||||||
enum_quantifiers = [''] * (len(enums) - 3) + ['?'] * 3
|
enum_quantifiers = [''] * (len(enums) - len(optional_enums)) + ['?'] * len(optional_enums)
|
||||||
# And we don't want redefinition of them.
|
# And we don't want redefinition of them.
|
||||||
enum_entries = enum_entries[:-3]
|
enum_entries = enum_entries[:-len(optional_enums)]
|
||||||
enum_kinds = [convert_operand_kind(e)
|
enum_kinds = [convert_operand_kind(e)
|
||||||
for e in zip(enum_kinds, enum_quantifiers)]
|
for e in zip(enum_kinds, enum_quantifiers)]
|
||||||
table_entries = zip(enum_kinds, enum_names, enum_names)
|
table_entries = zip(enum_kinds, enum_names, enum_names)
|
||||||
|
Loading…
Reference in New Issue
Block a user