From f0eaf38db2c7ed5dd3cbc62ad078bf9d08924640 Mon Sep 17 00:00:00 2001 From: Chad Versace Date: Fri, 24 Mar 2017 14:35:24 -0700 Subject: [PATCH] genxml: New generated header genX_bits.h (v6) genX_bits.h contains the sizes of bitfields in genxml instructions, structures, and registers. It also defines some functions to query those sizes. isl_surf_init() will use the new header to validate that requested pitches fit in their destination bitfields. What's currently in genX_bits.h: - Each CONTAINER::Field from gen*.xml that has a bitsize has a macro in genX_bits.h: #define GEN{N}_CONTAINER_Field_bits {bitsize} - For each set of macros whose name, after stripping the GEN prefix, is the same, genX_bits.h contains a query function: static inline uint32_t __attribute__((pure)) CONTAINER_Field_bits(const struct gen_device_info *devinfo); v2 (Chad Versace): - Parse the XML instead of scraping the generated gen*_pack.h headers. v3 (Dylan Baker): - Port to Mako. v4 (Jason Ekstrand): - Make the _bits functions take a gen_device_info. v5 (Chad Versace): - Fix autotools out-of-tree build. - Fix Android build. Tested with git://github.com/android-ia/manifest. - Fix macro names. They were all missing the "_bits" suffix. - Fix macros names more. Remove all double-underscores. - Unindent all generated code. (It was floating in a sea of whitespace). - Reformat header to appear human-written not machine-generated. - Sort gens from high to low. Newest gens should come first because, when we read code, we likely want to read the gen8/9 code and ignore the gen4 code. So put the gen4 code at the bottom. - Replace 'const' attributes with 'pure', because the functions now have a pointer parameter. - Add --cpp-guard flag. Used by Android. - Kill class FieldCollection. After Jason's rewrite, it was just a dict. v6 (Chad Versace): - Replace `key not in d.keys()` with `key not in d`. [for dylan] Co-authored-by: Dylan Baker Co-authored-by: Jason Ekstrand Reviewed-by: Jason Ekstrand (v5) Reviewed-by: Dylan Baker (v6) --- src/intel/Android.genxml.mk | 9 +- src/intel/Makefile.genxml.am | 6 +- src/intel/Makefile.sources | 6 +- src/intel/genxml/.gitignore | 1 + src/intel/genxml/gen_bits_header.py | 281 ++++++++++++++++++++++++++++ 5 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 src/intel/genxml/gen_bits_header.py diff --git a/src/intel/Android.genxml.mk b/src/intel/Android.genxml.mk index 79de7843801..842d0e13a33 100644 --- a/src/intel/Android.genxml.mk +++ b/src/intel/Android.genxml.mk @@ -46,9 +46,16 @@ LOCAL_GENERATED_SOURCES += $(addprefix $(intermediates)/, $(GENXML_GENERATED_FIL define header-gen @mkdir -p $(dir $@) @echo "Gen Header: $(PRIVATE_MODULE) <= $(notdir $(@))" - $(hide) $(PRIVATE_SCRIPT) $(PRIVATE_XML) > $@ + $(hide) $(PRIVATE_SCRIPT) $(PRIVATE_SCRIPT_FLAGS) $(PRIVATE_XML) > $@ endef +$(intermediates)/genxml/genX_bits.h: PRIVATE_SCRIPT := $(MESA_PYTHON2) $(LOCAL_PATH)/genxml/gen_bits_header.py +$(intermediates)/genxml/genX_bits.h: PRIVATE_SCRIPT_FLAGS := --cpp-guard=GENX_BITS_H +$(intermediates)/genxml/genX_bits.h: PRIVATE_XML := $(addprefix $(LOCAL_PATH)/,$(GENXML_XML_FILES)) +$(intermediates)/genxml/genX_bits.h: $(LOCAL_PATH)/genxml/gen_bits_header.py +$(intermediates)/genxml/genX_bits.h: $(addprefix $(LOCAL_PATH)/,$(GENXML_XML_FILES)) + $(call header-gen) + $(intermediates)/genxml/gen4_pack.h: PRIVATE_SCRIPT := $(MESA_PYTHON2) $(LOCAL_PATH)/genxml/gen_pack_header.py $(intermediates)/genxml/gen4_pack.h: PRIVATE_XML := $(LOCAL_PATH)/genxml/gen4.xml $(intermediates)/genxml/gen4_pack.h: $(LOCAL_PATH)/genxml/gen4.xml $(LOCAL_PATH)/genxml/gen_pack_header.py diff --git a/src/intel/Makefile.genxml.am b/src/intel/Makefile.genxml.am index 01a02b63b44..474b751f5fd 100644 --- a/src/intel/Makefile.genxml.am +++ b/src/intel/Makefile.genxml.am @@ -30,7 +30,7 @@ EXTRA_DIST += \ SUFFIXES = _pack.h _xml.h .xml -$(GENXML_GENERATED_FILES): genxml/gen_pack_header.py +$(GENXML_GENERATED_PACK_FILES): genxml/gen_pack_header.py .xml_pack.h: $(MKDIR_GEN) @@ -42,6 +42,10 @@ $(AUBINATOR_GENERATED_FILES): genxml/gen_zipped_file.py $(MKDIR_GEN) $(AM_V_GEN) $(PYTHON2) $(srcdir)/genxml/gen_zipped_file.py $< > $@ || ($(RM) $@; false) +genxml/genX_bits.h: genxml/gen_bits_header.py $(GENXML_XML_FILES) + $(MKDIR_GEN) + $(PYTHON_GEN) $< -o $@ $(addprefix $(srcdir)/,$(GENXML_XML_FILES)) + EXTRA_DIST += \ genxml/genX_pack.h \ genxml/gen_macros.h \ diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources index 88bcf60f6e3..c56891643ce 100644 --- a/src/intel/Makefile.sources +++ b/src/intel/Makefile.sources @@ -119,7 +119,7 @@ GENXML_XML_FILES = \ genxml/gen8.xml \ genxml/gen9.xml -GENXML_GENERATED_FILES = \ +GENXML_GENERATED_PACK_FILES = \ genxml/gen4_pack.h \ genxml/gen45_pack.h \ genxml/gen5_pack.h \ @@ -129,6 +129,10 @@ GENXML_GENERATED_FILES = \ genxml/gen8_pack.h \ genxml/gen9_pack.h +GENXML_GENERATED_FILES = \ + $(GENXML_GENERATED_PACK_FILES) \ + genxml/genX_bits.h + AUBINATOR_GENERATED_FILES = \ genxml/gen6_xml.h \ genxml/gen7_xml.h \ diff --git a/src/intel/genxml/.gitignore b/src/intel/genxml/.gitignore index c5672b5595c..3e2f1cfa9f0 100644 --- a/src/intel/genxml/.gitignore +++ b/src/intel/genxml/.gitignore @@ -1,2 +1,3 @@ +gen*_bits.h gen*_pack.h gen*_xml.h diff --git a/src/intel/genxml/gen_bits_header.py b/src/intel/genxml/gen_bits_header.py new file mode 100644 index 00000000000..808e6cf3f92 --- /dev/null +++ b/src/intel/genxml/gen_bits_header.py @@ -0,0 +1,281 @@ +#encoding=utf-8 +# Copyright © 2017 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS 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. + +from __future__ import ( + absolute_import, division, print_function, unicode_literals +) + +import argparse +import os +import sys +import xml.parsers.expat + +from mako.template import Template + +TEMPLATE = Template("""\ +<%! +from operator import itemgetter +%>\ +/* + * Copyright © 2017 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +/* THIS FILE HAS BEEN GENERATED, DO NOT HAND EDIT. + * + * Sizes of bitfields in genxml instructions, structures, and registers. + */ + +#ifndef ${guard} +#define ${guard} + +#include + +#include "common/gen_device_info.h" +#include "util/macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +% for _, field in sorted(fields.iteritems(), key=itemgetter(0)): + +/* ${field.container_name}::${field.name} */ +% for gen, bits in sorted(field.bits_by_gen.iteritems(), reverse=True): +#define ${gen.prefix(field.token_name, padded=True)} ${bits} +% endfor + +static inline uint32_t ATTRIBUTE_PURE +${field.token_name}(const struct gen_device_info *devinfo) +{ + switch (devinfo->gen) { + case 9: return ${field.bits(9)}; + case 8: return ${field.bits(8)}; + case 7: + if (devinfo->is_haswell) { + return ${field.bits(7.5)}; + } else { + return ${field.bits(7)}; + } + case 6: return ${field.bits(6)}; + case 5: return ${field.bits(5)}; + case 4: + if (devinfo->is_g4x) { + return ${field.bits(4.5)}; + } else { + return ${field.bits(4)}; + } + default: + unreachable("Invalid hardware generation"); + } +} +% endfor + +#ifdef __cplusplus +} +#endif + +#endif /* ${guard} */""", output_encoding='utf-8') + +def to_alphanum(name): + substitutions = { + ' ': '', + '/': '', + '[': '', + ']': '', + '(': '', + ')': '', + '-': '', + ':': '', + '.': '', + ',': '', + '=': '', + '>': '', + '#': '', + 'α': 'alpha', + '&': '', + '*': '', + '"': '', + '+': '', + '\'': '', + } + + for i, j in substitutions.items(): + name = name.replace(i, j) + + return name + +def safe_name(name): + name = to_alphanum(name) + if not name[0].isalpha(): + name = '_' + name + return name + +class Gen(object): + + def __init__(self, z): + # Convert potential "major.minor" string + z = float(z) + if z < 10: + z *= 10 + self.tenx = int(z) + + def __lt__(self, other): + return self.tenx < other.tenx + + def __hash__(self): + return hash(self.tenx) + + def __eq__(self, other): + return self.tenx == other.tenx + + def prefix(self, token, padded=False): + gen = self.tenx + pad = '' + + if gen % 10 == 0: + gen //= 10 + if padded: + pad = ' ' + + if token[0] == '_': + token = token[1:] + + return 'GEN{}_{}{}'.format(gen, token, pad) + +class Field(object): + + def __init__(self, container_name, name): + self.container_name = container_name + self.name = name + self.token_name = safe_name('_'.join([self.container_name, self.name, 'bits'])) + self.bits_by_gen = {} + + def add_gen(self, gen, xml_attrs): + assert isinstance(gen, Gen) + start = int(xml_attrs['start']) + end = int(xml_attrs['end']) + self.bits_by_gen[gen] = 1 + end - start + + def bits(self, gen): + if not isinstance(gen, Gen): + gen = Gen(gen) + return self.bits_by_gen.get(gen, 0) + +class XmlParser(object): + + def __init__(self, fields): + self.parser = xml.parsers.expat.ParserCreate() + self.parser.StartElementHandler = self.start_element + self.parser.EndElementHandler = self.end_element + + self.gen = None + self.container_name = None + self.fields = fields + + def parse(self, filename): + with open(filename) as f: + self.parser.ParseFile(f) + + def start_element(self, name, attrs): + if name == 'genxml': + self.gen = Gen(attrs['gen']) + elif name in ('instruction', 'struct', 'register'): + self.start_container(attrs) + elif name == 'field': + self.start_field(attrs) + else: + pass + + def end_element(self, name): + if name == 'genxml': + self.gen = None + elif name in ('instruction', 'struct', 'register'): + self.container_name = None + else: + pass + + def start_container(self, attrs): + assert self.container_name is None + self.container_name = attrs['name'] + + def start_field(self, attrs): + if self.container_name is None: + return + + field_name = attrs.get('name', None) + if not field_name: + return + + key = (self.container_name, field_name) + if key not in self.fields: + self.fields[key] = Field(self.container_name, field_name) + self.fields[key].add_gen(self.gen, attrs) + +def parse_args(): + p = argparse.ArgumentParser() + p.add_argument('-o', '--output', type=str, + help="If OUTPUT is unset or '-', then it defaults to '/dev/stdout'") + p.add_argument('--cpp-guard', type=str, + help='If unset, then CPP_GUARD is derived from OUTPUT.') + p.add_argument('xml_sources', metavar='XML_SOURCE', nargs='+') + + pargs = p.parse_args() + + if pargs.output in (None, '-'): + pargs.output = '/dev/stdout' + + if pargs.cpp_guard is None: + pargs.cpp_guard = os.path.basename(pargs.output).upper().replace('.', '_') + + return pargs + +def main(): + pargs = parse_args() + + # Maps (container_name, field_name) => Field + fields = {} + + for source in pargs.xml_sources: + XmlParser(fields).parse(source) + + with open(pargs.output, 'wb') as f: + f.write(TEMPLATE.render(fields=fields, guard=pargs.cpp_guard)) + +if __name__ == '__main__': + main() -- 2.30.2