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