//
//===----------------------------------------------------------------------===//
+// Note that for each op in this file, we use a tool to automatically generate
+// certain sections in its definition: basic structure, summary, description.
+// So modifications to these sections will not be respected. Modifications to
+// op traits, arguments, results, and sections after the results are retained.
+// Besides, ops in this file must be separated via the '// -----' marker.
+
#ifdef SPIRV_OPS
#else
#define SPIRV_OPS
include "mlir/SPIRV/SPIRVStructureOps.td"
#endif // SPIRV_STRUCTURE_OPS
+// -----
+
+def SPV_CompositeExtractOp : SPV_Op<"CompositeExtract", [NoSideEffect]> {
+ let summary = "Extract a part of a composite object.";
+
+ let description = [{
+ Result Type must be the type of object selected by the last provided
+ index. The instruction result is the extracted object.
+
+ Composite is the composite to extract from.
+
+ Indexes walk the type hierarchy, potentially down to component
+ granularity, to select the part to extract. All indexes must be in
+ bounds. All composite constituents use zero-based numbering, as
+ described by their OpType… instruction.
+
+ ### Custom assembly form
+
+ ``` {.ebnf}
+ composite-extract-op ::= ssa-id `=` `spv.CompositeExtract` ssa-use
+ `[` integer-literal (',' integer-literal)* `]`
+ `:` composite-type
+ ```
+
+ For example:
+
+ ```
+ %0 = spv.Variable : !spv.ptr<!spv.array<4x!spv.array<4xf32>>, Function>
+ %1 = spv.Load "Function" %0 ["Volatile"] : !spv.array<4x!spv.array<4xf32>>
+ %2 = spv.CompositeExtract %1[1 : i32] : !spv.array<4x!spv.array<4xf32>>
+ ```
+
+ }];
+
+ let arguments = (ins
+ SPV_Composite:$composite,
+ I32ArrayAttr:$indices
+ );
+
+ let results = (outs
+ SPV_Type:$component
+ );
+}
+
+// -----
+
def SPV_EntryPointOp : SPV_Op<"EntryPoint", [ModuleOnly]> {
let summary = [{
Declare an entry point, its execution model, and its interface.
Entry Point must be the Result <id> of an OpFunction instruction.
- Name is a name string for the entry point. A module cannot have
- two OpEntryPoint instructions with the same Execution Model and
- the same Name string.
-
- Interface is a list of <id> of global OpVariable
- instructions. These declare the set of global variables from a
- module that form the interface of this entry point. The set of
- Interface <id> must be equal to or a superset of the global
- OpVariable Result <id> referenced by the entry point’s static call
- tree, within the interface’s storage classes. Before version 1.4,
- the interface’s storage classes are limited to the Input and
- Output storage classes. Starting with version 1.4, the interface’s
- storage classes are all storage classes used in declaring all
- global variables referenced by the entry point’s call tree.
+ Name is a name string for the entry point. A module cannot have two
+ OpEntryPoint instructions with the same Execution Model and the same
+ Name string.
+
+ Interface is a list of <id> of global OpVariable instructions. These
+ declare the set of global variables from a module that form the
+ interface of this entry point. The set of Interface <id> must be equal
+ to or a superset of the global OpVariable Result <id> referenced by the
+ entry point’s static call tree, within the interface’s storage classes.
+ Before version 1.4, the interface’s storage classes are limited to the
+ Input and Output storage classes. Starting with version 1.4, the
+ interface’s storage classes are all storage classes used in declaring
+ all global variables referenced by the entry point’s call tree.
+
+ Interface <id> are forward references. Before version 1.4, duplication
+ of these <id> is tolerated. Starting with version 1.4, an <id> must not
+ appear more than once.
### Custom assembly form
let results = (outs SPV_EntryPoint:$id);
}
+// -----
+
def SPV_ExecutionModeOp : SPV_Op<"ExecutionMode", [ModuleOnly]> {
let summary = "Declare an execution mode for an entry point.";
let description = [{
- Entry Point must be the Entry Point <id> operand of an
- OpEntryPoint instruction.
+ Entry Point must be the Entry Point <id> operand of an OpEntryPoint
+ instruction.
Mode is the execution mode. See Execution Mode.
- This instruction is only valid when the Mode operand is an
- execution mode that takes no Extra Operands, or takes Extra
- Operands that are not <id> operands.
+ This instruction is only valid when the Mode operand is an execution
+ mode that takes no Extra Operands, or takes Extra Operands that are not
+ <id> operands.
### Custom assembly form
OptionalAttr<I32ArrayAttr>:$values
);
+ let results = (outs);
+
let verifier = [{ return success(); }];
}
+// -----
+
def SPV_FMulOp : SPV_Op<"FMul", [NoSideEffect, SameOperandsAndResultType]> {
- let summary = "Floating-point multiplication of Operand 1 and Operand 2";
+ let summary = "Floating-point multiplication of Operand 1 and Operand 2.";
let description = [{
Result Type must be a scalar or vector of floating-point type.
- The types of Operand 1 and Operand 2 both must be the same as Result Type.
+ The types of Operand 1 and Operand 2 both must be the same as Result
+ Type.
+
+ Results are computed per component.
+
+ ### Custom assembly form
+
+ ``` {.ebnf}
+ float-scalar-vector-type ::= float-type |
+ `vector<` integer-literal `x` float-type `>`
+ execution-mode-op ::= `spv.FMul` ssa-use, ssa-use
+ `:` float-scalar-vector-type
+ ```
- Results are computed per component.
+ For example:
+
+ ```
+ spv.FMul %0, %1 : f32
+ spv.FMul %2, %3 : vector<4xf32>
+ ```
}];
let arguments = (ins
let verifier = [{ return success(); }];
}
-def SPV_LoadOp : SPV_Op<"Load"> {
- let summary = "Load value through a pointer.";
+// -----
+
+def SPV_LoadOp : SPV_Op<"Load", []> {
+ let summary = "Load through a pointer.";
let description = [{
- Result Type is the type of the loaded object. It must be a type
- with fixed size; i.e., it cannot be, nor include, any
- OpTypeRuntimeArray types.
+ Result Type is the type of the loaded object. It must be a type with
+ fixed size; i.e., it cannot be, nor include, any OpTypeRuntimeArray
+ types.
- Pointer is the pointer to load through. Its type must be an
+ Pointer is the pointer to load through. Its type must be an
OpTypePointer whose Type operand is the same as Result Type.
If present, any Memory Operands must begin with a memory operand
- literal. If not present, it is the same as specifying the memory
- operand None.
+ literal. If not present, it is the same as specifying the memory operand
+ None.
### Custom assembly form
);
}
+// -----
+
def SPV_ReturnOp : SPV_Op<"Return", [Terminator]> {
- let summary = "Return with no value from a function with void return type";
+ let summary = "Return with no value from a function with void return type.";
let description = [{
This instruction must be the last instruction in a block.
+
+ ### Custom assembly form
+
+ ``` {.ebnf}
+ return-op ::= `spv.Return`
+ ```
}];
let arguments = (ins);
let verifier = [{ return verifyReturn(*this); }];
}
-def SPV_StoreOp : SPV_Op<"Store"> {
+// -----
+
+def SPV_StoreOp : SPV_Op<"Store", []> {
let summary = "Store through a pointer.";
let description = [{
- Pointer is the pointer to store through. Its type must be an
- OpTypePointer whose Type operand is the same as the type of
- Object.
+ Pointer is the pointer to store through. Its type must be an
+ OpTypePointer whose Type operand is the same as the type of Object.
Object is the object to store.
If present, any Memory Operands must begin with a memory operand
- literal. If not present, it is the same as specifying the memory
- operand None.
+ literal. If not present, it is the same as specifying the memory operand
+ None.
### Custom assembly form
OptionalAttr<SPV_MemoryAccessAttr>:$memory_access,
OptionalAttr<APIntAttr>:$alignment
);
+
+ let results = (outs);
}
-def SPV_VariableOp : SPV_Op<"Variable"> {
+// -----
+
+def SPV_VariableOp : SPV_Op<"Variable", []> {
let summary = [{
Allocate an object in memory, resulting in a pointer to it, which can be
- used with OpLoad and OpStore
+ used with OpLoad and OpStore.
}];
let description = [{
- Result Type must be an OpTypePointer. Its Type operand is the type of object
- in memory.
+ Result Type must be an OpTypePointer. Its Type operand is the type of
+ object in memory.
Storage Class is the Storage Class of the memory holding the object. It
- cannot be Generic. It must be the same as the Storage Class operand of the
- Result Type.
+ cannot be Generic. It must be the same as the Storage Class operand of
+ the Result Type.
- Initializer is optional. If Initializer is present, it will be the initial
- value of the variable’s memory content. Initializer must be an <id> from a
- constant instruction or a global (module scope) OpVariable instruction.
- Initializer must have the same type as the type pointed to by Result Type.
+ Initializer is optional. If Initializer is present, it will be the
+ initial value of the variable’s memory content. Initializer must be an
+ <id> from a constant instruction or a global (module scope) OpVariable
+ instruction. Initializer must have the same type as the type pointed to
+ by Result Type.
### Custom assembly form
);
}
-def SPV_CompositeExtractOp : SPV_Op<"CompositeExtract", [NoSideEffect]> {
- let summary = "Extract a part of a composite object.";
-
- let description = [{
- Result Type must be the type of object selected by the last provided index.
- The instruction result is the extracted object.
-
- Composite is the composite to extract from.
-
- Indexes walk the type hierarchy, potentially down to component granularity,
- to select the part to extract. All indexes must be in bounds.
- All composite constituents use zero-based numbering, as described by their
- OpType… instruction.
-
- ### Custom assembly form
-
- ``` {.ebnf}
- composite-extract-op ::= ssa-id `=` `spv.CompositeExtract` ssa-use
- `[` integer-literal (',' integer-literal)* `]`
- `:` composite-type
- ```
-
- For example:
-
- ```
- %0 = spv.Variable : !spv.ptr<!spv.array<4x!spv.array<4xf32>>, Function>
- %1 = spv.Load "Function" %0 ["Volatile"] : !spv.array<4x!spv.array<4xf32>>
- %2 = spv.CompositeExtract %1[1 : i32] : !spv.array<4x!spv.array<4xf32>>
- ```
-
- }];
-
- let arguments = (ins
- SPV_Composite:$composite,
- I32ArrayAttr:$indices
- );
-
- let results = (outs
- SPV_Type:$component
- );
-}
+// -----
#endif // SPIRV_OPS
#
# For example, to define the enum attribute for SPIR-V memory model:
#
-# ./gen_spirv_dialect.py --bash_td_path /path/to/SPIRVBase.td \
+# ./gen_spirv_dialect.py --base_td_path /path/to/SPIRVBase.td \
# --new-enum MemoryModel
#
# The 'operand_kinds' dict of spirv.core.grammar.json contains all supported
# SPIR-V enum classes.
+import re
import requests
+import textwrap
SPIRV_HTML_SPEC_URL = 'https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html'
SPIRV_JSON_SPEC_URL = 'https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json'
+AUTOGEN_OP_DEF_SEPARATOR = '\n// -----\n\n'
AUTOGEN_ENUM_SECTION_MARKER = 'enum section. Generated from SPIR-V spec; DO NOT MODIFY!'
-AUTOGEN_INSTRUCTION_OPCODE_SECTION_MARKER = ('opcode section. Generated from '
- 'SPIR-V spec; DO NOT MODIFY!')
+AUTOGEN_OPCODE_SECTION_MARKER = (
+ 'opcode section. Generated from SPIR-V spec; DO NOT MODIFY!')
+
+
+def get_spirv_doc_from_html_spec():
+ """Extracts instruction documentation from SPIR-V HTML spec.
+
+ Returns:
+ - A dict mapping from instruction opcode to documentation.
+ """
+ response = requests.get(SPIRV_HTML_SPEC_URL)
+ spec = response.content
+
+ from bs4 import BeautifulSoup
+ spirv = BeautifulSoup(spec, 'html.parser')
+
+ section_anchor = spirv.find('h3', {'id': '_a_id_instructions_a_instructions'})
+
+ doc = {}
+
+ for section in section_anchor.parent.find_all('div', {'class': 'sect3'}):
+ for table in section.find_all('table'):
+ inst_html = table.tbody.tr.td.p
+ opname = inst_html.a['id']
+ # Ignore the first line, which is just the opname.
+ doc[opname] = inst_html.text.split('\n', 1)[1].strip()
+
+ return doc
def get_spirv_grammar_from_json_spec():
"""Extracts operand kind and instruction grammar from SPIR-V JSON spec.
- Returns:
- - A list containing all operand kinds' grammar
- - A list containing all instructions' grammar
- """
+ Returns:
+ - A list containing all operand kinds' grammar
+ - A list containing all instructions' grammar
+ """
response = requests.get(SPIRV_JSON_SPEC_URL)
spec = response.content
def split_list_into_sublists(items, offset):
"""Split the list of items into multiple sublists.
- This is to make sure the string composed from each sublist won't exceed
- 80 characters.
+ This is to make sure the string composed from each sublist won't exceed
+ 80 characters.
- Arguments:
- - items: a list of strings
- - offset: the offset in calculating each sublist's length
- """
+ Arguments:
+ - items: a list of strings
+ - offset: the offset in calculating each sublist's length
+ """
chuncks = []
chunk = []
chunk_len = 0
def gen_operand_kind_enum_attr(operand_kind):
"""Generates the TableGen I32EnumAttr definition for the given operand kind.
- Returns:
- - The operand kind's name
- - A string containing the TableGen I32EnumAttr definition
- """
+ Returns:
+ - The operand kind's name
+ - A string containing the TableGen I32EnumAttr definition
+ """
if 'enumerants' not in operand_kind:
return '', ''
def gen_opcode(instructions):
""" Generates the TableGen definition to map opname to opcode
- Returns:
- - A string containing the TableGen SPV_OpCode definition
- """
+ Returns:
+ - A string containing the TableGen SPV_OpCode definition
+ """
max_len = max([len(inst['opname']) for inst in instructions])
def_fmt_str = 'def SPV_OC_{name} {colon:>{offset}} '\
def update_td_opcodes(path, instructions, filter_list):
+ """Updates SPIRBase.td with new generated opcode cases.
+
+ Arguments:
+ - path: the path to SPIRBase.td
+ - instructions: a list containing all SPIR-V instructions' grammar
+ - filter_list: a list containing new opnames to add
+ """
with open(path, 'r') as f:
content = f.read()
- content = content.split(AUTOGEN_INSTRUCTION_OPCODE_SECTION_MARKER)
+ content = content.split(AUTOGEN_OPCODE_SECTION_MARKER)
assert len(content) == 3
# Extend opcode list with existing list
- import re
existing_opcodes = [k[11:] for k in re.findall('def SPV_OC_\w+', content[1])]
filter_list.extend(existing_opcodes)
filter_list = list(set(filter_list))
opcode = gen_opcode(filter_instrs)
# Substitute the opcode
- content = content[0] + AUTOGEN_INSTRUCTION_OPCODE_SECTION_MARKER + '\n\n' + \
- opcode + '\n\n// End ' + AUTOGEN_INSTRUCTION_OPCODE_SECTION_MARKER \
+ content = content[0] + AUTOGEN_OPCODE_SECTION_MARKER + '\n\n' + \
+ opcode + '\n\n// End ' + AUTOGEN_OPCODE_SECTION_MARKER \
+ content[2]
with open(path, 'w') as f:
def update_td_enum_attrs(path, operand_kinds, filter_list):
"""Updates SPIRBase.td with new generated enum definitions.
- Arguments:
- - path: the path to SPIRBase.td
- - operand_kinds: a list containing all operand kinds' grammar
- - filter_list: a list containing new enums to add
+ Arguments:
+ - path: the path to SPIRBase.td
+ - operand_kinds: a list containing all operand kinds' grammar
+ - filter_list: a list containing new enums to add
"""
with open(path, 'r') as f:
content = f.read()
assert len(content) == 3
# Extend filter list with existing enum definitions
- import re
existing_kinds = [
k[8:-4] for k in re.findall('def SPV_\w+Attr', content[1])]
filter_list.extend(existing_kinds)
f.write(content)
+def snake_casify(name):
+ """Turns the given name to follow snake_case convension."""
+ name = re.sub('\W+', '', name).split()
+ name = [s.lower() for s in name]
+ return '_'.join(name)
+
+
+def map_spec_operand_to_ods_argument(operand):
+ """Maps a operand in SPIR-V JSON spec to an op argument in ODS.
+
+ Arguments:
+ - A dict containing the operand's kind, quantifier, and name
+
+ Returns:
+ - A string containing both the type and name for the argument
+ """
+ kind = operand['kind']
+ quantifier = operand.get('quantifier', '')
+
+ # These instruction "operands" are for encoding the results; they should
+ # not be handled here.
+ assert kind != 'IdResultType', 'unexpected to handle "IdResultType" kind'
+ assert kind != 'IdResult', 'unexpected to handle "IdResult" kind'
+
+ if kind == 'IdRef':
+ if quantifier == '':
+ arg_type = 'SPV_Type'
+ elif quantifier == '?':
+ arg_type = 'SPV_Optional<SPV_Type>'
+ else:
+ arg_type = 'Variadic<SPV_Type>'
+ elif kind == 'IdMemorySemantics' or kind == 'IdScope':
+ # TODO(antiagainst): Need to further constrain 'IdMemorySemantics'
+ # and 'IdScope' given that they should be gernated from OpConstant.
+ assert quantifier == '', ('unexpected to have optional/variadic memory '
+ 'semantics or scope <id>')
+ arg_type = 'I32'
+ elif kind == 'LiteralInteger':
+ if quantifier == '':
+ arg_type = 'I32Attr'
+ elif quantifier == '?':
+ arg_type = 'OptionalAttr<I32Attr>'
+ else:
+ arg_type = 'OptionalAttr<I32ArrayAttr>'
+ elif kind == 'LiteralString' or \
+ kind == 'LiteralContextDependentNumber' or \
+ kind == 'LiteralExtInstInteger' or \
+ kind == 'LiteralSpecConstantOpInteger' or \
+ kind == 'PairLiteralIntegerIdRef' or \
+ kind == 'PairIdRefLiteralInteger' or \
+ kind == 'PairIdRefIdRef':
+ assert False, '"{}" kind unimplemented'.format(kind)
+ else:
+ # The rest are all enum operands that we represent with op attributes.
+ assert quantifier != '*', 'unexpected to have variadic enum attribute'
+ arg_type = 'SPV_{}Attr'.format(kind)
+ if quantifier == '?':
+ arg_type = 'OptionalAttr<{}>'.format(arg_type)
+
+ name = operand.get('name', '')
+ name = snake_casify(name) if name else kind.lower()
+
+ return '{}:${}'.format(arg_type, name)
+
+
+def get_op_definition(instruction, doc, existing_info):
+ """Generates the TableGen op definition for the given SPIR-V instruction.
+
+ Arguments:
+ - instruction: the instruction's SPIR-V JSON grammar
+ - doc: the instruction's SPIR-V HTML doc
+ - existing_info: a dict containing potential manually specified sections for
+ this instruction
+
+ Returns:
+ - A string containing the TableGen op definition
+ """
+ fmt_str = 'def SPV_{opname}Op : SPV_Op<"{opname}", [{traits}]> {{\n'\
+ ' let summary = {summary};\n\n'\
+ ' let description = [{{\n'\
+ '{description}\n\n'\
+ ' ### Custom assembly form\n'\
+ '{assembly}'\
+ '}}];\n\n'\
+ ' let arguments = (ins{args});\n\n'\
+ ' let results = (outs{results});\n'\
+ '{extras}'\
+ '}}\n'
+
+ opname = instruction['opname'][2:]
+
+ summary, description = doc.split('\n', 1)
+ wrapper = textwrap.TextWrapper(
+ width=76, initial_indent=' ', subsequent_indent=' ')
+
+ # Format summary. If the summary can fit in the same line, we print it out
+ # as a "-quoted string; otherwise, wrap the lines using "[{...}]".
+ summary = summary.strip();
+ if len(summary) + len(' let summary = "";') <= 80:
+ summary = '"{}"'.format(summary)
+ else:
+ summary = '[{{\n{}\n }}]'.format(wrapper.fill(summary))
+
+ # Wrap description
+ description = description.split('\n')
+ description = [wrapper.fill(line) for line in description if line]
+ description = '\n\n'.join(description)
+
+ operands = instruction.get('operands', [])
+
+ # Set op's result
+ results = ''
+ if len(operands) > 0 and operands[0]['kind'] == 'IdResultType':
+ results = '\n SPV_Type:$result\n '
+ operands = operands[1:]
+ if 'results' in existing_info:
+ results = existing_info['results']
+
+ # Ignore the operand standing for the result <id>
+ if len(operands) > 0 and operands[0]['kind'] == 'IdResult':
+ operands = operands[1:]
+
+ # Set op' argument
+ arguments = existing_info.get('arguments', None)
+ if arguments is None:
+ arguments = [map_spec_operand_to_ods_argument(o) for o in operands]
+ arguments = '\n '.join(arguments)
+ if arguments:
+ # Prepend and append whitespace for formatting
+ arguments = '\n {}\n '.format(arguments)
+
+ assembly = existing_info.get('assembly', None)
+ if assembly is None:
+ assembly = ' ``` {.ebnf}\n'\
+ ' [TODO]\n'\
+ ' ```\n\n'\
+ ' For example:\n\n'\
+ ' ```\n'\
+ ' [TODO]\n'\
+ ' ```\n '
+
+ return fmt_str.format(
+ opname=opname,
+ traits=existing_info.get('traits', ''),
+ summary=summary,
+ description=description,
+ assembly=assembly,
+ args=arguments,
+ results=results,
+ extras=existing_info.get('extras', ''))
+
+
+def extract_td_op_info(op_def):
+ """Extracts potentially manually specified sections in op's definition.
+
+ Arguments: - A string containing the op's TableGen definition
+ - doc: the instruction's SPIR-V HTML doc
+
+ Returns:
+ - A dict containing potential manually specified sections
+ """
+ # Get opname
+ opname = [o[8:-2] for o in re.findall('def SPV_\w+Op', op_def)]
+ assert len(opname) == 1, 'more than one ops in the same section!'
+ opname = opname[0]
+
+ # Get traits
+ op_tmpl_params = op_def.split('<', 1)[1].split('>', 1)[0].split(', ', 1)
+ if len(op_tmpl_params) == 1:
+ traits = ''
+ else:
+ traits = op_tmpl_params[1].strip('[]')
+
+ # Get custom assembly form
+ rest = op_def.split('### Custom assembly form\n')
+ assert len(rest) == 2, \
+ '{}: cannot find "### Custom assembly form"'.format(opname)
+ rest = rest[1].split(' let arguments = (ins')
+ assert len(rest) == 2, '{}: cannot find arguments'.format(opname)
+ assembly = rest[0].rstrip('}];\n')
+
+ # Get arguments
+ rest = rest[1].split(' let results = (outs')
+ assert len(rest) == 2, '{}: cannot find results'.format(opname)
+ args = rest[0].rstrip(');\n')
+
+ # Get results
+ rest = rest[1].split(');', 1)
+ assert len(rest) == 2, \
+ '{}: cannot find ");" ending results'.format(opname)
+ results = rest[0]
+
+ extras = rest[1].strip(' }\n')
+ if extras:
+ extras = '\n {}\n'.format(extras)
+
+ return {
+ # Prefix with 'Op' to make it consistent with SPIR-V spec
+ 'opname': 'Op{}'.format(opname),
+ 'traits': traits,
+ 'assembly': assembly,
+ 'arguments': args,
+ 'results': results,
+ 'extras': extras
+ }
+
+
+def update_td_op_definitions(path, instructions, docs, filter_list):
+ """Updates SPIRVOps.td with newly generated op definition.
+
+ Arguments:
+ - path: path to SPIRVOps.td
+ - instructions: SPIR-V JSON grammar for all instructions
+ - docs: SPIR-V HTML doc for all instructions
+ - filter_list: a list containing new opnames to include
+
+ Returns:
+ - A string containing all the TableGen op definitions
+ """
+ with open(path, 'r') as f:
+ content = f.read()
+
+ # Split the file into chuncks, each containing one op.
+ ops = content.split(AUTOGEN_OP_DEF_SEPARATOR)
+ header = ops[0]
+ footer = ops[-1]
+ ops = ops[1:-1]
+
+ # For each existing op, extract the manually-written sections out to retain
+ # them when re-generating the ops. Also append the existing ops to filter
+ # list.
+ op_info_dict = {}
+ for op in ops:
+ info_dict = extract_td_op_info(op)
+ opname = info_dict['opname']
+ op_info_dict[opname] = info_dict
+ filter_list.append(opname)
+ filter_list = sorted(list(set(filter_list)))
+
+ op_defs = []
+ for opname in filter_list:
+ # Find the grammar spec for this op
+ instruction = next(
+ inst for inst in instructions if inst['opname'] == opname)
+ op_defs.append(
+ get_op_definition(instruction, docs[opname],
+ op_info_dict.get(opname, {})))
+
+ # Substitute the old op definitions
+ op_defs = [header] + op_defs + [footer]
+ content = AUTOGEN_OP_DEF_SEPARATOR.join(op_defs)
+
+ with open(path, 'w') as f:
+ f.write(content)
+
+
if __name__ == '__main__':
import argparse
cli_parser = argparse.ArgumentParser(
description='Update SPIR-V dialect definitions using SPIR-V spec')
- cli_parser.add_argument('--base-td-path', dest='base_td_path', type=str,
- help='Path to SPIRVBase.td')
- cli_parser.add_argument('--new-enum', dest='new_enum', type=str,
- help='SPIR-V enum to be added to SPIRVBase.td')
+
+ cli_parser.add_argument(
+ '--base-td-path',
+ dest='base_td_path',
+ type=str,
+ default=None,
+ help='Path to SPIRVBase.td')
+ cli_parser.add_argument(
+ '--op-td-path',
+ dest='op_td_path',
+ type=str,
+ default=None,
+ help='Path to SPIRVOps.td')
+
+ cli_parser.add_argument(
+ '--new-enum',
+ dest='new_enum',
+ type=str,
+ default=None,
+ help='SPIR-V enum to be added to SPIRVBase.td')
cli_parser.add_argument(
'--new-opcodes',
dest='new_opcodes',
type=str,
+ default=None,
nargs='*',
help='update SPIR-V opcodes in SPIRVBase.td')
+ cli_parser.add_argument(
+ '--new-inst',
+ dest='new_inst',
+ type=str,
+ default=None,
+ help='SPIR-V instruction to be added to SPIRVOps.td')
+
args = cli_parser.parse_args()
operand_kinds, instructions = get_spirv_grammar_from_json_spec()
- update_td_enum_attrs(args.base_td_path, operand_kinds, [args.new_enum])
-
- update_td_opcodes(args.base_td_path, instructions, args.new_opcodes)
+ # Define new enum attr
+ if args.new_enum is not None:
+ assert args.base_td_path is not None
+ filter_list = [args.new_enum] if args.new_enum else []
+ update_td_enum_attrs(args.base_td_path, operand_kinds, filter_list)
+
+ # Define new opcode
+ if args.new_opcodes is not None:
+ assert args.base_td_path is not None
+ update_td_opcodes(args.base_td_path, instructions, args.new_opcodes)
+
+ # Define new op
+ if args.new_inst is not None:
+ assert args.op_td_path is not None
+ filter_list = [args.new_inst] if args.new_inst else []
+ docs = get_spirv_doc_from_html_spec()
+ update_td_op_definitions(args.op_td_path, instructions, docs, filter_list)
+ print('Done. Note that this script just generates a template; ', end='')
+ print('please read the spec and update traits, arguments, and ', end='')
+ print('results accordingly.')