mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-21 19:20:07 +00:00
Handle aliases field in the grammar (#5799)
* Modify static table generation scripts to include alias lists * Modify spv_opcode_desc_t and spv_operand_desc_t to include aliases * Modify opcode and operand lookup by name to also search aliases * update vim syntax generator
This commit is contained in:
parent
4310fd4eda
commit
fcf994a619
2
DEPS
2
DEPS
@ -14,7 +14,7 @@ vars = {
|
||||
|
||||
're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca',
|
||||
|
||||
'spirv_headers_revision': 'a62b032007b2e7a69f24a195cbfbd0cf22d31bb0',
|
||||
'spirv_headers_revision': 'd92cf88c371424591115a87499009dfad41b669c',
|
||||
}
|
||||
|
||||
deps = {
|
||||
|
@ -102,7 +102,7 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
|
||||
const auto version = spvVersionForTargetEnv(env);
|
||||
for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
|
||||
const spv_opcode_desc_t& entry = table->entries[opcodeIndex];
|
||||
// We considers the current opcode as available as long as
|
||||
// We consider the current opcode as available as long as
|
||||
// 1. The target environment satisfies the minimal requirement of the
|
||||
// opcode; or
|
||||
// 2. There is at least one extension enabling this opcode.
|
||||
@ -110,14 +110,35 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
|
||||
// Note that the second rule assumes the extension enabling this instruction
|
||||
// is indeed requested in the SPIR-V code; checking that should be
|
||||
// validator's work.
|
||||
if (((version >= entry.minVersion && version <= entry.lastVersion) ||
|
||||
entry.numExtensions > 0u || entry.numCapabilities > 0u) &&
|
||||
nameLength == strlen(entry.name) &&
|
||||
if ((version >= entry.minVersion && version <= entry.lastVersion) ||
|
||||
entry.numExtensions > 0u || entry.numCapabilities > 0u) {
|
||||
// Exact match case.
|
||||
if (nameLength == strlen(entry.name) &&
|
||||
!strncmp(name, entry.name, nameLength)) {
|
||||
// NOTE: Found out Opcode!
|
||||
*pEntry = &entry;
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
// Lack of binary search really hurts here. There isn't an easy filter to
|
||||
// apply before checking aliases since we need to handle promotion from
|
||||
// vendor to KHR/EXT and KHR/EXT to core. It would require a sure-fire way
|
||||
// of dropping suffices. Fortunately, most lookup are based on token
|
||||
// value.
|
||||
//
|
||||
// If this was a binary search we could iterate between the lower and
|
||||
// upper bounds.
|
||||
if (entry.numAliases > 0) {
|
||||
for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
|
||||
aliasIndex++) {
|
||||
// Skip Op prefix. Should this be encoded in the table instead?
|
||||
const auto alias = entry.aliases[aliasIndex] + 2;
|
||||
const size_t aliasLength = strlen(alias);
|
||||
if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
|
||||
*pEntry = &entry;
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_ERROR_INVALID_LOOKUP;
|
||||
@ -133,8 +154,8 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
|
||||
const auto beg = table->entries;
|
||||
const auto end = table->entries + table->count;
|
||||
|
||||
spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {},
|
||||
false, false, 0, nullptr, ~0u, ~0u};
|
||||
spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {}, 0,
|
||||
{}, false, false, 0, nullptr, ~0u, ~0u};
|
||||
|
||||
auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
|
||||
return lhs.opcode < rhs.opcode;
|
||||
@ -189,6 +210,7 @@ const char* spvOpcodeString(const uint32_t opcode) {
|
||||
spv_opcode_desc_t needle = {"", static_cast<spv::Op>(opcode),
|
||||
0, nullptr,
|
||||
0, {},
|
||||
0, {},
|
||||
false, false,
|
||||
0, nullptr,
|
||||
~0u, ~0u};
|
||||
|
@ -64,11 +64,29 @@ spv_result_t spvOperandTableNameLookup(spv_target_env,
|
||||
// We consider the current operand as available as long as
|
||||
// it is in the grammar. It might not be *valid* to use,
|
||||
// but that should be checked by the validator, not by parsing.
|
||||
//
|
||||
// Exact match case
|
||||
if (nameLength == strlen(entry.name) &&
|
||||
!strncmp(entry.name, name, nameLength)) {
|
||||
*pEntry = &entry;
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
// Check the aliases. Ideally we would have a version of the table sorted
|
||||
// by name and then we could iterate between the lower and upper bounds to
|
||||
// restrict the amount comparisons. Fortunately, name-based lookups are
|
||||
// mostly restricted to the assembler.
|
||||
if (entry.numAliases > 0) {
|
||||
for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
|
||||
aliasIndex++) {
|
||||
const auto alias = entry.aliases[aliasIndex];
|
||||
const size_t aliasLength = strlen(alias);
|
||||
if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
|
||||
*pEntry = &entry;
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +101,8 @@ spv_result_t spvOperandTableValueLookup(spv_target_env,
|
||||
if (!table) return SPV_ERROR_INVALID_TABLE;
|
||||
if (!pEntry) return SPV_ERROR_INVALID_POINTER;
|
||||
|
||||
spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr, {}, ~0u, ~0u};
|
||||
spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr,
|
||||
0, nullptr, {}, ~0u, ~0u};
|
||||
|
||||
auto comp = [](const spv_operand_desc_t& lhs, const spv_operand_desc_t& rhs) {
|
||||
return lhs.value < rhs.value;
|
||||
|
@ -22,6 +22,8 @@
|
||||
typedef struct spv_opcode_desc_t {
|
||||
const char* name;
|
||||
const spv::Op opcode;
|
||||
const uint32_t numAliases;
|
||||
const char** aliases;
|
||||
const uint32_t numCapabilities;
|
||||
const spv::Capability* capabilities;
|
||||
// operandTypes[0..numTypes-1] describe logical operands for the instruction.
|
||||
@ -47,6 +49,8 @@ typedef struct spv_opcode_desc_t {
|
||||
typedef struct spv_operand_desc_t {
|
||||
const char* name;
|
||||
const uint32_t value;
|
||||
const uint32_t numAliases;
|
||||
const char** aliases;
|
||||
const uint32_t numCapabilities;
|
||||
const spv::Capability* capabilities;
|
||||
// A set of extensions that enable this feature. If empty then this operand
|
||||
|
@ -70,6 +70,39 @@ def convert_max_required_version(version):
|
||||
return '0xffffffffu'
|
||||
return 'SPV_SPIRV_VERSION_WORD({})'.format(version.replace('.', ','))
|
||||
|
||||
def get_alias_array_name(aliases):
|
||||
"""Returns the name of the array containing all the given aliases.
|
||||
|
||||
Arguments:
|
||||
- aliases: a sequence of alias names
|
||||
"""
|
||||
if not aliases:
|
||||
return 'nullptr';
|
||||
return '{}_aliases_{}'.format(PYGEN_VARIABLE_PREFIX, ''.join(aliases))
|
||||
|
||||
def compose_alias_list(aliases):
|
||||
"""Returns a string containing a braced list of aliases.
|
||||
|
||||
Arguments:
|
||||
- aliases: a sequence of alias names
|
||||
|
||||
Returns:
|
||||
a string containing the braced list of char* named by aliases.
|
||||
"""
|
||||
return '{' + ', '.join([('"{}"').format(a) for a in aliases]) + '}'
|
||||
|
||||
def generate_aliases_arrays(aliases):
|
||||
"""Returns the arrays of aliases
|
||||
|
||||
Arguments:
|
||||
- aliases: a sequence of sequence of alias names
|
||||
"""
|
||||
aliases = sorted(set([tuple(a) for a in aliases if a]))
|
||||
arrays = [
|
||||
'static const char* {}[] = {};'.format(
|
||||
get_alias_array_name(a), compose_alias_list(a))
|
||||
for a in aliases]
|
||||
return '\n'.join(arrays)
|
||||
|
||||
def compose_capability_list(caps):
|
||||
"""Returns a string containing a braced list of capabilities as enums.
|
||||
@ -224,11 +257,12 @@ class InstInitializer(object):
|
||||
"""Instances holds a SPIR-V instruction suitable for printing as the
|
||||
initializer for spv_opcode_desc_t."""
|
||||
|
||||
def __init__(self, opname, caps, exts, operands, version, lastVersion):
|
||||
def __init__(self, opname, aliases, caps, exts, operands, version, lastVersion):
|
||||
"""Initialization.
|
||||
|
||||
Arguments:
|
||||
- opname: opcode name (with the 'Op' prefix)
|
||||
- aliases: a sequence of aliases for the name of this opcode
|
||||
- caps: a sequence of capability names required by this opcode
|
||||
- exts: a sequence of names of extensions enabling this enumerant
|
||||
- operands: a sequence of (operand-kind, operand-quantifier) tuples
|
||||
@ -238,6 +272,8 @@ class InstInitializer(object):
|
||||
|
||||
assert opname.startswith('Op')
|
||||
self.opname = opname[2:] # Remove the "Op" prefix.
|
||||
self.num_aliases = len(aliases);
|
||||
self.aliases_mask = get_alias_array_name(aliases)
|
||||
self.num_caps = len(caps)
|
||||
self.caps_mask = get_capability_array_name(caps)
|
||||
self.num_exts = len(exts)
|
||||
@ -272,6 +308,7 @@ class InstInitializer(object):
|
||||
base_str = 'spv::Op::Op'
|
||||
|
||||
template = ['{{"{opname}"', base_str + '{opname}',
|
||||
'{num_aliases}', '{aliases_mask}',
|
||||
'{num_caps}', '{caps_mask}',
|
||||
'{num_operands}', '{{{operands}}}',
|
||||
'{def_result_id}', '{ref_type_id}',
|
||||
@ -279,6 +316,8 @@ class InstInitializer(object):
|
||||
'{min_version}', '{max_version}}}']
|
||||
return ', '.join(template).format(
|
||||
opname=self.opname,
|
||||
num_aliases=self.num_aliases,
|
||||
aliases_mask=self.aliases_mask,
|
||||
num_caps=self.num_caps,
|
||||
caps_mask=self.caps_mask,
|
||||
num_operands=len(self.operands),
|
||||
@ -336,6 +375,7 @@ def generate_instruction(inst, is_ext_inst):
|
||||
"""
|
||||
opname = inst.get('opname')
|
||||
opcode = inst.get('opcode')
|
||||
aliases = inst.get('aliases', [])
|
||||
caps = inst.get('capabilities', [])
|
||||
exts = inst.get('extensions', [])
|
||||
operands = inst.get('operands', {})
|
||||
@ -348,7 +388,7 @@ def generate_instruction(inst, is_ext_inst):
|
||||
if is_ext_inst:
|
||||
return str(ExtInstInitializer(opname, opcode, caps, operands))
|
||||
else:
|
||||
return str(InstInitializer(opname, caps, exts, operands, min_version, max_version))
|
||||
return str(InstInitializer(opname, aliases, caps, exts, operands, min_version, max_version))
|
||||
|
||||
|
||||
def generate_instruction_table(inst_table):
|
||||
@ -364,6 +404,8 @@ def generate_instruction_table(inst_table):
|
||||
"""
|
||||
inst_table = sorted(inst_table, key=lambda k: (k['opcode'], k['opname']))
|
||||
|
||||
aliases_arrays = generate_aliases_arrays(
|
||||
[inst.get('aliases', []) for inst in inst_table])
|
||||
caps_arrays = generate_capability_arrays(
|
||||
[inst.get('capabilities', []) for inst in inst_table])
|
||||
exts_arrays = generate_extension_arrays(
|
||||
@ -373,7 +415,7 @@ def generate_instruction_table(inst_table):
|
||||
insts = ['static const spv_opcode_desc_t kOpcodeTableEntries[] = {{\n'
|
||||
' {}\n}};'.format(',\n '.join(insts))]
|
||||
|
||||
return '{}\n\n{}\n\n{}'.format(caps_arrays, exts_arrays, '\n'.join(insts))
|
||||
return '{}\n\n{}\n\n{}\n\n{}'.format(aliases_arrays, caps_arrays, exts_arrays, '\n'.join(insts))
|
||||
|
||||
|
||||
def generate_extended_instruction_table(json_grammar, set_name, operand_kind_prefix=""):
|
||||
@ -405,12 +447,13 @@ def generate_extended_instruction_table(json_grammar, set_name, operand_kind_pre
|
||||
class EnumerantInitializer(object):
|
||||
"""Prints an enumerant as the initializer for spv_operand_desc_t."""
|
||||
|
||||
def __init__(self, enumerant, value, caps, exts, parameters, version, lastVersion):
|
||||
def __init__(self, enumerant, value, aliases, caps, exts, parameters, version, lastVersion):
|
||||
"""Initialization.
|
||||
|
||||
Arguments:
|
||||
- enumerant: enumerant name
|
||||
- value: enumerant value
|
||||
- aliases: a sequence of aliased capability names
|
||||
- caps: a sequence of capability names required by this enumerant
|
||||
- exts: a sequence of names of extensions enabling this enumerant
|
||||
- parameters: a sequence of (operand-kind, operand-quantifier) tuples
|
||||
@ -419,6 +462,8 @@ class EnumerantInitializer(object):
|
||||
"""
|
||||
self.enumerant = enumerant
|
||||
self.value = value
|
||||
self.num_aliases = len(aliases)
|
||||
self.aliases = get_alias_array_name(aliases)
|
||||
self.num_caps = len(caps)
|
||||
self.caps = get_capability_array_name(caps)
|
||||
self.num_exts = len(exts)
|
||||
@ -428,13 +473,17 @@ class EnumerantInitializer(object):
|
||||
self.lastVersion = convert_max_required_version(lastVersion)
|
||||
|
||||
def __str__(self):
|
||||
template = ['{{"{enumerant}"', '{value}', '{num_caps}',
|
||||
'{caps}', '{num_exts}', '{exts}',
|
||||
template = ['{{"{enumerant}"', '{value}',
|
||||
'{num_aliases}', '{aliases}',
|
||||
'{num_caps}', '{caps}',
|
||||
'{num_exts}', '{exts}',
|
||||
'{{{parameters}}}', '{min_version}',
|
||||
'{max_version}}}']
|
||||
return ', '.join(template).format(
|
||||
enumerant=self.enumerant,
|
||||
value=self.value,
|
||||
num_aliases=self.num_aliases,
|
||||
aliases=self.aliases,
|
||||
num_caps=self.num_caps,
|
||||
caps=self.caps,
|
||||
num_exts=self.num_exts,
|
||||
@ -456,6 +505,7 @@ def generate_enum_operand_kind_entry(entry, extension_map):
|
||||
"""
|
||||
enumerant = entry.get('enumerant')
|
||||
value = entry.get('value')
|
||||
aliases = entry.get('aliases', [])
|
||||
caps = entry.get('capabilities', [])
|
||||
if value in extension_map:
|
||||
exts = extension_map[value]
|
||||
@ -471,7 +521,7 @@ def generate_enum_operand_kind_entry(entry, extension_map):
|
||||
assert value is not None
|
||||
|
||||
return str(EnumerantInitializer(
|
||||
enumerant, value, caps, exts, params, version, max_version))
|
||||
enumerant, value, aliases, caps, exts, params, version, max_version))
|
||||
|
||||
|
||||
def generate_enum_operand_kind(enum, synthetic_exts_list):
|
||||
@ -516,7 +566,7 @@ def generate_enum_operand_kind(enum, synthetic_exts_list):
|
||||
if len(entries) == 0:
|
||||
# Insert a dummy entry. Otherwise the array is empty and compilation
|
||||
# will fail in MSVC.
|
||||
entries = [' {"place holder", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(999,0), 0}']
|
||||
entries = [' {"place holder", 0, 0, nullptr, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(999,0), 0}']
|
||||
|
||||
template = ['static const spv_operand_desc_t {name}[] = {{',
|
||||
'{entries}', '}};']
|
||||
@ -532,6 +582,11 @@ def generate_operand_kind_table(enums):
|
||||
# We only need to output info tables for those operand kinds that are enums.
|
||||
enums = [e for e in enums if e.get('category') in ['ValueEnum', 'BitEnum']]
|
||||
|
||||
aliases = [entry.get('aliases', [])
|
||||
for enum in enums
|
||||
for entry in enum.get('enumerants', [])]
|
||||
aliases_arrays = generate_aliases_arrays(aliases)
|
||||
|
||||
caps = [entry.get('capabilities', [])
|
||||
for enum in enums
|
||||
for entry in enum.get('enumerants', [])]
|
||||
@ -566,7 +621,7 @@ def generate_operand_kind_table(enums):
|
||||
table = '\n'.join(template).format(
|
||||
p=PYGEN_VARIABLE_PREFIX, enums=',\n'.join(table_entries))
|
||||
|
||||
return '\n\n'.join((caps_arrays,) + (exts_arrays,) + enum_entries + (table,))
|
||||
return '\n\n'.join((aliases_arrays,) + (caps_arrays,) + (exts_arrays,) + enum_entries + (table,))
|
||||
|
||||
|
||||
def get_extension_list(instructions, operand_kinds):
|
||||
|
@ -161,11 +161,17 @@ def main():
|
||||
print('\n" Core instructions')
|
||||
for inst in core["instructions"]:
|
||||
EmitAsStatement(inst['opname'])
|
||||
aliases = inst.get('aliases', [])
|
||||
for alias in aliases:
|
||||
EmitAsStatement(alias)
|
||||
print('\n" Core operand enums')
|
||||
for operand_kind in core["operand_kinds"]:
|
||||
if 'enumerants' in operand_kind:
|
||||
for e in operand_kind['enumerants']:
|
||||
EmitAsEnumerant(e['enumerant'])
|
||||
aliases = e.get('aliases', [])
|
||||
for a in aliases:
|
||||
EmitAsEnumerant(a)
|
||||
|
||||
if args.extinst_glsl_grammar is not None:
|
||||
print('\n" GLSL.std.450 extended instructions')
|
||||
|
Loading…
Reference in New Issue
Block a user