1#!/usr/bin/env python 2# Copyright (c) 2016 Google Inc. 3 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Generates Vim syntax rules for SPIR-V assembly (.spvasm) files""" 16 17from __future__ import print_function 18 19import json 20 21PREAMBLE="""" Vim syntax file 22" Language: spvasm 23" Generated by SPIRV-Tools 24 25if version < 600 26 syntax clear 27elseif exists("b:current_syntax") 28 finish 29endif 30 31syn case match 32""" 33 34POSTAMBLE=""" 35 36syntax keyword spvasmTodo TODO FIXME contained 37 38syn match spvasmIdNumber /%\d\+\>/ 39 40" The assembler treats the leading minus sign as part of the number token. 41" This applies to integers, and to floats below. 42syn match spvasmNumber /-\?\<\d\+\>/ 43 44" Floating point literals. 45" In general, C++ requires at least digit in the mantissa, and the 46" floating point is optional. This applies to both the regular decimal float 47" case and the hex float case. 48 49" First case: digits before the optional decimal, no trailing digits. 50syn match spvasmFloat /-\?\d\+\.\?\(e[+-]\d\+\)\?/ 51" Second case: optional digits before decimal, trailing digits 52syn match spvasmFloat /-\?\d*\.\d\+\(e[+-]\d\+\)\?/ 53 54" First case: hex digits before the optional decimal, no trailing hex digits. 55syn match spvasmFloat /-\?0[xX]\\x\+\.\?p[-+]\d\+/ 56" Second case: optional hex digits before decimal, trailing hex digits 57syn match spvasmFloat /-\?0[xX]\\x*\.\\x\+p[-+]\d\+/ 58 59syn match spvasmComment /;.*$/ contains=spvasmTodo 60syn region spvasmString start=/"/ skip=/\\\\"/ end=/"/ 61syn match spvasmId /%[a-zA-Z_][a-zA-Z_0-9]*/ 62 63" Highlight unknown constants and statements as errors 64syn match spvasmError /[a-zA-Z][a-zA-Z_0-9]*/ 65 66 67if version >= 508 || !exists("did_c_syn_inits") 68 if version < 508 69 let did_c_syn_inits = 1 70 command -nargs=+ HiLink hi link <args> 71 else 72 command -nargs=+ HiLink hi def link <args> 73 endif 74 75 HiLink spvasmStatement Statement 76 HiLink spvasmNumber Number 77 HiLink spvasmComment Comment 78 HiLink spvasmString String 79 HiLink spvasmFloat Float 80 HiLink spvasmConstant Constant 81 HiLink spvasmIdNumber Identifier 82 HiLink spvasmId Identifier 83 HiLink spvasmTodo Todo 84 85 delcommand HiLink 86endif 87 88let b:current_syntax = "spvasm" 89""" 90 91# This list is taken from the description of OpSpecConstantOp in SPIR-V 1.1. 92# TODO(dneto): Propose that this information be embedded in the grammar file. 93SPEC_CONSTANT_OP_OPCODES = """ 94 OpSConvert, OpFConvert 95 OpSNegate, OpNot 96 OpIAdd, OpISub 97 OpIMul, OpUDiv, OpSDiv, OpUMod, OpSRem, OpSMod 98 OpShiftRightLogical, OpShiftRightArithmetic, OpShiftLeftLogical 99 OpBitwiseOr, OpBitwiseXor, OpBitwiseAnd 100 OpVectorShuffle, OpCompositeExtract, OpCompositeInsert 101 OpLogicalOr, OpLogicalAnd, OpLogicalNot, 102 OpLogicalEqual, OpLogicalNotEqual 103 OpSelect 104 OpIEqual, OpINotEqual 105 OpULessThan, OpSLessThan 106 OpUGreaterThan, OpSGreaterThan 107 OpULessThanEqual, OpSLessThanEqual 108 OpUGreaterThanEqual, OpSGreaterThanEqual 109 110 OpQuantizeToF16 111 112 OpConvertFToS, OpConvertSToF 113 OpConvertFToU, OpConvertUToF 114 OpUConvert 115 OpConvertPtrToU, OpConvertUToPtr 116 OpGenericCastToPtr, OpPtrCastToGeneric 117 OpBitcast 118 OpFNegate 119 OpFAdd, OpFSub 120 OpFMul, OpFDiv 121 OpFRem, OpFMod 122 OpAccessChain, OpInBoundsAccessChain 123 OpPtrAccessChain, OpInBoundsPtrAccessChain""" 124 125 126def EmitAsStatement(name): 127 """Emits the given name as a statement token""" 128 print('syn keyword spvasmStatement', name) 129 130 131def EmitAsEnumerant(name): 132 """Emits the given name as an named operand token""" 133 print('syn keyword spvasmConstant', name) 134 135 136def main(): 137 """Parses arguments, then generates the Vim syntax rules for SPIR-V assembly 138 on stdout.""" 139 import argparse 140 parser = argparse.ArgumentParser(description='Generate SPIR-V info tables') 141 parser.add_argument('--spirv-core-grammar', metavar='<path>', 142 type=str, required=True, 143 help='input JSON grammar file for core SPIR-V ' 144 'instructions') 145 parser.add_argument('--extinst-glsl-grammar', metavar='<path>', 146 type=str, required=False, default=None, 147 help='input JSON grammar file for GLSL extended ' 148 'instruction set') 149 parser.add_argument('--extinst-opencl-grammar', metavar='<path>', 150 type=str, required=False, default=None, 151 help='input JSON grammar file for OpenGL extended ' 152 'instruction set') 153 parser.add_argument('--extinst-debuginfo-grammar', metavar='<path>', 154 type=str, required=False, default=None, 155 help='input JSON grammar file for DebugInfo extended ' 156 'instruction set') 157 args = parser.parse_args() 158 159 # Generate the syntax rules. 160 print(PREAMBLE) 161 162 core = json.loads(open(args.spirv_core_grammar).read()) 163 print('\n" Core instructions') 164 for inst in core["instructions"]: 165 EmitAsStatement(inst['opname']) 166 print('\n" Core operand enums') 167 for operand_kind in core["operand_kinds"]: 168 if 'enumerants' in operand_kind: 169 for e in operand_kind['enumerants']: 170 EmitAsEnumerant(e['enumerant']) 171 172 if args.extinst_glsl_grammar is not None: 173 print('\n" GLSL.std.450 extended instructions') 174 glsl = json.loads(open(args.extinst_glsl_grammar).read()) 175 # These opcodes are really enumerant operands for the OpExtInst 176 # instruction. 177 for inst in glsl["instructions"]: 178 EmitAsEnumerant(inst['opname']) 179 180 if args.extinst_opencl_grammar is not None: 181 print('\n" OpenCL.std extended instructions') 182 opencl = json.loads(open(args.extinst_opencl_grammar).read()) 183 for inst in opencl["instructions"]: 184 EmitAsEnumerant(inst['opname']) 185 186 if args.extinst_debuginfo_grammar is not None: 187 print('\n" DebugInfo extended instructions') 188 debuginfo = json.loads(open(args.extinst_debuginfo_grammar).read()) 189 for inst in debuginfo["instructions"]: 190 EmitAsEnumerant(inst['opname']) 191 print('\n" DebugInfo operand enums') 192 for operand_kind in debuginfo["operand_kinds"]: 193 if 'enumerants' in operand_kind: 194 for e in operand_kind['enumerants']: 195 EmitAsEnumerant(e['enumerant']) 196 197 print('\n" OpSpecConstantOp opcodes') 198 for word in SPEC_CONSTANT_OP_OPCODES.split(' '): 199 stripped = word.strip('\n,') 200 if stripped != "": 201 # Treat as an enumerant, but without the leading "Op" 202 EmitAsEnumerant(stripped[2:]) 203 print(POSTAMBLE) 204 205 206if __name__ == '__main__': 207 main() 208