xref: /aosp_15_r20/external/mesa3d/src/compiler/isaspec/decode.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#!/usr/bin/env python3
2#
3# Copyright © 2020 Google, Inc.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9# and/or sell copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice (including the next
13# paragraph) shall be included in all copies or substantial portions of the
14# Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23
24from mako.template import Template
25from isa import ISA
26import argparse
27import os
28import sys
29
30class FieldDecode(object):
31    def __init__(self, name, map_expr):
32        self.name = name
33        self.map_expr = map_expr
34
35    def get_c_name(self):
36        return self.name.lower().replace('-', '_')
37
38# State and helpers used by the template:
39class State(object):
40    def __init__(self, isa):
41        self.isa = isa
42
43    def case_name(self, bitset, name):
44        return bitset.encode.case_prefix + name.upper().replace('.', '_').replace('-', '_').replace('#', '')
45
46    # Return a list of all <map> entries for a leaf bitset, with the child
47    # bitset overriding the parent bitset's entries. Because we can't resolve
48    # which <map>s are used until we resolve which overload is used, we
49    # generate code for encoding all of these and then at runtime select which
50    # one to call based on the display.
51    def decode_fields(self, bitset):
52        if bitset.get_root().decode is None:
53            return
54
55        seen_fields = set()
56        if bitset.encode is not None:
57            for name, expr in bitset.encode.maps.items():
58                seen_fields.add(name)
59                yield FieldDecode(name, expr)
60
61        if bitset.extends is not None:
62            for field in self.decode_fields(self.isa.bitsets[bitset.extends]):
63                if field.name not in seen_fields:
64                    yield field
65
66    # A limited resolver for field type which doesn't properly account for
67    # overrides.  In particular, if a field is defined differently in multiple
68    # different cases, this just blindly picks the last one.
69    #
70    # TODO to do this properly, I don't think there is an alternative than
71    # to emit code which evaluates the case.expr
72    def resolve_simple_field(self, bitset, name):
73        field = None
74        for case in bitset.cases:
75            if name in case.fields:
76                field = case.fields[name]
77        if field is not None:
78            return field
79        if bitset.extends is not None:
80            return self.resolve_simple_field(bitset.isa.bitsets[bitset.extends], name)
81        return None
82
83template = """\
84/* Copyright (C) 2020 Google, Inc.
85 *
86 * Permission is hereby granted, free of charge, to any person obtaining a
87 * copy of this software and associated documentation files (the "Software"),
88 * to deal in the Software without restriction, including without limitation
89 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
90 * and/or sell copies of the Software, and to permit persons to whom the
91 * Software is furnished to do so, subject to the following conditions:
92 *
93 * The above copyright notice and this permission notice (including the next
94 * paragraph) shall be included in all copies or substantial portions of the
95 * Software.
96 *
97 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
98 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
99 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
100 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
101 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
102 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
103 * IN THE SOFTWARE.
104 */
105
106#include "${header}"
107
108#include <stdint.h>
109#include <util/bitset.h>
110
111#define BITMASK_WORDS BITSET_WORDS(${isa.bitsize})
112
113typedef struct {
114    BITSET_WORD bitset[BITMASK_WORDS];
115} bitmask_t;
116
117
118#define BITSET_FORMAT ${isa.format()}
119#define BITSET_VALUE(v) ${isa.value()}
120
121static inline void
122next_instruction(bitmask_t *instr, BITSET_WORD *start)
123{
124    %for i in range(0, int(isa.bitsize / 32)):
125    instr->bitset[${i}] = *(start + ${i});
126    %endfor
127}
128
129static inline uint64_t
130bitmask_to_uint64_t(bitmask_t mask)
131{
132%   if isa.bitsize <= 32:
133    return mask.bitset[0];
134%   else:
135    return ((uint64_t)mask.bitset[1] << 32) | mask.bitset[0];
136%   endif
137}
138
139static inline bitmask_t
140uint64_t_to_bitmask(uint64_t val)
141{
142    bitmask_t mask = {
143        .bitset[0] = val & 0xffffffff,
144%   if isa.bitsize > 32:
145        .bitset[1] = (val >> 32) & 0xffffffff,
146%   endif
147    };
148
149    return mask;
150}
151
152#include "isaspec_decode_decl.h"
153
154static uint64_t
155isa_decode_field(struct decode_scope *scope, const char *field_name);
156
157/*
158 * enum tables, these don't have any link back to other tables so just
159 * dump them up front before the bitset tables
160 */
161
162%for name, enum in isa.enums.items():
163static const struct isa_enum ${enum.get_c_name()} = {
164    .num_values = ${len(enum.values)},
165    .values = {
166%   for val, display in enum.values.items():
167        { .val = ${val}, .display = "${display}" },
168%   endfor
169    },
170};
171%endfor
172
173/*
174 * generated expression functions, can be linked from bitset tables, so
175 * also dump them up front
176 */
177
178%for name, expr in isa.expressions.items():
179static uint64_t
180${expr.get_c_name()}(struct decode_scope *scope)
181{
182%   for fieldname in sorted(expr.fieldnames):
183    int64_t ${fieldname} = isa_decode_field(scope, "${fieldname}");
184%   endfor
185    return ${expr.expr};
186}
187%endfor
188
189/* forward-declarations of bitset decode functions */
190%for name, bitset in isa.all_bitsets():
191%   for df in s.decode_fields(bitset):
192static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val);
193%   endfor
194static const struct isa_field_decode decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields[] = {
195%   for df in s.decode_fields(bitset):
196    {
197        .name = "${df.name}",
198        .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()},
199    },
200%   endfor
201};
202static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope);
203%endfor
204
205/*
206 * Forward-declarations (so we don't have to figure out which order to
207 * emit various tables when they have pointers to each other)
208 */
209
210%for name, bitset in isa.all_bitsets():
211static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min};
212%endfor
213
214%for root_name, root in isa.roots.items():
215static const struct isa_bitset *${root.get_c_name()}[];
216%endfor
217
218/*
219 * bitset tables:
220 */
221
222%for name, bitset in isa.all_bitsets():
223%   for case in bitset.cases:
224%      for field_name, field in case.fields.items():
225%         if field.get_c_typename() == 'TYPE_BITSET':
226%            if len(field.params) > 0:
227static const struct isa_field_params ${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()} = {
228       .num_params = ${len(field.params)},
229       .params = {
230%               for param in field.params:
231           { .name= "${param[0]}",  .as = "${param[1]}" },
232%               endfor
233
234       },
235};
236%            endif
237%         endif
238%      endfor
239static const struct isa_case ${case.get_c_name()}_gen_${bitset.gen_min} = {
240%   if case.expr is not None:
241       .expr     = &${isa.expressions[case.expr].get_c_name()},
242%   endif
243%   if case.display is not None:
244       .display  = "${case.display}",
245%   endif
246       .num_fields = ${len(case.fields)},
247       .fields   = {
248%   for field_name, field in case.fields.items():
249          { .name = "${field_name}", .low = ${field.low}, .high = ${field.high},
250%      if field.expr is not None:
251            .expr = &${isa.expressions[field.expr].get_c_name()},
252%      endif
253%      if field.display is not None:
254            .display = "${field.display}",
255%      endif
256            .type = ${field.get_c_typename()},
257%      if field.get_c_typename() == 'TYPE_BITSET':
258            .bitsets = ${isa.roots[field.type].get_c_name()},
259%         if len(field.params) > 0:
260            .params = &${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()},
261%         endif
262%      endif
263%      if field.get_c_typename() == 'TYPE_ENUM':
264            .enums = &${isa.enums[field.type].get_c_name()},
265%      endif
266%      if field.get_c_typename() == 'TYPE_ASSERT':
267            .val.bitset = { ${', '.join(isa.split_bits(field.val, 32))} },
268%      endif
269%      if field.get_c_typename() == 'TYPE_BRANCH' or field.get_c_typename() == 'TYPE_ABSBRANCH':
270            .call = ${str(field.call).lower()},
271%      endif
272          },
273%   endfor
274       },
275};
276%   endfor
277static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min} = {
278<% pattern = bitset.get_pattern() %>
279%   if bitset.extends is not None:
280       .parent   = &bitset_${isa.bitsets[bitset.extends].get_c_name()}_gen_${isa.bitsets[bitset.extends].gen_min},
281%   endif
282       .name     = "${bitset.display_name}",
283       .gen      = {
284           .min  = ${bitset.get_gen_min()},
285           .max  = ${bitset.get_gen_max()},
286       },
287       .match.bitset    = { ${', '.join(isa.split_bits(pattern.match, 32))} },
288       .dontcare.bitset = { ${', '.join(isa.split_bits(pattern.dontcare, 32))} },
289       .mask.bitset     = { ${', '.join(isa.split_bits(pattern.mask, 32))} },
290       .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min},
291       .num_decode_fields = ARRAY_SIZE(decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields),
292       .decode_fields = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields,
293       .num_cases = ${len(bitset.cases)},
294       .cases    = {
295%   for case in bitset.cases:
296            &${case.get_c_name()}_gen_${bitset.gen_min},
297%   endfor
298       },
299};
300%endfor
301
302/*
303 * bitset hierarchy root tables (where decoding starts from):
304 */
305
306%for root_name, root in isa.roots.items():
307static const struct isa_bitset *${root.get_c_name()}[] = {
308%   for leaf_name, leafs in isa.leafs.items():
309%      for leaf in leafs:
310%         if leaf.get_root() == root:
311             &bitset_${leaf.get_c_name()}_gen_${leaf.gen_min},
312%         endif
313%      endfor
314%   endfor
315    (void *)0
316};
317%endfor
318
319#include "isaspec_decode_impl.c"
320
321%for name, bitset in isa.all_bitsets():
322%   for df in s.decode_fields(bitset):
323<%  field = s.resolve_simple_field(bitset, df.name) %>
324static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val)
325{
326%       if bitset.get_root().decode is not None and field is not None:
327    ${bitset.get_root().encode.type} src = *(${bitset.get_root().encode.type} *)out;
328%           if field.get_c_typename() == 'TYPE_BITSET':
329    isa_decode_bitset(&${df.map_expr}, ${isa.roots[field.type].get_c_name()}, scope, uint64_t_to_bitmask(val));
330%           elif field.get_c_typename() in ['TYPE_BRANCH', 'TYPE_INT', 'TYPE_OFFSET']:
331    ${df.map_expr} = util_sign_extend(val, ${field.get_size()});
332%           else:
333    ${df.map_expr} = val;
334%           endif
335    *(${bitset.get_root().encode.type} *)out = src;
336%       endif
337}
338
339%   endfor
340static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope)
341{
342%   if bitset.get_root().decode is not None:
343    UNUSED ${bitset.get_root().encode.type} src;
344%       if bitset.get_root().encode.type.endswith('*') and name in isa.leafs and bitset.get_root().encode.case_prefix is not None:
345    src = ${bitset.get_root().get_c_name()}_create(${s.case_name(bitset.get_root(), bitset.name)});
346    *(${bitset.get_root().encode.type} *)out = src;
347%       endif
348%   endif
349}
350%endfor
351
352void ${prefix}_isa_disasm(void *bin, int sz, FILE *out, const struct isa_decode_options *options)
353{
354    isa_disasm(bin, sz, out, options);
355}
356
357bool ${prefix}_isa_decode(void *out, void *bin, const struct isa_decode_options *options)
358{
359    return isa_decode(out, bin, options);
360}
361
362uint32_t ${prefix}_isa_get_gpu_id(struct decode_scope *scope)
363{
364    return isa_get_gpu_id(scope);
365}
366"""
367
368header = """\
369/* Copyright (C) 2020 Google, Inc.
370 *
371 * Permission is hereby granted, free of charge, to any person obtaining a
372 * copy of this software and associated documentation files (the "Software"),
373 * to deal in the Software without restriction, including without limitation
374 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
375 * and/or sell copies of the Software, and to permit persons to whom the
376 * Software is furnished to do so, subject to the following conditions:
377 *
378 * The above copyright notice and this permission notice (including the next
379 * paragraph) shall be included in all copies or substantial portions of the
380 * Software.
381 *
382 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
383 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
384 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
385 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
386 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
387 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
388 * IN THE SOFTWARE.
389 */
390
391#ifndef _${guard}_
392#define _${guard}_
393
394#include "compiler/isaspec/isaspec.h"
395
396#ifdef __cplusplus
397extern "C" {
398#endif
399
400void ${prefix}_isa_disasm(void *bin, int sz, FILE *out, const struct isa_decode_options *options);
401bool ${prefix}_isa_decode(void *out, void *bin, const struct isa_decode_options *options);
402
403struct decode_scope;
404
405uint32_t ${prefix}_isa_get_gpu_id(struct decode_scope *scope);
406
407/**
408 * Allows to use gpu_id in expr functions
409 */
410#define ISA_GPU_ID() ${prefix}_isa_get_gpu_id(scope)
411
412#ifdef __cplusplus
413}
414#endif
415
416#endif /* _${guard}_ */
417
418"""
419
420def guard(p):
421    return os.path.basename(p).upper().replace("-", "_").replace(".", "_")
422
423def prefix(p):
424    return os.path.basename(p).lower().replace("-", "_").replace(".", "_").split('_')[0]
425
426def main():
427    parser = argparse.ArgumentParser()
428    parser.add_argument('--xml', required=True, help='isaspec XML file.')
429    parser.add_argument('--out-c', required=True, help='Output C file.')
430    parser.add_argument('--out-h', required=True, help='Output H file.')
431    args = parser.parse_args()
432
433    isa = ISA(args.xml)
434    s = State(isa)
435
436    try:
437        with open(args.out_c, 'w', encoding='utf-8') as f:
438            out_h_basename = os.path.basename(args.out_h)
439            f.write(Template(template).render(isa=isa, s=s, header=out_h_basename, prefix=prefix(args.out_h)))
440
441        with open(args.out_h, 'w', encoding='utf-8') as f:
442            f.write(Template(header).render(isa=isa, guard=guard(args.out_h), prefix=prefix(args.out_h)))
443
444    except Exception:
445        # In the event there's an error, this imports some helpers from mako
446        # to print a useful stack trace and prints it, then exits with
447        # status 1, if python is run with debug; otherwise it just raises
448        # the exception
449        import sys
450        from mako import exceptions
451        print(exceptions.text_error_template().render(), file=sys.stderr)
452        sys.exit(1)
453
454if __name__ == '__main__':
455    main()
456