[Mesa-dev] [PATCH 3/9] genxml: New generated header genX_bits.h (v2)

Jason Ekstrand jason at jlekstrand.net
Thu Mar 23 18:54:00 UTC 2017


I'm not going to ask you to rewrite it in mako but that's what we should do
in the future. :-)  Someone can rewrite later.  I want things to land. :-)

On Wed, Mar 22, 2017 at 6:03 PM, Chad Versace <chadversary at chromium.org>
wrote:

> 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:
>
>   - For each CONTAINER::Field in gen{n}.xml whose name matches
>     /.*Surface(Q?)Pitch_bits$/, genX_bits.h contains the line:
>
>       #define GEN{n}_CONTAINER_Field_bits {number of bits in field}
>
>     STREAMOUT fields are omitted because isl doesn't care about them.
>
>   - For each set of macros whose name, after stripping the GEN prefix,
>     is the same, genX_bits.h contains the query function:
>
>       static inline uint32_t __attribute__((const))
>       CONTAINER_Field_bits(int gen_10x)
>

If it's practical, I would much rather they just take a devinfo.  The
GENx10 thing is a hack that I don't think we can trust to work
indefinitely.  Also, it makes it much easier for the caller to deal with.

I think Dylan is going to see if he can quickly cook up a mako version and
I'll see how hard devinfo is.  Don't spend time on this yet.

--Jason


