X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fintel%2Fgenxml%2Fgen_pack_header.py;h=118cc6330aff8277d3546a93dbade949e0298dbf;hb=1ecd37eac68709c3f55d352a2852d19dcb58cf46;hp=75c4f269cdd3e903e482d3174c2014d69924cf56;hpb=1375cb3c273453920d9a15fb6ca67714f534704d;p=mesa.git diff --git a/src/intel/genxml/gen_pack_header.py b/src/intel/genxml/gen_pack_header.py old mode 100755 new mode 100644 index 75c4f269cdd..118cc6330af --- a/src/intel/genxml/gen_pack_header.py +++ b/src/intel/genxml/gen_pack_header.py @@ -1,12 +1,18 @@ -#!/usr/bin/env python3 +#encoding=utf-8 +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) +import argparse +import ast import xml.parsers.expat import re import sys import copy +import textwrap license = """/* - * Copyright © 2016 Intel Corporation + * Copyright (C) 2016 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,10 +42,14 @@ pack_header = """%(license)s * This file has been generated, do not hand edit. */ -#pragma once +#ifndef %(guard)s +#define %(guard)s #include +#include +#include #include +#include #ifndef __gen_validate_value #define __gen_validate_value(x) @@ -48,6 +58,12 @@ pack_header = """%(license)s #ifndef __gen_field_functions #define __gen_field_functions +#ifdef NDEBUG +#define NDEBUG_UNUSED __attribute__((unused)) +#else +#define NDEBUG_UNUSED +#endif + union __gen_value { float f; uint32_t dw; @@ -60,11 +76,11 @@ __gen_mbo(uint32_t start, uint32_t end) } static inline uint64_t -__gen_uint(uint64_t v, uint32_t start, uint32_t end) +__gen_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end) { __gen_validate_value(v); -#if DEBUG +#ifndef NDEBUG const int width = end - start + 1; if (width < 64) { const uint64_t max = (1ull << width) - 1; @@ -82,7 +98,7 @@ __gen_sint(int64_t v, uint32_t start, uint32_t end) __gen_validate_value(v); -#if DEBUG +#ifndef NDEBUG if (width < 64) { const int64_t max = (1ll << (width - 1)) - 1; const int64_t min = -(1ll << (width - 1)); @@ -96,10 +112,10 @@ __gen_sint(int64_t v, uint32_t start, uint32_t end) } static inline uint64_t -__gen_offset(uint64_t v, uint32_t start, uint32_t end) +__gen_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end) { __gen_validate_value(v); -#if DEBUG +#ifndef NDEBUG uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; assert((v & ~mask) == 0); @@ -122,32 +138,32 @@ __gen_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) const float factor = (1 << fract_bits); -#if DEBUG +#ifndef NDEBUG const float max = ((1 << (end - start)) - 1) / factor; const float min = -(1 << (end - start)) / factor; assert(min <= v && v <= max); #endif - const int32_t int_val = roundf(v * factor); + const int64_t int_val = llroundf(v * factor); const uint64_t mask = ~0ull >> (64 - (end - start + 1)); return (int_val & mask) << start; } static inline uint64_t -__gen_ufixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) +__gen_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits) { __gen_validate_value(v); const float factor = (1 << fract_bits); -#if DEBUG +#ifndef NDEBUG const float max = ((1 << (end - start + 1)) - 1) / factor; const float min = 0.0f; assert(min <= v && v <= max); #endif - const uint32_t uint_val = roundf(v * factor); + const uint64_t uint_val = llroundf(v * factor); return uint_val << start; } @@ -160,6 +176,8 @@ __gen_ufixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits) #error #define __gen_combine_address before including this file #endif +#undef NDEBUG_UNUSED + #endif """ @@ -179,7 +197,6 @@ def to_alphanum(name): '=': '', '>': '', '#': '', - 'α': 'alpha', '&': '', '*': '', '"': '', @@ -194,14 +211,21 @@ def to_alphanum(name): def safe_name(name): name = to_alphanum(name) - if not str.isalpha(name[0]): + if not name[0].isalpha(): name = '_' + name return name -class Field: - ufixed_pattern = re.compile("u(\d+)\.(\d+)") - sfixed_pattern = re.compile("s(\d+)\.(\d+)") +def num_from_str(num_str): + if num_str.lower().startswith('0x'): + return int(num_str, base=16) + + assert not num_str.startswith('0'), 'octals numbers not allowed' + return int(num_str) + +class Field(object): + ufixed_pattern = re.compile(r"u(\d+)\.(\d+)") + sfixed_pattern = re.compile(r"s(\d+)\.(\d+)") def __init__(self, parser, attrs): self.parser = parser @@ -211,13 +235,21 @@ class Field: self.end = int(attrs["end"]) self.type = attrs["type"] + assert self.start <= self.end, \ + 'field {} has end ({}) < start ({})'.format(self.name, self.end, + self.start) + if self.type == 'bool': + assert self.end == self.start, \ + 'bool field ({}) is too wide'.format(self.name) + if "prefix" in attrs: self.prefix = attrs["prefix"] else: self.prefix = None if "default" in attrs: - self.default = int(attrs["default"]) + # Base 0 recognizes 0x, 0o, 0b prefixes in addition to decimal ints. + self.default = int(attrs["default"], base=0) else: self.default = None @@ -231,6 +263,17 @@ class Field: self.type = 'sfixed' self.fractional_size = int(sfixed_match.group(2)) + def is_builtin_type(self): + builtins = [ 'address', 'bool', 'float', 'ufixed', + 'offset', 'sfixed', 'offset', 'int', 'uint', 'mbo' ] + return self.type in builtins + + def is_struct_type(self): + return self.type in self.parser.structs + + def is_enum_type(self): + return self.type in self.parser.enums + def emit_template_struct(self, dim): if self.type == 'address': type = '__gen_address_type' @@ -250,25 +293,27 @@ class Field: type = 'int32_t' elif self.type == 'uint': type = 'uint32_t' - elif self.type in self.parser.structs: + elif self.is_struct_type(): type = 'struct ' + self.parser.gen_prefix(safe_name(self.type)) + elif self.is_enum_type(): + type = 'enum ' + self.parser.gen_prefix(safe_name(self.type)) elif self.type == 'mbo': return else: print("#error unhandled type: %s" % self.type) + return print(" %-36s %s%s;" % (type, self.name, dim)) - if len(self.values) > 0 and self.default == None: + prefix = "" + if self.values and self.default is None: if self.prefix: prefix = self.prefix + "_" - else: - prefix = "" for value in self.values: print("#define %-40s %d" % (prefix + value.name, value.value)) -class Group: +class Group(object): def __init__(self, parser, parent, start, count, size): self.parser = parser self.parent = parent @@ -295,7 +340,7 @@ class Group: def collect_dwords(self, dwords, start, dim): for field in self.fields: - if type(field) is Group: + if isinstance(field, Group): if field.count == 1: field.collect_dwords(dwords, start + field.start, dim) else: @@ -330,7 +375,7 @@ class Group: dwords[index + 1] = dwords[index] index = index + 1 - def emit_pack_function(self, start): + def collect_dwords_and_length(self): dwords = {} self.collect_dwords(dwords, 0, "") @@ -340,9 +385,14 @@ class Group: # index we've seen plus one. if self.size > 0: length = self.size // 32 - else: + elif dwords: length = max(dwords.keys()) + 1 + else: + length = 0 + return (dwords, length) + + def emit_pack_function(self, dwords, length): for index in range(length): # Handle MBZ dwords if not index in dwords: @@ -364,7 +414,7 @@ class Group: if len(dw.fields) == 1: field = dw.fields[0] name = field.name + field.dim - if field.type in self.parser.structs and field.start % 32 == 0: + if field.is_struct_type() and field.start % 32 == 0: print("") print(" %s_pack(data, &dw[%d], &values->%s);" % (self.parser.gen_prefix(safe_name(field.type)), index, name)) @@ -374,7 +424,7 @@ class Group: # to the dword for those fields. field_index = 0 for field in dw.fields: - if type(field) is Field and field.type in self.parser.structs: + if isinstance(field, Field) and field.is_struct_type(): name = field.name + field.dim print("") print(" uint32_t v%d_%d;" % (index, field_index)) @@ -399,69 +449,74 @@ class Group: v = "0" field_index = 0 + non_address_fields = [] for field in dw.fields: if field.type != "mbo": name = field.name + field.dim if field.type == "mbo": - s = "__gen_mbo(%d, %d)" % \ - (field.start - dword_start, field.end - dword_start) + non_address_fields.append("__gen_mbo(%d, %d)" % \ + (field.start - dword_start, field.end - dword_start)) elif field.type == "address": - s = None + pass elif field.type == "uint": - s = "__gen_uint(values->%s, %d, %d)" % \ - (name, field.start - dword_start, field.end - dword_start) + non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start)) + elif field.is_enum_type(): + non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start)) elif field.type == "int": - s = "__gen_sint(values->%s, %d, %d)" % \ - (name, field.start - dword_start, field.end - dword_start) + non_address_fields.append("__gen_sint(values->%s, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start)) elif field.type == "bool": - s = "__gen_uint(values->%s, %d, %d)" % \ - (name, field.start - dword_start, field.end - dword_start) + non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start)) elif field.type == "float": - s = "__gen_float(values->%s)" % name + non_address_fields.append("__gen_float(values->%s)" % name) elif field.type == "offset": - s = "__gen_offset(values->%s, %d, %d)" % \ - (name, field.start - dword_start, field.end - dword_start) + non_address_fields.append("__gen_offset(values->%s, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start)) elif field.type == 'ufixed': - s = "__gen_ufixed(values->%s, %d, %d, %d)" % \ - (name, field.start - dword_start, field.end - dword_start, field.fractional_size) + non_address_fields.append("__gen_ufixed(values->%s, %d, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start, field.fractional_size)) elif field.type == 'sfixed': - s = "__gen_sfixed(values->%s, %d, %d, %d)" % \ - (name, field.start - dword_start, field.end - dword_start, field.fractional_size) - elif field.type in self.parser.structs: - s = "__gen_uint(v%d_%d, %d, %d)" % \ - (index, field_index, field.start - dword_start, field.end - dword_start) + non_address_fields.append("__gen_sfixed(values->%s, %d, %d, %d)" % \ + (name, field.start - dword_start, field.end - dword_start, field.fractional_size)) + elif field.is_struct_type(): + non_address_fields.append("__gen_uint(v%d_%d, %d, %d)" % \ + (index, field_index, field.start - dword_start, field.end - dword_start)) field_index = field_index + 1 else: - print("/* unhandled field %s, type %s */\n" % (name, field.type)) - s = None + non_address_fields.append("/* unhandled field %s, type %s */\n" % \ + (name, field.type)) - if not s == None: - if field == dw.fields[-1]: - print(" %s;" % s) - else: - print(" %s |" % s) + if non_address_fields: + print(" |\n".join(" " + f for f in non_address_fields) + ";") if dw.size == 32: if dw.address: - print(" dw[%d] = __gen_combine_address(data, &dw[%d], values->%s, %s);" % (index, index, dw.address.name, v)) + print(" dw[%d] = __gen_combine_address(data, &dw[%d], values->%s, %s);" % (index, index, dw.address.name + field.dim, v)) continue if dw.address: v_address = "v%d_address" % index print(" const uint64_t %s =\n __gen_combine_address(data, &dw[%d], values->%s, %s);" % - (v_address, index, dw.address.name, v)) - v = v_address - + (v_address, index, dw.address.name + field.dim, v)) + if len(dw.fields) > address_count: + print(" dw[%d] = %s;" % (index, v_address)) + print(" dw[%d] = (%s >> 32) | (%s >> 32);" % (index + 1, v_address, v)) + continue + else: + v = v_address print(" dw[%d] = %s;" % (index, v)) print(" dw[%d] = %s >> 32;" % (index + 1, v)) -class Value: +class Value(object): def __init__(self, attrs): self.name = safe_name(attrs["name"]) - self.value = int(attrs["value"]) + self.value = ast.literal_eval(attrs["value"]) -class Parser: +class Parser(object): def __init__(self): self.parser = xml.parsers.expat.ParserCreate() self.parser.StartElementHandler = self.start_element @@ -469,25 +524,41 @@ class Parser: self.instruction = None self.structs = {} + # Set of enum names we've seen. + self.enums = set() + self.registers = {} + + def gen_prefix(self, name): + if name[0] == "_": + return 'GEN%s%s' % (self.gen, name) + return 'GEN%s_%s' % (self.gen, name) + + def gen_guard(self): + return self.gen_prefix("PACK_H") def start_element(self, name, attrs): if name == "genxml": self.platform = attrs["name"] self.gen = attrs["gen"].replace('.', '') - print(pack_header % {'license': license, 'platform': self.platform}) - elif name == "instruction": - self.instruction = safe_name(attrs["name"]) - self.length_bias = int(attrs["bias"]) - if "length" in attrs: - self.length = int(attrs["length"]) - size = self.length * 32 - else: - self.length = None - size = 0 - self.group = Group(self, None, 0, 1, size) - elif name == "struct": - self.struct = safe_name(attrs["name"]) - self.structs[attrs["name"]] = 1 + print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()}) + elif name in ("instruction", "struct", "register"): + if name == "instruction": + self.instruction = safe_name(attrs["name"]) + self.length_bias = int(attrs["bias"]) + if "engine" in attrs: + self.instruction_engines = set(attrs["engine"].split('|')) + else: + # When an instruction doesn't have the engine specified, + # it is considered to be for all engines, so 'None' is used + # to signify that the instruction belongs to all engines. + self.instruction_engines = None + elif name == "struct": + self.struct = safe_name(attrs["name"]) + self.structs[attrs["name"]] = 1 + elif name == "register": + self.register = safe_name(attrs["name"]) + self.reg_num = num_from_str(attrs["num"]) + self.registers[attrs["name"]] = 1 if "length" in attrs: self.length = int(attrs["length"]) size = self.length * 32 @@ -507,6 +578,7 @@ class Parser: elif name == "enum": self.values = [] self.enum = safe_name(attrs["name"]) + self.enums.add(attrs["name"]) if "prefix" in attrs: self.prefix = safe_name(attrs["prefix"]) else: @@ -519,10 +591,15 @@ class Parser: self.emit_instruction() self.instruction = None self.group = None - elif name == "struct": + elif name == "struct": self.emit_struct() self.struct = None self.group = None + elif name == "register": + self.emit_register() + self.register = None + self.reg_num = None + self.group = None elif name == "group": self.group = self.group.parent elif name == "field": @@ -530,12 +607,8 @@ class Parser: elif name == "enum": self.emit_enum() self.enum = None - - def gen_prefix(self, name): - if name[0] == "_": - return 'GEN%s%s' % (self.gen, name) - else: - return 'GEN%s_%s' % (self.gen, name) + elif name == "genxml": + print('#endif /* %s */' % self.gen_guard()) def emit_template_struct(self, name, group): print("struct %s {" % self.gen_prefix(name)) @@ -544,31 +617,40 @@ class Parser: def emit_pack_function(self, name, group): name = self.gen_prefix(name) - print("static inline void\n%s_pack(__gen_user_data *data, void * restrict dst,\n%sconst struct %s * restrict values)\n{" % - (name, ' ' * (len(name) + 6), name)) + print(textwrap.dedent("""\ + static inline void + %s_pack(__attribute__((unused)) __gen_user_data *data, + %s__attribute__((unused)) void * restrict dst, + %s__attribute__((unused)) const struct %s * restrict values) + {""") % (name, ' ' * len(name), ' ' * len(name), name)) - # Cast dst to make header C++ friendly - print(" uint32_t * restrict dw = (uint32_t * restrict) dst;") + (dwords, length) = group.collect_dwords_and_length() + if length: + # Cast dst to make header C++ friendly + print(" uint32_t * restrict dw = (uint32_t * restrict) dst;") - group.emit_pack_function(0) + group.emit_pack_function(dwords, length) print("}\n") def emit_instruction(self): name = self.instruction - if not self.length == None: - print('#define %-33s %4d' % + if self.instruction_engines and not self.instruction_engines & self.engines: + return + + if not self.length is None: + print('#define %-33s %6d' % (self.gen_prefix(name + "_length"), self.length)) - print('#define %-33s %4d' % + print('#define %-33s %6d' % (self.gen_prefix(name + "_length_bias"), self.length_bias)) default_fields = [] for field in self.group.fields: - if not type(field) is Field: + if not isinstance(field, Field): continue - if field.default == None: + if field.default is None: continue - default_fields.append(" .%-35s = %4d" % (field.name, field.default)) + default_fields.append(" .%-35s = %6d" % (field.name, field.default)) if default_fields: print('#define %-40s\\' % (self.gen_prefix(name + '_header'))) @@ -579,35 +661,73 @@ class Parser: self.emit_pack_function(self.instruction, self.group) + def emit_register(self): + name = self.register + if not self.reg_num is None: + print('#define %-33s 0x%04x' % + (self.gen_prefix(name + "_num"), self.reg_num)) + + if not self.length is None: + print('#define %-33s %6d' % + (self.gen_prefix(name + "_length"), self.length)) + + self.emit_template_struct(self.register, self.group) + self.emit_pack_function(self.register, self.group) + def emit_struct(self): name = self.struct - if not self.length == None: - print('#define %-33s %4d' % + if not self.length is None: + print('#define %-33s %6d' % (self.gen_prefix(name + "_length"), self.length)) self.emit_template_struct(self.struct, self.group) self.emit_pack_function(self.struct, self.group) def emit_enum(self): - print('/* enum %s */' % self.gen_prefix(self.enum)) + print('enum %s {' % self.gen_prefix(self.enum)) for value in self.values: if self.prefix: name = self.prefix + "_" + value.name else: name = value.name - print('#define %-36s %4d' % (name.upper(), value.value)) - print('') + print(' %-36s = %6d,' % (name.upper(), value.value)) + print('};\n') def parse(self, filename): file = open(filename, "rb") self.parser.ParseFile(file) file.close() -if len(sys.argv) < 2: - print("No input xml file specified") - sys.exit(1) +def parse_args(): + p = argparse.ArgumentParser() + p.add_argument('xml_source', metavar='XML_SOURCE', + help="Input xml file") + p.add_argument('--engines', nargs='?', type=str, default='render', + help="Comma-separated list of engines whose instructions should be parsed (default: %(default)s)") + + pargs = p.parse_args() + + if pargs.engines is None: + print("No engines specified") + sys.exit(1) + + return pargs + +def main(): + pargs = parse_args() + + input_file = pargs.xml_source + engines = pargs.engines.split(',') + valid_engines = [ 'render', 'blitter', 'video' ] + if set(engines) - set(valid_engines): + print("Invalid engine specified, valid engines are:\n") + for e in valid_engines: + print("\t%s" % e) + sys.exit(1) -input_file = sys.argv[1] + p = Parser() + p.engines = set(engines) + p.parse(input_file) -p = Parser() -p.parse(input_file) +if __name__ == '__main__': + main()