From 37663438f7535586f0c5bd1cd2b7aa6657f471dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Briano?= Date: Tue, 2 Mar 2021 14:34:10 -0600 Subject: [PATCH] anv/grl: Add a GRL file parser Reviewed-by: Lionel Landwerlin Acked-by: Caio Oliveira Part-of: --- src/intel/vulkan/grl/grl_parser.py | 586 +++++++++++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 src/intel/vulkan/grl/grl_parser.py diff --git a/src/intel/vulkan/grl/grl_parser.py b/src/intel/vulkan/grl/grl_parser.py new file mode 100644 index 00000000000..2d62b25a169 --- /dev/null +++ b/src/intel/vulkan/grl/grl_parser.py @@ -0,0 +1,586 @@ +#!/bin/env python +COPYRIGHT = """\ +/* + * Copyright 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +""" + +import os +import re +import ply.lex as lex +import ply.yacc as yacc + +# Libraries + +libraries = {} + +# LEXER + +keywords = { + '__debugbreak': 'KW_DEBUGBREAK', + 'alignas': 'KW_ALIGNAS', + 'args': 'KW_ARGS', + 'atomic': 'KW_ATOMIC', + 'atomic_return': 'KW_ATOMIC_RETURN', + 'const': 'KW_CONST', + 'control': 'KW_CONTROL', + 'define': 'KW_DEFINE', + 'dispatch': 'KW_DISPATCH', + 'dispatch_indirect': 'KW_DISPATCH_INDIRECT', + 'goto': 'KW_GOTO', + 'if': 'KW_IF', + 'kernel': 'KW_KERNEL', + 'kernel_module': 'KW_KERNEL_MODULE', + 'import': 'KW_IMPORT', + 'library': 'KW_LIBRARY', + 'links': 'KW_LINKS', + 'load_dword': 'KW_LOAD_DWORD', + 'load_qword': 'KW_LOAD_QWORD', + 'metakernel': 'KW_METAKERNEL', + 'module': 'KW_MODULE', + 'not': 'KW_NOT', + 'offsetof': 'KW_OFFSETOF', + 'postsync': 'KW_POSTSYNC', + 'print': 'KW_PRINT', + 'semaphore_wait': 'KW_SEMAPHORE_WAIT', + 'shiftof': 'KW_SHIFTOF', + 'sizeof': 'KW_SIZEOF', + 'store_dword': 'KW_STORE_DWORD', + 'store_qword': 'KW_STORE_QWORD', + 'store_timestamp': 'KW_STORE_TIMESTAMP', + 'struct': 'KW_STRUCT', + 'unsigned': 'KW_UNSIGNED', + 'while': 'KW_WHILE' +} + +ops = { + '&&': 'OP_LOGICAL_AND', + '||': 'OP_LOGICAL_OR', + '==': 'OP_EQUALEQUAL', + '!=': 'OP_NOTEQUAL', + '<=': 'OP_LESSEQUAL', + '>=': 'OP_GREATEREQUAL', + '<<': 'OP_LSHIFT', + '>>': 'OP_RSHIFT' +} + +tokens = [ + 'INT_LITERAL', + 'STRING_LITERAL', + 'OP', + 'IDENTIFIER' +] + list(keywords.values()) + list(ops.values()) + +def t_INT_LITERAL(t): + r'(0x[a-fA-F0-9]+|\d+)' + if t.value.startswith('0x'): + t.value = int(t.value[2:], 16) + else: + t.value = int(t.value) + return t + +def t_OP(t): + r'(&&|\|\||==|!=|<=|>=|<<|>>)' + t.type = ops.get(t.value) + return t + +def t_IDENTIFIER(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + t.type = keywords.get(t.value, 'IDENTIFIER') + return t + +def t_STRING_LITERAL(t): + r'"(\\.|[^"\\])*"' + t.value = t.value[1:-1] + return t + +literals = "+*/(){};:,=&|!~^.%?-<>[]" + +t_ignore = ' \t' + +def t_newline(t): + r'\n+' + t.lexer.lineno += len(t.value) + +def t_error(t): + print("WUT: {}".format(t.value)) + t.lexer.skip(1) + +LEXER = lex.lex() + +# PARSER + +precedence = ( + ('right', '?', ':'), + ('left', 'OP_LOGICAL_OR', 'OP_LOGICAL_AND'), + ('left', '|'), + ('left', '^'), + ('left', '&'), + ('left', 'OP_EQUALEQUAL', 'OP_NOTEQUAL'), + ('left', '<', '>', 'OP_LESSEQUAL', 'OP_GREATEREQUAL'), + ('left', 'OP_LSHIFT', 'OP_RSHIFT'), + ('left', '+', '-'), + ('left', '*', '/', '%'), + ('right', '!', '~'), + ('left', '[', ']', '.') +) + +def p_module(p): + 'module : element_list' + p[0] = p[1] + +def p_element_list(p): + '''element_list : element_list element + | element''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + +def p_element(p): + '''element : kernel_definition + | kernel_module_definition + | library_definition + | metakernel_definition + | module_name + | struct_definition + | const_definition + | import_definition''' + p[0] = p[1] + +def p_module_name(p): + 'module_name : KW_MODULE IDENTIFIER ";"' + p[0] = ('module-name', p[2]) + +def p_kernel_module_definition(p): + 'kernel_module_definition : KW_KERNEL_MODULE IDENTIFIER "(" STRING_LITERAL ")" "{" kernel_definition_list "}"' + p[0] = ('kernel-module', p[2], p[4], p[7]) + +def p_kernel_definition(p): + 'kernel_definition : KW_KERNEL IDENTIFIER optional_annotation_list' + p[0] = ('kernel', p[2], p[3]) + +def p_library_definition(p): + 'library_definition : KW_LIBRARY IDENTIFIER "{" library_definition_list "}"' + p[0] = ('library', p[2], p[4]) + +def p_library_definition_list(p): + '''library_definition_list : + | library_definition_list IDENTIFIER STRING_LITERAL ";"''' + if len(p) < 3: + p[0] = [] + else: + p[0] = p[1] + p[0].append((p[2], p[3])) + +def p_import_definition(p): + 'import_definition : KW_IMPORT KW_STRUCT IDENTIFIER STRING_LITERAL ";"' + p[0] = ('import', p[4], 'struct', p[3]) + +def p_links_definition(p): + 'links_definition : KW_LINKS IDENTIFIER' + + # Process a library include like a preprocessor + global libraries + + if not p[2] in libraries: + raise "Not able to find library {0}".format(p[2]) + p[0] = libraries[p[2]] + +def p_metakernel_definition(p): + 'metakernel_definition : KW_METAKERNEL IDENTIFIER "(" optional_parameter_list ")" optional_annotation_list scope' + p[0] = ('meta-kernel', p[2], p[4], p[6], p[7]) + +def p_kernel_definition_list(p): + '''kernel_definition_list : + | kernel_definition_list kernel_definition ";" + | kernel_definition_list links_definition ";"''' + if len(p) < 3: + p[0] = [] + else: + p[0] = p[1] + p[0].append(p[2]) + +def p_optional_annotation_list(p): + '''optional_annotation_list : + | "<" ">" + | "<" annotation_list ">"''' + if len(p) < 4: + p[0] = {} + else: + p[0] = p[2] + +def p_optional_parameter_list(p): + '''optional_parameter_list : + | parameter_list''' + p[0] = p[1] + +def p_annotation_list(p): + '''annotation_list : annotation''' + p[0] = p[1] + +def p_annotation_list_append(p): + '''annotation_list : annotation_list "," annotation''' + p[0] = {**p[1], **p[3]} + +def p_annotation(p): + '''annotation : IDENTIFIER "=" INT_LITERAL + | IDENTIFIER "=" IDENTIFIER + | IDENTIFIER "=" STRING_LITERAL''' + p[0] = {p[1]: p[3]} + +def p_parameter_list(p): + '''parameter_list : parameter_definition''' + p[0] = [p[1]] + +def p_parameter_list_append(p): + '''parameter_list : parameter_list "," parameter_definition''' + p[0] = p[1] + p[0].append(p[3]) + +def p_parameter_definition(p): + 'parameter_definition : IDENTIFIER IDENTIFIER' + p[0] = (p[1], p[2]) + +def p_scope(p): + '''scope : "{" optional_statement_list "}"''' + p[0] = p[2] + +def p_optional_statement_list(p): + '''optional_statement_list : + | statement_list''' + p[0] = p[1] + +def p_statement_list(p): + '''statement_list : statement''' + p[0] = [p[1]] + +def p_statement_list_append(p): + '''statement_list : statement_list statement''' + p[0] = p[1] + p[0].append(p[2]) + +def p_statement(p): + '''statement : definition_statement ";" + | assignment_statement ";" + | load_store_statement ";" + | dispatch_statement ";" + | semaphore_statement ";" + | label + | goto_statement ";" + | scope_statement + | atomic_op_statement ";" + | control_statement ";" + | print_statement ";" + | debug_break_statement ";"''' + p[0] = p[1] + +def p_definition_statement(p): + 'definition_statement : KW_DEFINE IDENTIFIER value' + p[0] = ('define', p[2], p[3]) + +def p_assignemt_statement(p): + 'assignment_statement : value "=" value' + p[0] = ('assign', p[1], p[3]) + +def p_load_store_statement_load_dword(p): + '''load_store_statement : value "=" KW_LOAD_DWORD "(" value ")"''' + p[0] = ('load-dword', p[1], p[5]) + +def p_load_store_statement_load_qword(p): + '''load_store_statement : value "=" KW_LOAD_QWORD "(" value ")"''' + p[0] = ('load-qword', p[1], p[5]) + +def p_load_store_statement_store_dword(p): + '''load_store_statement : KW_STORE_DWORD "(" value "," value ")"''' + p[0] = ('store-dword', p[3], p[5]) + +def p_load_store_statement_store_qword(p): + '''load_store_statement : KW_STORE_QWORD "(" value "," value ")"''' + p[0] = ('store-qword', p[3], p[5]) + +def p_dispatch_statement(p): + '''dispatch_statement : direct_dispatch_statement + | indirect_dispatch_statement''' + p[0] = p[1] + +def p_direct_dispatch_statement(p): + '''direct_dispatch_statement : KW_DISPATCH IDENTIFIER "(" value "," value "," value ")" optional_kernel_arg_list optional_postsync''' + p[0] = ('dispatch', p[2], (p[4], p[6], p[8]), p[10], p[11]) + +def p_indirect_dispatch_statement(p): + '''indirect_dispatch_statement : KW_DISPATCH_INDIRECT IDENTIFIER optional_kernel_arg_list optional_postsync''' + p[0] = ('dispatch', p[2], None, p[3], p[4]) + +def p_optional_kernel_arg_list(p): + '''optional_kernel_arg_list : + | KW_ARGS "(" value_list ")"''' + p[0] = p[3] + +def p_value_list(p): + '''value_list : value''' + p[0] = [p[1]] + +def p_value_list_append(p): + '''value_list : value_list "," value''' + p[0] = p[1] + p[0].append(p[3]) + +def p_optional_postsync(p): + '''optional_postsync : + | postsync_operation''' + if len(p) > 1: + p[0] = p[1] + +def p_postsync_operation(p): + '''postsync_operation : postsync_write_dword + | postsync_write_timestamp''' + p[0] = p[1] + +def p_postsync_write_dword(p): + '''postsync_write_dword : KW_POSTSYNC KW_STORE_DWORD "(" value "," value ")"''' + p[0] = ('postsync', 'store-dword', p[4], p[6]) + +def p_postsync_write_timestamp(p): + '''postsync_write_timestamp : KW_POSTSYNC KW_STORE_TIMESTAMP "(" value ")"''' + p[0] = ('postsync', 'timestamp', p[4]) + +def p_semaphore_statement(p): + '''semaphore_statement : KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value "<" value ")" + | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value ">" value ")" + | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_LESSEQUAL value ")" + | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_GREATEREQUAL value ")" + | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_EQUALEQUAL value ")" + | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_NOTEQUAL value ")"''' + p[0] = ('sem-wait-while', p[5], p[6], p[7]) + +def p_atomic_op_statement(p): + '''atomic_op_statement : KW_ATOMIC IDENTIFIER IDENTIFIER "(" value_list ")"''' + p[0] = ('atomic', p[2], p[3], p[5]) + +def p_atomic_op_statement_return(p): + '''atomic_op_statement : KW_ATOMIC_RETURN IDENTIFIER IDENTIFIER "(" value_list ")"''' + p[0] = ('atomic-return', p[2], p[3], p[5]) + +def p_label(p): + '''label : IDENTIFIER ":"''' + p[0] = ('label', p[1]) + +def p_goto_statement(p): + '''goto_statement : KW_GOTO IDENTIFIER''' + p[0] = ('goto', p[2]) + +def p_goto_statement_if(p): + '''goto_statement : KW_GOTO IDENTIFIER KW_IF "(" value ")"''' + p[0] = ('goto-if', p[2], p[5]) + +def p_goto_statement_if_not(p): + '''goto_statement : KW_GOTO IDENTIFIER KW_IF KW_NOT "(" value ")"''' + p[0] = ('goto-if-not', p[2], p[6]) + +def p_scope_statement(p): + '''scope_statement : scope''' + p[0] = (p[1]) + +def p_control_statement(p): + '''control_statement : KW_CONTROL "(" id_list ")"''' + p[0] = ('control', p[3]) + +def p_print_statement(p): + '''print_statement : KW_PRINT "(" printable_list ")"''' + p[0] = ('print', p[3]) + +def p_printable_list(p): + '''printable_list : printable''' + p[0] = [p[1]] + +def p_printable_list_append(p): + '''printable_list : printable_list "," printable''' + p[0] = p[1] + p[0].append(p[3]) + +def p_printable_str_lit(p): + '''printable : STRING_LITERAL''' + p[0] = '"{}"'.format(p[1]) + +def p_printable_value(p): + '''printable : value''' + p[0] = p[1] + +def p_printable_str_lit_value(p): + '''printable : STRING_LITERAL value''' + p[0] = ('"{}"'.format(p[1]), p[2]) + +def p_debug_break_statement(p): + '''debug_break_statement : KW_DEBUGBREAK''' + p[0] = ('debug-break') + +def p_id_list(p): + '''id_list : IDENTIFIER''' + p[0] = p[1] + +def p_id_list_append(p): + '''id_list : id_list "," IDENTIFIER''' + p[0] = p[1] + p[0].append(p[3]) + +def p_value(p): + '''value : IDENTIFIER + | INT_LITERAL''' + p[0] = p[1] + +def p_value_braces(p): + '''value : "(" value ")"''' + p[0] = (p[2]) + +def p_value_member(p): + '''value : value "." IDENTIFIER''' + p[0] = ('member', p[1], p[3]) + +def p_value_idx(p): + '''value : value "[" value "]"''' + p[0] = ('index', p[1], p[3]) + +def p_value_binop(p): + '''value : value "+" value + | value "-" value + | value "*" value + | value "/" value + | value "%" value + | value "&" value + | value "|" value + | value "<" value + | value ">" value + | value "^" value + | value OP_LESSEQUAL value + | value OP_GREATEREQUAL value + | value OP_EQUALEQUAL value + | value OP_NOTEQUAL value + | value OP_LOGICAL_AND value + | value OP_LOGICAL_OR value + | value OP_LSHIFT value + | value OP_RSHIFT value''' + p[0] = (p[2], p[1], p[3]) + +def p_value_uniop(p): + '''value : "!" value + | "~" value''' + p[0] = (p[1], p[2]) + +def p_value_cond(p): + '''value : value "?" value ":" value''' + p[0] = ('?', p[1], p[3], p[5]) + +def p_value_funcop(p): + '''value : KW_OFFSETOF "(" offset_expression ")" + | KW_SHIFTOF "(" IDENTIFIER ")" + | KW_SIZEOF "(" IDENTIFIER ")"''' + p[0] = (p[1], p[3]) + +def p_offset_expression(p): + '''offset_expression : IDENTIFIER''' + p[0] = p[1] + +def p_offset_expression_member(p): + '''offset_expression : offset_expression "." IDENTIFIER''' + p[0] = ('member', p[1], p[3]) + +def p_offset_expression_idx(p): + '''offset_expression : offset_expression "[" INT_LITERAL "]"''' + p[0] = ('index', p[1], p[3]) + +def p_struct_definition(p): + '''struct_definition : KW_STRUCT optional_alignment_specifier IDENTIFIER "{" optional_struct_member_list "}" ";"''' + p[0] = ('struct', p[3], p[5], p[2]) + +def p_optional_alignment_specifier(p): + '''optional_alignment_specifier : + | KW_ALIGNAS "(" INT_LITERAL ")"''' + if len(p) == 1: + p[0] = 0 + else: + p[0] = p[3] + +def p_optional_struct_member_list(p): + '''optional_struct_member_list : + | struct_member_list''' + if len(p) == 1: + p[0] = {} + else: + p[0] = p[1] + +def p_struct_member_list(p): + '''struct_member_list : struct_member''' + p[0] = [p[1]] + +def p_struct_member_list_append(p): + '''struct_member_list : struct_member_list struct_member''' + p[0] = p[1] + [p[2]] + +def p_struct_member(p): + '''struct_member : struct_member_typename IDENTIFIER ";"''' + p[0] = (p[1], p[2]) + +def p_struct_member_array(p): + '''struct_member : struct_member_typename IDENTIFIER "[" INT_LITERAL "]" ";"''' + '''struct_member : struct_member_typename IDENTIFIER "[" IDENTIFIER "]" ";"''' + p[0] = {p[1]: p[2], 'count': p[4]} + +def p_struct_member_typename(p): + '''struct_member_typename : IDENTIFIER''' + p[0] = p[1] + +def p_struct_member_typename_unsigned(p): + '''struct_member_typename : KW_UNSIGNED IDENTIFIER''' + p[0] = ('unsigned', p[2]) + +def p_struct_member_typename_struct(p): + '''struct_member_typename : KW_STRUCT IDENTIFIER''' + p[0] = ('struct', p[2]) + +def p_const_definition(p): + '''const_definition : KW_CONST IDENTIFIER "=" INT_LITERAL ";"''' + p[0] = ('named-constant', p[2], p[4]) + +PARSER = yacc.yacc() + +# Shamelessly stolen from some StackOverflow answer +def _remove_comments(text): + def replacer(match): + s = match.group(0) + if s.startswith('/'): + return " " # note: a space and not an empty string + else: + return s + pattern = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE + ) + return re.sub(pattern, replacer, text) + +def parse_grl_file(grl_fname, libs): + global libraries + + libraries = libs + with open(grl_fname, 'r') as f: + return PARSER.parse(_remove_comments(f.read()))