xref: /aosp_15_r20/external/mesa3d/src/intel/vulkan/grl/grl_parser.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#!/bin/env python
2COPYRIGHT = """\
3/*
4 * Copyright 2021 Intel Corporation
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26"""
27
28import os
29import re
30import ply.lex as lex
31import ply.yacc as yacc
32
33# Libraries
34
35libraries = {}
36
37# LEXER
38
39keywords = {
40    '__debugbreak': 'KW_DEBUGBREAK',
41    'alignas': 'KW_ALIGNAS',
42    'args': 'KW_ARGS',
43    'atomic': 'KW_ATOMIC',
44    'atomic_return': 'KW_ATOMIC_RETURN',
45    'const': 'KW_CONST',
46    'control': 'KW_CONTROL',
47    'define': 'KW_DEFINE',
48    'dispatch': 'KW_DISPATCH',
49    'dispatch_indirect': 'KW_DISPATCH_INDIRECT',
50    'goto': 'KW_GOTO',
51    'if': 'KW_IF',
52    'kernel': 'KW_KERNEL',
53    'kernel_module': 'KW_KERNEL_MODULE',
54    'import': 'KW_IMPORT',
55    'library': 'KW_LIBRARY',
56    'links': 'KW_LINKS',
57    'load_dword': 'KW_LOAD_DWORD',
58    'load_qword': 'KW_LOAD_QWORD',
59    'metakernel': 'KW_METAKERNEL',
60    'module': 'KW_MODULE',
61    'not': 'KW_NOT',
62    'offsetof': 'KW_OFFSETOF',
63    'postsync': 'KW_POSTSYNC',
64    'print': 'KW_PRINT',
65    'semaphore_wait': 'KW_SEMAPHORE_WAIT',
66    'shiftof': 'KW_SHIFTOF',
67    'sizeof': 'KW_SIZEOF',
68    'store_dword': 'KW_STORE_DWORD',
69    'store_qword': 'KW_STORE_QWORD',
70    'store_timestamp': 'KW_STORE_TIMESTAMP',
71    'struct': 'KW_STRUCT',
72    'unsigned': 'KW_UNSIGNED',
73    'while': 'KW_WHILE'
74}
75
76ops = {
77    '&&': 'OP_LOGICAL_AND',
78    '||': 'OP_LOGICAL_OR',
79    '==': 'OP_EQUALEQUAL',
80    '!=': 'OP_NOTEQUAL',
81    '<=': 'OP_LESSEQUAL',
82    '>=': 'OP_GREATEREQUAL',
83    '<<': 'OP_LSHIFT',
84    '>>': 'OP_RSHIFT'
85}
86
87tokens = [
88    'INT_LITERAL',
89    'STRING_LITERAL',
90    'OP',
91    'IDENTIFIER'
92] + list(keywords.values()) + list(ops.values())
93
94def t_INT_LITERAL(t):
95    r'(0x[a-fA-F0-9]+|\d+)'
96    if t.value.startswith('0x'):
97        t.value = int(t.value[2:], 16)
98    else:
99        t.value = int(t.value)
100    return t
101
102def t_OP(t):
103    r'(&&|\|\||==|!=|<=|>=|<<|>>)'
104    t.type = ops.get(t.value)
105    return t
106
107def t_IDENTIFIER(t):
108    r'[a-zA-Z_][a-zA-Z_0-9]*'
109    t.type = keywords.get(t.value, 'IDENTIFIER')
110    return t
111
112def t_STRING_LITERAL(t):
113    r'"(\\.|[^"\\])*"'
114    t.value = t.value[1:-1]
115    return t
116
117literals = "+*/(){};:,=&|!~^.%?-<>[]"
118
119t_ignore = ' \t'
120
121def t_newline(t):
122    r'\n+'
123    t.lexer.lineno += len(t.value)
124
125def t_error(t):
126    print("WUT: {}".format(t.value))
127    t.lexer.skip(1)
128
129LEXER = lex.lex()
130
131# PARSER
132
133precedence = (
134    ('right', '?', ':'),
135    ('left', 'OP_LOGICAL_OR', 'OP_LOGICAL_AND'),
136    ('left', '|'),
137    ('left', '^'),
138    ('left', '&'),
139    ('left', 'OP_EQUALEQUAL', 'OP_NOTEQUAL'),
140    ('left', '<', '>', 'OP_LESSEQUAL', 'OP_GREATEREQUAL'),
141    ('left', 'OP_LSHIFT', 'OP_RSHIFT'),
142    ('left', '+', '-'),
143    ('left', '*', '/', '%'),
144    ('right', '!', '~'),
145    ('left', '[', ']', '.')
146)
147
148def p_module(p):
149    'module : element_list'
150    p[0] = p[1]
151
152def p_element_list(p):
153    '''element_list : element_list element
154                    | element'''
155    if len(p) == 2:
156        p[0] = [p[1]]
157    else:
158        p[0] = p[1] + [p[2]]
159
160def p_element(p):
161    '''element : kernel_definition
162               | kernel_module_definition
163               | library_definition
164               | metakernel_definition
165               | module_name
166               | struct_definition
167               | const_definition
168               | import_definition'''
169    p[0] = p[1]
170
171def p_module_name(p):
172    'module_name : KW_MODULE IDENTIFIER ";"'
173    p[0] = ('module-name', p[2])
174
175def p_kernel_module_definition(p):
176    'kernel_module_definition : KW_KERNEL_MODULE IDENTIFIER "(" STRING_LITERAL ")" "{" kernel_definition_list "}"'
177    p[0] = ('kernel-module', p[2], p[4], p[7])
178
179def p_kernel_definition(p):
180    'kernel_definition : KW_KERNEL IDENTIFIER optional_annotation_list'
181    p[0] = ('kernel', p[2], p[3])
182
183def p_library_definition(p):
184    'library_definition : KW_LIBRARY IDENTIFIER "{" library_definition_list "}"'
185    p[0] = ('library', p[2], p[4])
186
187def p_library_definition_list(p):
188    '''library_definition_list :
189                              | library_definition_list IDENTIFIER STRING_LITERAL ";"'''
190    if len(p) < 3:
191        p[0] = []
192    else:
193        p[0] = p[1]
194        p[0].append((p[2], p[3]))
195
196def p_import_definition(p):
197    'import_definition : KW_IMPORT KW_STRUCT IDENTIFIER STRING_LITERAL ";"'
198    p[0] = ('import', p[4], 'struct', p[3])
199
200def p_links_definition(p):
201    'links_definition : KW_LINKS IDENTIFIER'
202
203    # Process a library include like a preprocessor
204    global libraries
205
206    if not p[2] in libraries:
207        raise "Not able to find library {0}".format(p[2])
208    p[0] = libraries[p[2]]
209
210def p_metakernel_definition(p):
211    'metakernel_definition : KW_METAKERNEL IDENTIFIER "(" optional_parameter_list ")" optional_annotation_list scope'
212    p[0] = ('meta-kernel', p[2], p[4], p[6], p[7])
213
214def p_kernel_definition_list(p):
215    '''kernel_definition_list :
216                              | kernel_definition_list kernel_definition ";"
217                              | kernel_definition_list links_definition ";"'''
218    if len(p) < 3:
219        p[0] = []
220    else:
221        p[0] = p[1]
222        p[0].append(p[2])
223
224def p_optional_annotation_list(p):
225    '''optional_annotation_list :
226                                | "<" ">"
227                                | "<" annotation_list ">"'''
228    if len(p) < 4:
229        p[0] = {}
230    else:
231        p[0] = p[2]
232
233def p_optional_parameter_list(p):
234    '''optional_parameter_list :
235                               | parameter_list'''
236    p[0] = p[1]
237
238def p_annotation_list(p):
239    '''annotation_list : annotation'''
240    p[0] = p[1]
241
242def p_annotation_list_append(p):
243    '''annotation_list : annotation_list "," annotation'''
244    p[0] = {**p[1], **p[3]}
245
246def p_annotation(p):
247    '''annotation : IDENTIFIER "=" INT_LITERAL
248                  | IDENTIFIER "=" IDENTIFIER
249                  | IDENTIFIER "=" STRING_LITERAL'''
250    p[0] = {p[1]: p[3]}
251
252def p_parameter_list(p):
253    '''parameter_list : parameter_definition'''
254    p[0] = [p[1]]
255
256def p_parameter_list_append(p):
257    '''parameter_list : parameter_list "," parameter_definition'''
258    p[0] = p[1]
259    p[0].append(p[3])
260
261def p_parameter_definition(p):
262    'parameter_definition : IDENTIFIER IDENTIFIER'
263    p[0] = (p[1], p[2])
264
265def p_scope(p):
266    '''scope : "{" optional_statement_list "}"'''
267    p[0] = p[2]
268
269def p_optional_statement_list(p):
270    '''optional_statement_list :
271                               | statement_list'''
272    p[0] = p[1]
273
274def p_statement_list(p):
275    '''statement_list : statement'''
276    p[0] = [p[1]]
277
278def p_statement_list_append(p):
279    '''statement_list : statement_list statement'''
280    p[0] = p[1]
281    p[0].append(p[2])
282
283def p_statement(p):
284    '''statement : definition_statement ";"
285                 | assignment_statement ";"
286                 | load_store_statement ";"
287                 | dispatch_statement ";"
288                 | semaphore_statement ";"
289                 | label
290                 | goto_statement ";"
291                 | scope_statement
292                 | atomic_op_statement ";"
293                 | control_statement ";"
294                 | print_statement ";"
295                 | debug_break_statement ";"'''
296    p[0] = p[1]
297
298def p_definition_statement(p):
299    'definition_statement : KW_DEFINE IDENTIFIER value'
300    p[0] = ('define', p[2], p[3])
301
302def p_assignemt_statement(p):
303    'assignment_statement : value "=" value'
304    p[0] = ('assign', p[1], p[3])
305
306def p_load_store_statement_load_dword(p):
307    '''load_store_statement : value "=" KW_LOAD_DWORD "(" value ")"'''
308    p[0] = ('load-dword', p[1], p[5])
309
310def p_load_store_statement_load_qword(p):
311    '''load_store_statement : value "=" KW_LOAD_QWORD "(" value ")"'''
312    p[0] = ('load-qword', p[1], p[5])
313
314def p_load_store_statement_store_dword(p):
315    '''load_store_statement : KW_STORE_DWORD "(" value "," value ")"'''
316    p[0] = ('store-dword', p[3], p[5])
317
318def p_load_store_statement_store_qword(p):
319    '''load_store_statement : KW_STORE_QWORD "(" value "," value ")"'''
320    p[0] = ('store-qword', p[3], p[5])
321
322def p_dispatch_statement(p):
323    '''dispatch_statement : direct_dispatch_statement
324                          | indirect_dispatch_statement'''
325    p[0] = p[1]
326
327def p_direct_dispatch_statement(p):
328    '''direct_dispatch_statement : KW_DISPATCH IDENTIFIER "(" value "," value "," value ")" optional_kernel_arg_list optional_postsync'''
329    p[0] = ('dispatch', p[2], (p[4], p[6], p[8]), p[10], p[11])
330
331def p_indirect_dispatch_statement(p):
332    '''indirect_dispatch_statement : KW_DISPATCH_INDIRECT IDENTIFIER optional_kernel_arg_list optional_postsync'''
333    p[0] = ('dispatch', p[2], None, p[3], p[4])
334
335def p_optional_kernel_arg_list(p):
336    '''optional_kernel_arg_list :
337                                | KW_ARGS "(" value_list ")"'''
338    p[0] = p[3]
339
340def p_value_list(p):
341    '''value_list : value'''
342    p[0] = [p[1]]
343
344def p_value_list_append(p):
345    '''value_list : value_list "," value'''
346    p[0] = p[1]
347    p[0].append(p[3])
348
349def p_optional_postsync(p):
350    '''optional_postsync :
351                         | postsync_operation'''
352    if len(p) > 1:
353        p[0] = p[1]
354
355def p_postsync_operation(p):
356    '''postsync_operation : postsync_write_dword
357                          | postsync_write_timestamp'''
358    p[0] = p[1]
359
360def p_postsync_write_dword(p):
361    '''postsync_write_dword : KW_POSTSYNC KW_STORE_DWORD "(" value "," value ")"'''
362    p[0] = ('postsync', 'store-dword', p[4], p[6])
363
364def p_postsync_write_timestamp(p):
365    '''postsync_write_timestamp : KW_POSTSYNC KW_STORE_TIMESTAMP "(" value ")"'''
366    p[0] = ('postsync', 'timestamp', p[4])
367
368def p_semaphore_statement(p):
369    '''semaphore_statement : KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value "<" value ")"
370                           | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value ">" value ")"
371                           | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_LESSEQUAL value ")"
372                           | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_GREATEREQUAL value ")"
373                           | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_EQUALEQUAL value ")"
374                           | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_NOTEQUAL value ")"'''
375    p[0] = ('sem-wait-while', p[5], p[6], p[7])
376
377def p_atomic_op_statement(p):
378    '''atomic_op_statement : KW_ATOMIC IDENTIFIER IDENTIFIER "(" value_list ")"'''
379    p[0] = ('atomic', p[2], p[3], p[5])
380
381def p_atomic_op_statement_return(p):
382    '''atomic_op_statement : KW_ATOMIC_RETURN IDENTIFIER IDENTIFIER "(" value_list ")"'''
383    p[0] = ('atomic-return', p[2], p[3], p[5])
384
385def p_label(p):
386    '''label : IDENTIFIER ":"'''
387    p[0] = ('label', p[1])
388
389def p_goto_statement(p):
390    '''goto_statement : KW_GOTO IDENTIFIER'''
391    p[0] = ('goto', p[2])
392
393def p_goto_statement_if(p):
394    '''goto_statement : KW_GOTO IDENTIFIER KW_IF "(" value ")"'''
395    p[0] = ('goto-if', p[2], p[5])
396
397def p_goto_statement_if_not(p):
398    '''goto_statement : KW_GOTO IDENTIFIER KW_IF KW_NOT "(" value ")"'''
399    p[0] = ('goto-if-not', p[2], p[6])
400
401def p_scope_statement(p):
402    '''scope_statement : scope'''
403    p[0] = (p[1])
404
405def p_control_statement(p):
406    '''control_statement : KW_CONTROL "(" id_list ")"'''
407    p[0] = ('control', p[3])
408
409def p_print_statement(p):
410    '''print_statement : KW_PRINT "(" printable_list ")"'''
411    p[0] = ('print', p[3])
412
413def p_printable_list(p):
414    '''printable_list : printable'''
415    p[0] = [p[1]]
416
417def p_printable_list_append(p):
418    '''printable_list : printable_list "," printable'''
419    p[0] = p[1]
420    p[0].append(p[3])
421
422def p_printable_str_lit(p):
423    '''printable : STRING_LITERAL'''
424    p[0] = '"{}"'.format(p[1])
425
426def p_printable_value(p):
427    '''printable : value'''
428    p[0] = p[1]
429
430def p_printable_str_lit_value(p):
431    '''printable : STRING_LITERAL value'''
432    p[0] = ('"{}"'.format(p[1]), p[2])
433
434def p_debug_break_statement(p):
435    '''debug_break_statement : KW_DEBUGBREAK'''
436    p[0] = ('debug-break')
437
438def p_id_list(p):
439    '''id_list : IDENTIFIER'''
440    p[0] = p[1]
441
442def p_id_list_append(p):
443    '''id_list : id_list "," IDENTIFIER'''
444    p[0] = p[1]
445    p[0].append(p[3])
446
447def p_value(p):
448    '''value : IDENTIFIER
449             | INT_LITERAL'''
450    p[0] = p[1]
451
452def p_value_braces(p):
453    '''value : "(" value ")"'''
454    p[0] = (p[2])
455
456def p_value_member(p):
457    '''value : value "." IDENTIFIER'''
458    p[0] = ('member', p[1], p[3])
459
460def p_value_idx(p):
461    '''value : value "[" value "]"'''
462    p[0] = ('index', p[1], p[3])
463
464def p_value_binop(p):
465    '''value : value "+" value
466             | value "-" value
467             | value "*" value
468             | value "/" value
469             | value "%" value
470             | value "&" value
471             | value "|" value
472             | value "<" value
473             | value ">" value
474             | value "^" value
475             | value OP_LESSEQUAL value
476             | value OP_GREATEREQUAL value
477             | value OP_EQUALEQUAL value
478             | value OP_NOTEQUAL value
479             | value OP_LOGICAL_AND value
480             | value OP_LOGICAL_OR value
481             | value OP_LSHIFT value
482             | value OP_RSHIFT value'''
483    p[0] = (p[2], p[1], p[3])
484
485def p_value_uniop(p):
486    '''value : "!" value
487             | "~" value'''
488    p[0] = (p[1], p[2])
489
490def p_value_cond(p):
491    '''value : value "?" value ":" value'''
492    p[0] = ('?', p[1], p[3], p[5])
493
494def p_value_funcop(p):
495    '''value : KW_OFFSETOF "(" offset_expression ")"
496             | KW_SHIFTOF "(" IDENTIFIER ")"
497             | KW_SIZEOF "(" IDENTIFIER ")"'''
498    p[0] = (p[1], p[3])
499
500def p_offset_expression(p):
501    '''offset_expression : IDENTIFIER'''
502    p[0] = p[1]
503
504def p_offset_expression_member(p):
505    '''offset_expression : offset_expression "." IDENTIFIER'''
506    p[0] = ('member', p[1], p[3])
507
508def p_offset_expression_idx(p):
509    '''offset_expression : offset_expression "[" INT_LITERAL "]"'''
510    p[0] = ('index', p[1], p[3])
511
512def p_struct_definition(p):
513    '''struct_definition : KW_STRUCT optional_alignment_specifier IDENTIFIER "{" optional_struct_member_list "}" ";"'''
514    p[0] = ('struct', p[3], p[5], p[2])
515
516def p_optional_alignment_specifier(p):
517    '''optional_alignment_specifier :
518                                    | KW_ALIGNAS "(" INT_LITERAL ")"'''
519    if len(p) == 1:
520        p[0] = 0
521    else:
522        p[0] = p[3]
523
524def p_optional_struct_member_list(p):
525    '''optional_struct_member_list :
526                                   | struct_member_list'''
527    if len(p) == 1:
528        p[0] = {}
529    else:
530        p[0] = p[1]
531
532def p_struct_member_list(p):
533    '''struct_member_list : struct_member'''
534    p[0] = [p[1]]
535
536def p_struct_member_list_append(p):
537    '''struct_member_list : struct_member_list struct_member'''
538    p[0] = p[1] + [p[2]]
539
540def p_struct_member(p):
541    '''struct_member : struct_member_typename IDENTIFIER ";"'''
542    p[0] = (p[1], p[2])
543
544def p_struct_member_array(p):
545    '''struct_member : struct_member_typename IDENTIFIER "[" INT_LITERAL "]" ";"'''
546    '''struct_member : struct_member_typename IDENTIFIER "[" IDENTIFIER "]" ";"'''
547    p[0] = {p[1]: p[2], 'count': p[4]}
548
549def p_struct_member_typename(p):
550    '''struct_member_typename : IDENTIFIER'''
551    p[0] = p[1]
552
553def p_struct_member_typename_unsigned(p):
554    '''struct_member_typename : KW_UNSIGNED IDENTIFIER'''
555    p[0] = ('unsigned', p[2])
556
557def p_struct_member_typename_struct(p):
558    '''struct_member_typename : KW_STRUCT IDENTIFIER'''
559    p[0] = ('struct', p[2])
560
561def p_const_definition(p):
562    '''const_definition : KW_CONST IDENTIFIER "=" INT_LITERAL ";"'''
563    p[0] = ('named-constant', p[2], p[4])
564
565PARSER = yacc.yacc()
566
567# Shamelessly stolen from some StackOverflow answer
568def _remove_comments(text):
569    def replacer(match):
570        s = match.group(0)
571        if s.startswith('/'):
572            return " " # note: a space and not an empty string
573        else:
574            return s
575    pattern = re.compile(
576        r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
577        re.DOTALL | re.MULTILINE
578    )
579    return re.sub(pattern, replacer, text)
580
581def parse_grl_file(grl_fname, libs):
582    global libraries
583
584    libraries = libs
585    with open(grl_fname, 'r') as f:
586        return PARSER.parse(_remove_comments(f.read()))
587