Edit

IABSD.fr/xenocara/lib/mesa/src/compiler/isaspec/decode.py

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2025-06-05 11:23:11
    Hash : 67d6f117
    Message : Import Mesa 25.0.7

  • lib/mesa/src/compiler/isaspec/decode.py
  • #!/usr/bin/env python3
    #
    # Copyright © 2020 Google, Inc.
    #
    # 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.
    
    from mako.template import Template
    from isa import ISA
    import argparse
    import os
    import sys
    
    class FieldDecode(object):
        def __init__(self, name, map_expr):
            self.name = name
            self.map_expr = map_expr
    
        def get_c_name(self):
            return self.name.lower().replace('-', '_')
    
    # State and helpers used by the template:
    class State(object):
        def __init__(self, isa):
            self.isa = isa
    
        def case_name(self, bitset, name):
            return bitset.encode.case_prefix + name.upper().replace('.', '_').replace('-', '_').replace('#', '')
    
        # Return a list of all <map> entries for a leaf bitset, with the child
        # bitset overriding the parent bitset's entries. Because we can't resolve
        # which <map>s are used until we resolve which overload is used, we
        # generate code for encoding all of these and then at runtime select which
        # one to call based on the display.
        def decode_fields(self, bitset):
            if bitset.get_root().decode is None:
                return
    
            seen_fields = set()
            if bitset.encode is not None:
                for name, expr in bitset.encode.maps.items():
                    seen_fields.add(name)
                    yield FieldDecode(name, expr)
    
            if bitset.extends is not None:
                for field in self.decode_fields(self.isa.bitsets[bitset.extends]):
                    if field.name not in seen_fields:
                        yield field
    
        # A limited resolver for field type which doesn't properly account for
        # overrides.  In particular, if a field is defined differently in multiple
        # different cases, this just blindly picks the last one.
        #
        # TODO to do this properly, I don't think there is an alternative than
        # to emit code which evaluates the case.expr
        def resolve_simple_field(self, bitset, name):
            field = None
            for case in bitset.cases:
                if name in case.fields:
                    field = case.fields[name]
            if field is not None:
                return field
            if bitset.extends is not None:
                return self.resolve_simple_field(bitset.isa.bitsets[bitset.extends], name)
            return None
    
    template = """\
    /* Copyright (C) 2020 Google, Inc.
     *
     * 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.
     */
    
    #include "${header}"
    
    #include <stdint.h>
    #include <util/bitset.h>
    
    #define BITMASK_WORDS BITSET_WORDS(${isa.bitsize})
    
    typedef struct {
        BITSET_WORD bitset[BITMASK_WORDS];
    } bitmask_t;
    
    
    #define BITSET_FORMAT ${isa.format()}
    #define BITSET_VALUE(v) ${isa.value()}
    
    static inline void
    next_instruction(bitmask_t *instr, BITSET_WORD *start)
    {
        %for i in range(0, int(isa.bitsize / 32)):
        instr->bitset[${i}] = *(start + ${i});
        %endfor
    }
    
    static inline uint64_t
    bitmask_to_uint64_t(bitmask_t mask)
    {
    %   if isa.bitsize <= 32:
        return mask.bitset[0];
    %   else:
        return ((uint64_t)mask.bitset[1] << 32) | mask.bitset[0];
    %   endif
    }
    
    static inline bitmask_t
    uint64_t_to_bitmask(uint64_t val)
    {
        bitmask_t mask = {
            .bitset[0] = val & 0xffffffff,
    %   if isa.bitsize > 32:
            .bitset[1] = (val >> 32) & 0xffffffff,
    %   endif
        };
    
        return mask;
    }
    
    #include "isaspec_decode_decl.h"
    
    static uint64_t
    isa_decode_field(struct decode_scope *scope, const char *field_name);
    
    /*
     * enum tables, these don't have any link back to other tables so just
     * dump them up front before the bitset tables
     */
    
    %for name, enum in isa.enums.items():
    static const struct isa_enum ${enum.get_c_name()} = {
        .num_values = ${len(enum.values)},
        .values = {
    %   for val, display in enum.values.items():
            { .val = ${val}, .display = "${display}" },
    %   endfor
        },
    };
    %endfor
    
    /*
     * generated expression functions, can be linked from bitset tables, so
     * also dump them up front
     */
    
    %for name, expr in isa.expressions.items():
    static uint64_t
    ${expr.get_c_name()}(struct decode_scope *scope)
    {
    %   for fieldname in sorted(expr.fieldnames):
        int64_t ${fieldname} = isa_decode_field(scope, "${fieldname}");
    %   endfor
        return ${expr.expr};
    }
    %endfor
    
    /* forward-declarations of bitset decode functions */
    %for name, bitset in isa.all_bitsets():
    %   for df in s.decode_fields(bitset):
    static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val);
    %   endfor
    static const struct isa_field_decode decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields[] = {
    %   for df in s.decode_fields(bitset):
        {
            .name = "${df.name}",
            .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()},
        },
    %   endfor
    };
    static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope);
    %endfor
    
    /*
     * Forward-declarations (so we don't have to figure out which order to
     * emit various tables when they have pointers to each other)
     */
    
    %for name, bitset in isa.all_bitsets():
    static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min};
    %endfor
    
    %for root_name, root in isa.roots.items():
    static const struct isa_bitset *${root.get_c_name()}[];
    %endfor
    
    /*
     * bitset tables:
     */
    
    %for name, bitset in isa.all_bitsets():
    %   for case in bitset.cases:
    %      for field_name, field in case.fields.items():
    %         if field.get_c_typename() == 'TYPE_BITSET':
    %            if len(field.params) > 0:
    static const struct isa_field_params ${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()} = {
           .num_params = ${len(field.params)},
           .params = {
    %               for param in field.params:
               { .name= "${param[0]}",  .as = "${param[1]}" },
    %               endfor
    
           },
    };
    %            endif
    %         endif
    %      endfor
    static const struct isa_case ${case.get_c_name()}_gen_${bitset.gen_min} = {
    %   if case.expr is not None:
           .expr     = &${isa.expressions[case.expr].get_c_name()},
    %   endif
    %   if case.display is not None:
           .display  = "${case.display}",
    %   endif
           .num_fields = ${len(case.fields)},
           .fields   = {
    %   for field_name, field in case.fields.items():
              { .name = "${field_name}", .low = ${field.low}, .high = ${field.high},
    %      if field.expr is not None:
                .expr = &${isa.expressions[field.expr].get_c_name()},
    %      endif
    %      if field.display is not None:
                .display = "${field.display}",
    %      endif
                .type = ${field.get_c_typename()},
    %      if field.get_c_typename() == 'TYPE_BITSET':
                .bitsets = ${isa.roots[field.type].get_c_name()},
    %         if len(field.params) > 0:
                .params = &${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()},
    %         endif
    %      endif
    %      if field.get_c_typename() == 'TYPE_ENUM':
                .enums = &${isa.enums[field.type].get_c_name()},
    %      endif
    %      if field.get_c_typename() == 'TYPE_ASSERT':
                .val.bitset = { ${', '.join(isa.split_bits(field.val, 32))} },
    %      endif
    %      if field.get_c_typename() == 'TYPE_BRANCH' or field.get_c_typename() == 'TYPE_ABSBRANCH':
                .call = ${str(field.call).lower()},
    %      endif
              },
    %   endfor
           },
    };
    %   endfor
    static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min} = {
    <% pattern = bitset.get_pattern() %>
    %   if bitset.extends is not None:
           .parent   = &bitset_${isa.bitsets[bitset.extends].get_c_name()}_gen_${isa.bitsets[bitset.extends].gen_min},
    %   endif
           .name     = "${bitset.display_name}",
           .gen      = {
               .min  = ${bitset.get_gen_min()},
               .max  = ${bitset.get_gen_max()},
           },
           .match.bitset    = { ${', '.join(isa.split_bits(pattern.match, 32))} },
           .dontcare.bitset = { ${', '.join(isa.split_bits(pattern.dontcare, 32))} },
           .mask.bitset     = { ${', '.join(isa.split_bits(pattern.mask, 32))} },
           .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min},
           .num_decode_fields = ARRAY_SIZE(decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields),
           .decode_fields = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields,
           .num_cases = ${len(bitset.cases)},
           .cases    = {
    %   for case in bitset.cases:
                &${case.get_c_name()}_gen_${bitset.gen_min},
    %   endfor
           },
    };
    %endfor
    
    /*
     * bitset hierarchy root tables (where decoding starts from):
     */
    
    %for root_name, root in isa.roots.items():
    static const struct isa_bitset *${root.get_c_name()}[] = {
    %   for leaf_name, leafs in isa.leafs.items():
    %      for leaf in leafs:
    %         if leaf.get_root() == root:
                 &bitset_${leaf.get_c_name()}_gen_${leaf.gen_min},
    %         endif
    %      endfor
    %   endfor
        (void *)0
    };
    %endfor
    
    #include "isaspec_decode_impl.c"
    
    %for name, bitset in isa.all_bitsets():
    %   for df in s.decode_fields(bitset):
    <%  field = s.resolve_simple_field(bitset, df.name) %>
    static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val)
    {
    %       if bitset.get_root().decode is not None and field is not None:
        ${bitset.get_root().encode.type} src = *(${bitset.get_root().encode.type} *)out;
    %           if field.get_c_typename() == 'TYPE_BITSET':
        isa_decode_bitset(&${df.map_expr}, ${isa.roots[field.type].get_c_name()}, scope, uint64_t_to_bitmask(val));
    %           elif field.get_c_typename() in ['TYPE_BRANCH', 'TYPE_INT', 'TYPE_OFFSET']:
        ${df.map_expr} = util_sign_extend(val, ${field.get_size()});
    %           else:
        ${df.map_expr} = val;
    %           endif
        *(${bitset.get_root().encode.type} *)out = src;
    %       endif
    }
    
    %   endfor
    static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope)
    {
    %   if bitset.get_root().decode is not None:
        UNUSED ${bitset.get_root().encode.type} src;
    %       if bitset.get_root().encode.type.endswith('*') and name in isa.leafs and bitset.get_root().encode.case_prefix is not None:
        src = ${bitset.get_root().get_c_name()}_create(${s.case_name(bitset.get_root(), bitset.name)});
        *(${bitset.get_root().encode.type} *)out = src;
    %       endif
    %   endif
    }
    %endfor
    
    void ${prefix}_isa_disasm(void *bin, int sz, FILE *out, const struct isa_decode_options *options)
    {
        isa_disasm(bin, sz, out, options);
    }
    
    bool ${prefix}_isa_decode(void *out, void *bin, const struct isa_decode_options *options)
    {
        return isa_decode(out, bin, options);
    }
    
    uint32_t ${prefix}_isa_get_gpu_id(struct decode_scope *scope)
    {
        return isa_get_gpu_id(scope);
    }
    """
    
    header = """\
    /* Copyright (C) 2020 Google, Inc.
     *
     * 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.
     */
    
    #ifndef _${guard}_
    #define _${guard}_
    
    #include "compiler/isaspec/isaspec.h"
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void ${prefix}_isa_disasm(void *bin, int sz, FILE *out, const struct isa_decode_options *options);
    bool ${prefix}_isa_decode(void *out, void *bin, const struct isa_decode_options *options);
    
    struct decode_scope;
    
    uint32_t ${prefix}_isa_get_gpu_id(struct decode_scope *scope);
    
    /**
     * Allows to use gpu_id in expr functions
     */
    #define ISA_GPU_ID() ${prefix}_isa_get_gpu_id(scope)
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif /* _${guard}_ */
    
    """
    
    def guard(p):
        return os.path.basename(p).upper().replace("-", "_").replace(".", "_")
    
    def prefix(p):
        return os.path.basename(p).lower().replace("-", "_").replace(".", "_").split('_')[0]
    
    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument('--xml', required=True, help='isaspec XML file.')
        parser.add_argument('--out-c', required=True, help='Output C file.')
        parser.add_argument('--out-h', required=True, help='Output H file.')
        args = parser.parse_args()
    
        isa = ISA(args.xml)
        s = State(isa)
    
        try:
            with open(args.out_c, 'w', encoding='utf-8') as f:
                out_h_basename = os.path.basename(args.out_h)
                f.write(Template(template).render(isa=isa, s=s, header=out_h_basename, prefix=prefix(args.out_h)))
    
            with open(args.out_h, 'w', encoding='utf-8') as f:
                f.write(Template(header).render(isa=isa, guard=guard(args.out_h), prefix=prefix(args.out_h)))
    
        except Exception:
            # In the event there's an error, this imports some helpers from mako
            # to print a useful stack trace and prints it, then exits with
            # status 1, if python is run with debug; otherwise it just raises
            # the exception
            import sys
            from mako import exceptions
            print(exceptions.text_error_template().render(), file=sys.stderr)
            sys.exit(1)
    
    if __name__ == '__main__':
        main()