>       {
>          switch (gen_10x) {
>          case {n0}: return GEN{n0}_CONTAINER_Field_bits;
>          case {n1}: return GEN{n1}_CONTAINER_Field_bits;
>          ...
>          default: return 0;
>       }
>
> v2: Parse the XML instead of scraping the generated gen*_pack.h headers.
>     [for jekstrand]
>
>     Jason and I tentatively agreed that I should just hand-write the
>     header. But my conscience refused. The XML way is the right way.
>     Anyway, the generator script are about the same number of lines (259
>     vs 222), so the generator is the clear winner in my opinion.
> ---
>  src/intel/Makefile.genxml.am        |   6 +-
>  src/intel/Makefile.sources          |   6 +-
>  src/intel/genxml/.gitignore         |   1 +
>  src/intel/genxml/gen_bits_header.py | 259 ++++++++++++++++++++++++++++++
> ++++++
>  4 files changed, 270 insertions(+), 2 deletions(-)
>  create mode 100644 src/intel/genxml/gen_bits_header.py
>
> diff --git a/src/intel/Makefile.genxml.am b/src/intel/Makefile.genxml.am
> index 01a02b63b44..4e59a918618 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 $@ $(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 801797d2768..ec43f06a495 100644
> --- a/src/intel/Makefile.sources
> +++ b/src/intel/Makefile.sources
> @@ -117,7 +117,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 \
> @@ -127,6 +127,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..0315c6251e7
> --- /dev/null
> +++ b/src/intel/genxml/gen_bits_header.py
> @@ -0,0 +1,259 @@
> +#encoding=utf-8
> +
> +from __future__ import (
> +    absolute_import, division, print_function, unicode_literals
> +)
> +
> +import argparse
> +import io
> +import os
> +import os.path
> +import re
> +import sys
> +from sys import stdout, stderr
> +from textwrap import dedent
> +import xml.parsers.expat
> +
> +def safe_token(t):
> +    t = t.replace(' ', '')
> +    if t[0].isdigit():
> +        t = '_' + t
> +    return t
> +
> +class Gen(object):
> +
> +    def __init__(self, z):
> +        # Convert potential "major.minor" string
> +        z = float(z)
> +        if z < 10:
> +            z *= 10
> +        self._10x = int(z)
> +
> +    def prefix(self, token):
> +        gen = self._10x
> +
> +        if gen % 10 == 0:
> +            gen //= 10
> +
> +        if token[0] == '_':
> +            token = token[1:]
> +
> +        return 'GEN{}_{}'.format(gen, token)
> +
> +class Header(object):
> +
> +    def __init__(self, buf):
> +        self.buf = buf
> +        self.cpp_guard = os.path.basename(buf.name).upper().replace('.',
> '_')
> +
> +    def write(self, *args, **kwargs):
> +        self.buf.write(*args, **kwargs)
> +
> +    def write_prologue(self):
> +        self.write(dedent("""\
> +            /*
> +             * Copyright (C) 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.
> +             */
> +
> +             """))
> +
> +        self.write('#ifndef {}\n'.format(self.cpp_guard))
> +        self.write('#define {}\n'.format(self.cpp_guard))
> +
> +        self.write(dedent("""
> +            #include <stdint.h>
> +
> +            #ifdef __cplusplus
> +            extern "C" {
> +            #endif
> +
> +            """))
> +
> +    def write_epilogue(self):
> +        self.write(dedent("""\
> +            #ifdef __cplusplus
> +            }
> +            #endif
> +
> +            """))
> +
> +        self.write('#endif /* {} */\n'.format(self.cpp_guard))
> +
> +    def write_macros(self, fields):
> +        for gen_10x in sorted(fields.by_gen_10x.keys(), reverse=True):
> +            for f in fields.by_gen_10x[gen_10x]:
> +                self.write('#define {:56} {:2}'.format(f.token_name,
> f.bits))
> +                if f.comment:
> +                    self.write(' /* {} */'.format(f.comment))
> +                self.write('\n')
> +            self.write('\n')
> +
> +    def write_funcs(self, fields):
> +        def gen_10x(field):
> +            return field.gen._10x
> +
> +        for basename in sorted(fields.by_token_basenames.keys()):
> +            self.write('static inline uint32_t __attribute__((const))\n')
> +            self.write('{}(int gen_10x)\n'.format(basename))
> +            self.write('{\n')
> +            self.write('   switch (gen_10x) {\n')
> +
> +            for f in sorted(fields.by_token_basenames[basename],
> +                            key=gen_10x, reverse=True):
> +                self.write('   case {}: return {};\n'
> +                           .format(f.gen._10x, f.token_name))
> +
> +            self.write('   default: return 0;\n')
> +            self.write('   }\n')
> +            self.write('}\n')
> +            self.write('\n')
> +
> +class Field(object):
> +
> +    SURFACE_PITCH_REGEX = re.compile(r'.*Surface (Q?)Pitch$')
> +
> +    def __init__(self, gen, container_name, xml_attrs, comment=None):
> +        assert isinstance(gen, Gen)
> +        assert container_name
> +
> +        self.gen = gen
> +        self.container_name = container_name
> +        self.name = xml_attrs['name']
> +        self.start = int(xml_attrs['start'])
> +        self.end = int(xml_attrs['end'])
> +        self.bits = 1 + self.end - self.start
> +        self.token_basename = '_'.join([safe_token(container_name),
> safe_token(self.name), 'bits'])
> +        self.token_name = gen.prefix(self.token_basename)
> +        self.comment = comment
> +
> +class FieldCollection(object):
> +
> +    def __init__(self):
> +        self.by_gen_10x = {}
> +        self.by_token_basenames = {}
> +
> +    def add(self, field):
> +        self.by_gen_10x.setdefault(field.gen._10x, []).append(field)
> +        self.by_token_basenames.setdefault(field.token_basename,
> []).append(field)
> +
> +class XmlParser(object):
> +
> +    def __init__(self, field_collection):
> +        self.parser = xml.parsers.expat.ParserCreate()
> +        self.parser.StartElementHandler = self.start_element
> +        self.parser.EndElementHandler = self.end_element
> +
> +        self.fields = field_collection
> +        self.container_name = None
> +
> +    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
> +        name = attrs['name']
> +
> +        # We don't care about these
> +        if re.search(r'STREAMOUT|3DSTATE_SO', name):
> +            return
> +
> +        self.container_name = safe_token(name)
> +
> +    def start_field(self, attrs):
> +        if self.container_name is None:
> +            return
> +
> +        name = attrs.get('name', None)
> +        if not name:
> +            return
> +
> +        match = Field.SURFACE_PITCH_REGEX.match(name)
> +        if not match:
> +            return
> +
> +        self.fields.add(Field(self.gen, self.container_name, attrs))
> +
> +        if name == 'MCS Surface Pitch':
> +            # MCSSurfacePitch in older gens is analogous to
> +            # AuxiliarySurfacePitch in newer gens.
> +            aux_attrs = attrs.copy()
> +            aux_attrs['name'] = 'Auxiliary Surface Pitch'
> +            self.fields.add(Field(self.gen, self.container_name,
> aux_attrs,
> +                                  comment='alias of MCSSurfacePitch'))
> +
> +def parse_args():
> +    p = argparse.ArgumentParser()
> +    p.add_argument('-o', '--output', type=str)
> +    p.add_argument('sources', metavar='SOURCES', nargs=argparse.REMAINDER)
> +
> +    pargs = p.parse_args()
> +
> +    if len(pargs.sources) == 0:
> +        stderr.write('error: no source files\n')
> +        sys.exit(1)
> +
> +    if pargs.output in (None, '-'):
> +        pargs.output = '/dev/stdout'
> +
> +    return pargs
> +
> +def main():
> +    pargs = parse_args()
> +
> +    fields = FieldCollection()
> +
> +    for source in pargs.sources:
> +        XmlParser(fields).parse(source)
> +
> +    with open(pargs.output, 'w') as outfile:
> +        header = Header(outfile)
> +        header.write_prologue()
> +        header.write_macros(fields)
> +        header.write_funcs(fields)
> +        header.write_epilogue()
> +
> +if __name__ == '__main__':
> +    main()
> --
> 2.12.0
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170323/f67687c6/attachment-0001.html>


More information about the mesa-dev mailing list