|  | #!/usr/bin/env python | 
|  | # Copyright (c) 2016 Google Inc. | 
|  |  | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  | """Generates Vim syntax rules for SPIR-V assembly (.spvasm) files""" | 
|  |  | 
|  | import json | 
|  |  | 
|  | PREAMBLE="""" Vim syntax file | 
|  | " Language:   spvasm | 
|  | " Generated by SPIRV-Tools | 
|  |  | 
|  | if version < 600 | 
|  | syntax clear | 
|  | elseif exists("b:current_syntax") | 
|  | finish | 
|  | endif | 
|  |  | 
|  | syn case match | 
|  | """ | 
|  |  | 
|  | POSTAMBLE=""" | 
|  |  | 
|  | syntax keyword spvasmTodo TODO FIXME contained | 
|  |  | 
|  | syn match   spvasmIdNumber /%\d\+\>/ | 
|  |  | 
|  | " The assembler treats the leading minus sign as part of the number token. | 
|  | " This applies to integers, and to floats below. | 
|  | syn match   spvasmNumber /-\?\<\d\+\>/ | 
|  |  | 
|  | " Floating point literals. | 
|  | " In general, C++ requires at least digit in the mantissa, and the | 
|  | " floating point is optional.  This applies to both the regular decimal float | 
|  | " case and the hex float case. | 
|  |  | 
|  | " First case: digits before the optional decimal, no trailing digits. | 
|  | syn match   spvasmFloat  /-\?\d\+\.\?\(e[+-]\d\+\)\?/ | 
|  | " Second case: optional digits before decimal, trailing digits | 
|  | syn match   spvasmFloat  /-\?\d*\.\d\+\(e[+-]\d\+\)\?/ | 
|  |  | 
|  | " First case: hex digits before the optional decimal, no trailing hex digits. | 
|  | syn match   spvasmFloat  /-\?0[xX]\\x\+\.\?p[-+]\d\+/ | 
|  | " Second case: optional hex digits before decimal, trailing hex digits | 
|  | syn match   spvasmFloat  /-\?0[xX]\\x*\.\\x\+p[-+]\d\+/ | 
|  |  | 
|  | syn match   spvasmComment /;.*$/ contains=spvasmTodo | 
|  | syn region  spvasmString start=/"/ skip=/\\\\"/ end=/"/ | 
|  | syn match   spvasmId /%[a-zA-Z_][a-zA-Z_0-9]*/ | 
|  |  | 
|  | " Highlight unknown constants and statements as errors | 
|  | syn match   spvasmError /[a-zA-Z][a-zA-Z_0-9]*/ | 
|  |  | 
|  |  | 
|  | if version >= 508 || !exists("did_c_syn_inits") | 
|  | if version < 508 | 
|  | let did_c_syn_inits = 1 | 
|  | command -nargs=+ HiLink hi link <args> | 
|  | else | 
|  | command -nargs=+ HiLink hi def link <args> | 
|  | endif | 
|  |  | 
|  | HiLink spvasmStatement Statement | 
|  | HiLink spvasmNumber Number | 
|  | HiLink spvasmComment Comment | 
|  | HiLink spvasmString String | 
|  | HiLink spvasmFloat Float | 
|  | HiLink spvasmConstant Constant | 
|  | HiLink spvasmIdNumber Identifier | 
|  | HiLink spvasmId Identifier | 
|  | HiLink spvasmTodo Todo | 
|  |  | 
|  | delcommand HiLink | 
|  | endif | 
|  |  | 
|  | let b:current_syntax = "spvasm" | 
|  | """ | 
|  |  | 
|  | # This list is taken from the description of OpSpecConstantOp in SPIR-V 1.1. | 
|  | # TODO(dneto): Propose that this information be embedded in the grammar file. | 
|  | SPEC_CONSTANT_OP_OPCODES = """ | 
|  | OpSConvert, OpFConvert | 
|  | OpSNegate, OpNot | 
|  | OpIAdd, OpISub | 
|  | OpIMul, OpUDiv, OpSDiv, OpUMod, OpSRem, OpSMod | 
|  | OpShiftRightLogical, OpShiftRightArithmetic, OpShiftLeftLogical | 
|  | OpBitwiseOr, OpBitwiseXor, OpBitwiseAnd | 
|  | OpVectorShuffle, OpCompositeExtract, OpCompositeInsert | 
|  | OpLogicalOr, OpLogicalAnd, OpLogicalNot, | 
|  | OpLogicalEqual, OpLogicalNotEqual | 
|  | OpSelect | 
|  | OpIEqual, OpINotEqual | 
|  | OpULessThan, OpSLessThan | 
|  | OpUGreaterThan, OpSGreaterThan | 
|  | OpULessThanEqual, OpSLessThanEqual | 
|  | OpUGreaterThanEqual, OpSGreaterThanEqual | 
|  |  | 
|  | OpQuantizeToF16 | 
|  |  | 
|  | OpConvertFToS, OpConvertSToF | 
|  | OpConvertFToU, OpConvertUToF | 
|  | OpUConvert | 
|  | OpConvertPtrToU, OpConvertUToPtr | 
|  | OpGenericCastToPtr, OpPtrCastToGeneric | 
|  | OpBitcast | 
|  | OpFNegate | 
|  | OpFAdd, OpFSub | 
|  | OpFMul, OpFDiv | 
|  | OpFRem, OpFMod | 
|  | OpAccessChain, OpInBoundsAccessChain | 
|  | OpPtrAccessChain, OpInBoundsPtrAccessChain""" | 
|  |  | 
|  |  | 
|  | def EmitAsStatement(name): | 
|  | """Emits the given name as a statement token""" | 
|  | print('syn keyword spvasmStatement', name) | 
|  |  | 
|  |  | 
|  | def EmitAsEnumerant(name): | 
|  | """Emits the given name as an named operand token""" | 
|  | print('syn keyword spvasmConstant', name) | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | """Parses arguments, then generates the Vim syntax rules for SPIR-V assembly | 
|  | on stdout.""" | 
|  | import argparse | 
|  | parser = argparse.ArgumentParser(description='Generate SPIR-V info tables') | 
|  | parser.add_argument('--spirv-core-grammar', metavar='<path>', | 
|  | type=str, required=True, | 
|  | help='input JSON grammar file for core SPIR-V ' | 
|  | 'instructions') | 
|  | parser.add_argument('--extinst-glsl-grammar', metavar='<path>', | 
|  | type=str, required=False, default=None, | 
|  | help='input JSON grammar file for GLSL extended ' | 
|  | 'instruction set') | 
|  | parser.add_argument('--extinst-opencl-grammar', metavar='<path>', | 
|  | type=str, required=False, default=None, | 
|  | help='input JSON grammar file for OpenGL extended ' | 
|  | 'instruction set') | 
|  | parser.add_argument('--extinst-debuginfo-grammar', metavar='<path>', | 
|  | type=str, required=False, default=None, | 
|  | help='input JSON grammar file for DebugInfo extended ' | 
|  | 'instruction set') | 
|  | args = parser.parse_args() | 
|  |  | 
|  | # Generate the syntax rules. | 
|  | print(PREAMBLE) | 
|  |  | 
|  | core = json.loads(open(args.spirv_core_grammar).read()) | 
|  | print('\n" Core instructions') | 
|  | for inst in core["instructions"]: | 
|  | EmitAsStatement(inst['opname']) | 
|  | 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']) | 
|  |  | 
|  | if args.extinst_glsl_grammar is not None: | 
|  | print('\n" GLSL.std.450 extended instructions') | 
|  | glsl = json.loads(open(args.extinst_glsl_grammar).read()) | 
|  | # These opcodes are really enumerant operands for the OpExtInst | 
|  | # instruction. | 
|  | for inst in glsl["instructions"]: | 
|  | EmitAsEnumerant(inst['opname']) | 
|  |  | 
|  | if args.extinst_opencl_grammar is not None: | 
|  | print('\n" OpenCL.std extended instructions') | 
|  | opencl = json.loads(open(args.extinst_opencl_grammar).read()) | 
|  | for inst in opencl["instructions"]: | 
|  | EmitAsEnumerant(inst['opname']) | 
|  |  | 
|  | if args.extinst_debuginfo_grammar is not None: | 
|  | print('\n" DebugInfo extended instructions') | 
|  | debuginfo = json.loads(open(args.extinst_debuginfo_grammar).read()) | 
|  | for inst in debuginfo["instructions"]: | 
|  | EmitAsEnumerant(inst['opname']) | 
|  | print('\n" DebugInfo operand enums') | 
|  | for operand_kind in debuginfo["operand_kinds"]: | 
|  | if 'enumerants' in operand_kind: | 
|  | for e in operand_kind['enumerants']: | 
|  | EmitAsEnumerant(e['enumerant']) | 
|  |  | 
|  | print('\n" OpSpecConstantOp opcodes') | 
|  | for word in SPEC_CONSTANT_OP_OPCODES.split(' '): | 
|  | stripped = word.strip('\n,') | 
|  | if stripped != "": | 
|  | # Treat as an enumerant, but without the leading "Op" | 
|  | EmitAsEnumerant(stripped[2:]) | 
|  | print(POSTAMBLE) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main() |