Skip to content

Commit fcf994a

Browse files
authored
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
1 parent 4310fd4 commit fcf994a

File tree

6 files changed

+127
-21
lines changed

6 files changed

+127
-21
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ vars = {
1414

1515
're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca',
1616

17-
'spirv_headers_revision': 'a62b032007b2e7a69f24a195cbfbd0cf22d31bb0',
17+
'spirv_headers_revision': 'd92cf88c371424591115a87499009dfad41b669c',
1818
}
1919

2020
deps = {

source/opcode.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,42 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
102102
const auto version = spvVersionForTargetEnv(env);
103103
for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
104104
const spv_opcode_desc_t& entry = table->entries[opcodeIndex];
105-
// We considers the current opcode as available as long as
105+
// We consider the current opcode as available as long as
106106
// 1. The target environment satisfies the minimal requirement of the
107107
// opcode; or
108108
// 2. There is at least one extension enabling this opcode.
109109
//
110110
// Note that the second rule assumes the extension enabling this instruction
111111
// is indeed requested in the SPIR-V code; checking that should be
112112
// validator's work.
113-
if (((version >= entry.minVersion && version <= entry.lastVersion) ||
114-
entry.numExtensions > 0u || entry.numCapabilities > 0u) &&
115-
nameLength == strlen(entry.name) &&
116-
!strncmp(name, entry.name, nameLength)) {
117-
// NOTE: Found out Opcode!
118-
*pEntry = &entry;
119-
return SPV_SUCCESS;
113+
if ((version >= entry.minVersion && version <= entry.lastVersion) ||
114+
entry.numExtensions > 0u || entry.numCapabilities > 0u) {
115+
// Exact match case.
116+
if (nameLength == strlen(entry.name) &&
117+
!strncmp(name, entry.name, nameLength)) {
118+
*pEntry = &entry;
119+
return SPV_SUCCESS;
120+
}
121+
// Lack of binary search really hurts here. There isn't an easy filter to
122+
// apply before checking aliases since we need to handle promotion from
123+
// vendor to KHR/EXT and KHR/EXT to core. It would require a sure-fire way
124+
// of dropping suffices. Fortunately, most lookup are based on token
125+
// value.
126+
//
127+
// If this was a binary search we could iterate between the lower and
128+
// upper bounds.
129+
if (entry.numAliases > 0) {
130+
for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
131+
aliasIndex++) {
132+
// Skip Op prefix. Should this be encoded in the table instead?
133+
const auto alias = entry.aliases[aliasIndex] + 2;
134+
const size_t aliasLength = strlen(alias);
135+
if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
136+
*pEntry = &entry;
137+
return SPV_SUCCESS;
138+
}
139+
}
140+
}
120141
}
121142
}
122143

@@ -133,8 +154,8 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
133154
const auto beg = table->entries;
134155
const auto end = table->entries + table->count;
135156

136-
spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {},
137-
false, false, 0, nullptr, ~0u, ~0u};
157+
spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {}, 0,
158+
{}, false, false, 0, nullptr, ~0u, ~0u};
138159

139160
auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
140161
return lhs.opcode < rhs.opcode;
@@ -189,6 +210,7 @@ const char* spvOpcodeString(const uint32_t opcode) {
189210
spv_opcode_desc_t needle = {"", static_cast<spv::Op>(opcode),
190211
0, nullptr,
191212
0, {},
213+
0, {},
192214
false, false,
193215
0, nullptr,
194216
~0u, ~0u};

source/operand.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,29 @@ spv_result_t spvOperandTableNameLookup(spv_target_env,
6464
// We consider the current operand as available as long as
6565
// it is in the grammar. It might not be *valid* to use,
6666
// but that should be checked by the validator, not by parsing.
67+
//
68+
// Exact match case
6769
if (nameLength == strlen(entry.name) &&
6870
!strncmp(entry.name, name, nameLength)) {
6971
*pEntry = &entry;
7072
return SPV_SUCCESS;
7173
}
74+
75+
// Check the aliases. Ideally we would have a version of the table sorted
76+
// by name and then we could iterate between the lower and upper bounds to
77+
// restrict the amount comparisons. Fortunately, name-based lookups are
78+
// mostly restricted to the assembler.
79+
if (entry.numAliases > 0) {
80+
for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
81+
aliasIndex++) {
82+
const auto alias = entry.aliases[aliasIndex];
83+
const size_t aliasLength = strlen(alias);
84+
if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
85+
*pEntry = &entry;
86+
return SPV_SUCCESS;
87+
}
88+
}
89+
}
7290
}
7391
}
7492

@@ -83,7 +101,8 @@ spv_result_t spvOperandTableValueLookup(spv_target_env,
83101
if (!table) return SPV_ERROR_INVALID_TABLE;
84102
if (!pEntry) return SPV_ERROR_INVALID_POINTER;
85103

86-
spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr, {}, ~0u, ~0u};
104+
spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr,
105+
0, nullptr, {}, ~0u, ~0u};
87106

88107
auto comp = [](const spv_operand_desc_t& lhs, const spv_operand_desc_t& rhs) {
89108
return lhs.value < rhs.value;

source/table.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
typedef struct spv_opcode_desc_t {
2323
const char* name;
2424
const spv::Op opcode;
25+
const uint32_t numAliases;
26+
const char** aliases;
2527
const uint32_t numCapabilities;
2628
const spv::Capability* capabilities;
2729
// operandTypes[0..numTypes-1] describe logical operands for the instruction.
@@ -47,6 +49,8 @@ typedef struct spv_opcode_desc_t {
4749
typedef struct spv_operand_desc_t {
4850
const char* name;
4951
const uint32_t value;
52+
const uint32_t numAliases;
53+
const char** aliases;
5054
const uint32_t numCapabilities;
5155
const spv::Capability* capabilities;
5256
// A set of extensions that enable this feature. If empty then this operand

utils/generate_grammar_tables.py

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,39 @@ def convert_max_required_version(version):
7070
return '0xffffffffu'
7171
return 'SPV_SPIRV_VERSION_WORD({})'.format(version.replace('.', ','))
7272

73+
def get_alias_array_name(aliases):
74+
"""Returns the name of the array containing all the given aliases.
75+
76+
Arguments:
77+
- aliases: a sequence of alias names
78+
"""
79+
if not aliases:
80+
return 'nullptr';
81+
return '{}_aliases_{}'.format(PYGEN_VARIABLE_PREFIX, ''.join(aliases))
82+
83+
def compose_alias_list(aliases):
84+
"""Returns a string containing a braced list of aliases.
85+
86+
Arguments:
87+
- aliases: a sequence of alias names
88+
89+
Returns:
90+
a string containing the braced list of char* named by aliases.
91+
"""
92+
return '{' + ', '.join([('"{}"').format(a) for a in aliases]) + '}'
93+
94+
def generate_aliases_arrays(aliases):
95+
"""Returns the arrays of aliases
96+
97+
Arguments:
98+
- aliases: a sequence of sequence of alias names
99+
"""
100+
aliases = sorted(set([tuple(a) for a in aliases if a]))
101+
arrays = [
102+
'static const char* {}[] = {};'.format(
103+
get_alias_array_name(a), compose_alias_list(a))
104+
for a in aliases]
105+
return '\n'.join(arrays)
73106

74107
def compose_capability_list(caps):
75108
"""Returns a string containing a braced list of capabilities as enums.
@@ -224,11 +257,12 @@ class InstInitializer(object):
224257
"""Instances holds a SPIR-V instruction suitable for printing as the
225258
initializer for spv_opcode_desc_t."""
226259

227-
def __init__(self, opname, caps, exts, operands, version, lastVersion):
260+
def __init__(self, opname, aliases, caps, exts, operands, version, lastVersion):
228261
"""Initialization.
229262
230263
Arguments:
231264
- opname: opcode name (with the 'Op' prefix)
265+
- aliases: a sequence of aliases for the name of this opcode
232266
- caps: a sequence of capability names required by this opcode
233267
- exts: a sequence of names of extensions enabling this enumerant
234268
- operands: a sequence of (operand-kind, operand-quantifier) tuples
@@ -238,6 +272,8 @@ def __init__(self, opname, caps, exts, operands, version, lastVersion):
238272

239273
assert opname.startswith('Op')
240274
self.opname = opname[2:] # Remove the "Op" prefix.
275+
self.num_aliases = len(aliases);
276+
self.aliases_mask = get_alias_array_name(aliases)
241277
self.num_caps = len(caps)
242278
self.caps_mask = get_capability_array_name(caps)
243279
self.num_exts = len(exts)
@@ -272,13 +308,16 @@ def __str__(self):
272308
base_str = 'spv::Op::Op'
273309

274310
template = ['{{"{opname}"', base_str + '{opname}',
311+
'{num_aliases}', '{aliases_mask}',
275312
'{num_caps}', '{caps_mask}',
276313
'{num_operands}', '{{{operands}}}',
277314
'{def_result_id}', '{ref_type_id}',
278315
'{num_exts}', '{exts}',
279316
'{min_version}', '{max_version}}}']
280317
return ', '.join(template).format(
281318
opname=self.opname,
319+
num_aliases=self.num_aliases,
320+
aliases_mask=self.aliases_mask,
282321
num_caps=self.num_caps,
283322
caps_mask=self.caps_mask,
284323
num_operands=len(self.operands),
@@ -336,6 +375,7 @@ def generate_instruction(inst, is_ext_inst):
336375
"""
337376
opname = inst.get('opname')
338377
opcode = inst.get('opcode')
378+
aliases = inst.get('aliases', [])
339379
caps = inst.get('capabilities', [])
340380
exts = inst.get('extensions', [])
341381
operands = inst.get('operands', {})
@@ -348,7 +388,7 @@ def generate_instruction(inst, is_ext_inst):
348388
if is_ext_inst:
349389
return str(ExtInstInitializer(opname, opcode, caps, operands))
350390
else:
351-
return str(InstInitializer(opname, caps, exts, operands, min_version, max_version))
391+
return str(InstInitializer(opname, aliases, caps, exts, operands, min_version, max_version))
352392

353393

354394
def generate_instruction_table(inst_table):
@@ -364,6 +404,8 @@ def generate_instruction_table(inst_table):
364404
"""
365405
inst_table = sorted(inst_table, key=lambda k: (k['opcode'], k['opname']))
366406

407+
aliases_arrays = generate_aliases_arrays(
408+
[inst.get('aliases', []) for inst in inst_table])
367409
caps_arrays = generate_capability_arrays(
368410
[inst.get('capabilities', []) for inst in inst_table])
369411
exts_arrays = generate_extension_arrays(
@@ -373,7 +415,7 @@ def generate_instruction_table(inst_table):
373415
insts = ['static const spv_opcode_desc_t kOpcodeTableEntries[] = {{\n'
374416
' {}\n}};'.format(',\n '.join(insts))]
375417

376-
return '{}\n\n{}\n\n{}'.format(caps_arrays, exts_arrays, '\n'.join(insts))
418+
return '{}\n\n{}\n\n{}\n\n{}'.format(aliases_arrays, caps_arrays, exts_arrays, '\n'.join(insts))
377419

378420

379421
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
405447
class EnumerantInitializer(object):
406448
"""Prints an enumerant as the initializer for spv_operand_desc_t."""
407449

408-
def __init__(self, enumerant, value, caps, exts, parameters, version, lastVersion):
450+
def __init__(self, enumerant, value, aliases, caps, exts, parameters, version, lastVersion):
409451
"""Initialization.
410452
411453
Arguments:
412454
- enumerant: enumerant name
413455
- value: enumerant value
456+
- aliases: a sequence of aliased capability names
414457
- caps: a sequence of capability names required by this enumerant
415458
- exts: a sequence of names of extensions enabling this enumerant
416459
- parameters: a sequence of (operand-kind, operand-quantifier) tuples
@@ -419,6 +462,8 @@ def __init__(self, enumerant, value, caps, exts, parameters, version, lastVersio
419462
"""
420463
self.enumerant = enumerant
421464
self.value = value
465+
self.num_aliases = len(aliases)
466+
self.aliases = get_alias_array_name(aliases)
422467
self.num_caps = len(caps)
423468
self.caps = get_capability_array_name(caps)
424469
self.num_exts = len(exts)
@@ -428,13 +473,17 @@ def __init__(self, enumerant, value, caps, exts, parameters, version, lastVersio
428473
self.lastVersion = convert_max_required_version(lastVersion)
429474

430475
def __str__(self):
431-
template = ['{{"{enumerant}"', '{value}', '{num_caps}',
432-
'{caps}', '{num_exts}', '{exts}',
476+
template = ['{{"{enumerant}"', '{value}',
477+
'{num_aliases}', '{aliases}',
478+
'{num_caps}', '{caps}',
479+
'{num_exts}', '{exts}',
433480
'{{{parameters}}}', '{min_version}',
434481
'{max_version}}}']
435482
return ', '.join(template).format(
436483
enumerant=self.enumerant,
437484
value=self.value,
485+
num_aliases=self.num_aliases,
486+
aliases=self.aliases,
438487
num_caps=self.num_caps,
439488
caps=self.caps,
440489
num_exts=self.num_exts,
@@ -456,6 +505,7 @@ def generate_enum_operand_kind_entry(entry, extension_map):
456505
"""
457506
enumerant = entry.get('enumerant')
458507
value = entry.get('value')
508+
aliases = entry.get('aliases', [])
459509
caps = entry.get('capabilities', [])
460510
if value in extension_map:
461511
exts = extension_map[value]
@@ -471,7 +521,7 @@ def generate_enum_operand_kind_entry(entry, extension_map):
471521
assert value is not None
472522

473523
return str(EnumerantInitializer(
474-
enumerant, value, caps, exts, params, version, max_version))
524+
enumerant, value, aliases, caps, exts, params, version, max_version))
475525

476526

477527
def generate_enum_operand_kind(enum, synthetic_exts_list):
@@ -516,7 +566,7 @@ def functor(k): return (int(k['value'], 16))
516566
if len(entries) == 0:
517567
# Insert a dummy entry. Otherwise the array is empty and compilation
518568
# will fail in MSVC.
519-
entries = [' {"place holder", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(999,0), 0}']
569+
entries = [' {"place holder", 0, 0, nullptr, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(999,0), 0}']
520570

521571
template = ['static const spv_operand_desc_t {name}[] = {{',
522572
'{entries}', '}};']
@@ -532,6 +582,11 @@ def generate_operand_kind_table(enums):
532582
# We only need to output info tables for those operand kinds that are enums.
533583
enums = [e for e in enums if e.get('category') in ['ValueEnum', 'BitEnum']]
534584

585+
aliases = [entry.get('aliases', [])
586+
for enum in enums
587+
for entry in enum.get('enumerants', [])]
588+
aliases_arrays = generate_aliases_arrays(aliases)
589+
535590
caps = [entry.get('capabilities', [])
536591
for enum in enums
537592
for entry in enum.get('enumerants', [])]
@@ -566,7 +621,7 @@ def generate_operand_kind_table(enums):
566621
table = '\n'.join(template).format(
567622
p=PYGEN_VARIABLE_PREFIX, enums=',\n'.join(table_entries))
568623

569-
return '\n\n'.join((caps_arrays,) + (exts_arrays,) + enum_entries + (table,))
624+
return '\n\n'.join((aliases_arrays,) + (caps_arrays,) + (exts_arrays,) + enum_entries + (table,))
570625

571626

572627
def get_extension_list(instructions, operand_kinds):

utils/generate_vim_syntax.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,17 @@ def main():
161161
print('\n" Core instructions')
162162
for inst in core["instructions"]:
163163
EmitAsStatement(inst['opname'])
164+
aliases = inst.get('aliases', [])
165+
for alias in aliases:
166+
EmitAsStatement(alias)
164167
print('\n" Core operand enums')
165168
for operand_kind in core["operand_kinds"]:
166169
if 'enumerants' in operand_kind:
167170
for e in operand_kind['enumerants']:
168171
EmitAsEnumerant(e['enumerant'])
172+
aliases = e.get('aliases', [])
173+
for a in aliases:
174+
EmitAsEnumerant(a)
169175

170176
if args.extinst_glsl_grammar is not None:
171177
print('\n" GLSL.std.450 extended instructions')

0 commit comments

Comments
 (0)