xref: /aosp_15_r20/external/mesa3d/src/compiler/isaspec/encode.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, BitSetDerivedField, BitSetAssertField
26import argparse
27import sys
28import re
29
30# Encoding is driven by the display template that would be used
31# to decode any given instruction, essentially working backwards
32# from the decode case.  (Or put another way, the decoded bitset
33# should contain enough information to re-encode it again.)
34#
35# In the xml, we can have multiple override cases per bitset,
36# which can override display template and/or fields.  Iterating
37# all this from within the template is messy, so use helpers
38# outside of the template for this.
39#
40# The hierarchy of iterators for encoding is:
41#
42#   // First level - Case()  (s.bitset_cases() iterator)
43#   if (caseA.expression()) {  // maps to <override/> in xml
44#      // Second level - DisplayField()  (case.display_fields() iterator)
45#      ... encode field A ...
46#      ... encode field B ...
47#
48#      // Third level - each display field can be potentially resolved
49#      // by multiple different overrides, you can end up with
50#      // an if/else ladder for an individual display field
51#      if (field_c_case1.expression()) {
52#         ... encode field C ...
53#      } else if (field_c_case2.expression() {
54#         ... encode field C ...
55#      } else {
56#      }
57#
58#   } else if (caseB.expression())(
59#   } else {  // maps to the default case in bitset, ie. outside <override/>
60#   }
61
62
63# Represents a concrete field, ie. a field can be overriden
64# by an override, so the exact choice to encode a given field
65# in a bitset may be conditional
66class FieldCase(object):
67    def __init__(self, bitset, field, case):
68        self.field = field
69        self.expr  = None
70        if case.expr is not None:
71            self.expr = bitset.isa.expressions[case.expr]
72
73    def signed(self):
74        if self.field.type in ['int', 'offset', 'branch']:
75            return 'true'
76        return 'false'
77
78class AssertField(object):
79    def __init__(self, bitset, field, case):
80        self.field = field
81        self.expr  = None
82        if case.expr is not None:
83            self.expr = bitset.isa.expressions[case.expr]
84
85    def signed(self):
86        return 'false'
87
88# Represents a field to be encoded:
89class DisplayField(object):
90    def __init__(self, bitset, case, name):
91        self.bitset = bitset   # leaf bitset
92        self.case = case
93        self.name = name
94
95    def fields(self, bitset=None):
96        if bitset is None:
97            bitset = self.bitset
98        # resolving the various cases for encoding a given
99        # field is similar to resolving the display template
100        # string
101        for case in bitset.cases:
102            if case.expr is not None:
103                expr = bitset.isa.expressions[case.expr]
104                self.case.append_expr_fields(expr)
105            if self.name in case.fields:
106                field = case.fields[self.name]
107                # For bitset fields, the bitset type could reference
108                # fields in this (the containing) bitset, in addition
109                # to the ones which are directly used to encode the
110                # field itself.
111                if field.get_c_typename() == 'TYPE_BITSET':
112                    for param in field.params:
113                        self.case.append_field(param[0])
114                # For derived fields, we want to consider any other
115                # fields that are referenced by the expr
116                if isinstance(field, BitSetDerivedField):
117                    expr = bitset.isa.expressions[field.expr]
118                    self.case.append_expr_fields(expr)
119                elif not isinstance(field, BitSetAssertField):
120                    yield FieldCase(bitset, field, case)
121                # if we've found an unconditional case specifying
122                # the named field, we are done
123                if case.expr is None:
124                    return
125        if bitset.extends is not None:
126            yield from self.fields(bitset.isa.bitsets[bitset.extends])
127
128# Represents an if/else case in bitset encoding which has a display
129# template string:
130class Case(object):
131    def __init__(self, bitset, case):
132        self.bitset = bitset   # leaf bitset
133        self.case = case
134        self.expr = None
135        if case.expr is not None:
136            self.expr = bitset.isa.expressions[case.expr]
137        self.fieldnames = re.findall(r"{([a-zA-Z0-9_:=]+)}", case.display)
138        self.append_forced(bitset)
139
140        # remove special fieldname properties e.g. :align=
141        self.fieldnames = list(map(lambda name: name.split(':')[0], self.fieldnames))
142
143    # Handle fields which don't appear in display template but have
144    # force="true"
145    def append_forced(self, bitset):
146        if bitset.encode is not None:
147            for name, val in bitset.encode.forced.items():
148                self.append_field(name)
149        if bitset.extends is not None:
150            self.append_forced(bitset.isa.bitsets[bitset.extends])
151
152    # In the process of resolving a field, we might discover additional
153    # fields that need resolving:
154    #
155    # a) a derived field which maps to one or more other concrete fields
156    # b) a bitset field, which may be "parameterized".. for example a
157    #    #multisrc field which refers back to SRC1_R/SRC2_R outside of
158    #    the range of bits covered by the #multisrc field itself
159    def append_field(self, fieldname):
160        if fieldname not in self.fieldnames:
161            self.fieldnames.append(fieldname)
162
163    def append_expr_fields(self, expr):
164        for fieldname in expr.fieldnames:
165            self.append_field(fieldname)
166
167    def display_fields(self):
168        for fieldname in self.fieldnames:
169            yield DisplayField(self.bitset, self, fieldname)
170
171    def assert_cases(self, bitset=None):
172        if bitset is None:
173            bitset = self.bitset
174        for case in bitset.cases:
175            for name, field in case.fields.items():
176                if field.get_c_typename() == 'TYPE_ASSERT':
177                    yield AssertField(bitset, field, case)
178        if bitset.extends is not None:
179            yield from self.assert_cases(bitset.isa.bitsets[bitset.extends])
180
181# State and helpers used by the template:
182class State(object):
183    def __init__(self, isa):
184        self.isa = isa
185        self.warned_missing_extractors = []
186
187    def bitset_cases(self, bitset, leaf_bitset=None):
188        if leaf_bitset is None:
189            leaf_bitset = bitset
190        for case in bitset.cases:
191            if case.display is None:
192                # if this is the last case (ie. case.expr is None)
193                # then we need to go up the inheritance chain:
194                if case.expr is None and bitset.extends is not None:
195                    parent_bitset = bitset.isa.bitsets[bitset.extends]
196                    yield from self.bitset_cases(parent_bitset, leaf_bitset)
197                continue
198            yield Case(leaf_bitset, case)
199
200    # Find unique bitset remap/parameter names, to generate a struct
201    # used to pass "parameters" to bitset fields:
202    def unique_param_names(self):
203        unique_names = []
204        for root in self.encode_roots():
205            for leaf in self.encode_leafs(root):
206                for case in self.bitset_cases(leaf):
207                    for df in case.display_fields():
208                        for f in df.fields():
209                            if f.field.get_c_typename() == 'TYPE_BITSET':
210                                for param in f.field.params:
211                                    target_name = param[1]
212                                    if target_name not in unique_names:
213                                        yield target_name
214                                        unique_names.append(target_name)
215
216    def case_name(self, bitset, name):
217       return bitset.encode.case_prefix + name.upper().replace('.', '_').replace('-', '_').replace('#', '')
218
219    def encode_roots(self):
220       for name, root in self.isa.roots.items():
221          if root.encode is None:
222             continue
223          yield root
224
225    def encode_leafs(self, root):
226        for name, leafs in self.isa.leafs.items():
227            for leaf in leafs:
228                if leaf.get_root() != root:
229                    continue
230                yield leaf
231
232    def encode_leaf_groups(self, root):
233        for name, leafs in self.isa.leafs.items():
234            if leafs[0].get_root() != root:
235                continue
236            yield leafs
237
238    # expressions used in a bitset (case or field or recursively parent bitsets)
239    def bitset_used_exprs(self, bitset):
240       for case in bitset.cases:
241          if case.expr:
242             yield self.isa.expressions[case.expr]
243          for name, field in case.fields.items():
244             if isinstance(field, BitSetDerivedField):
245                yield self.isa.expressions[field.expr]
246       if bitset.extends is not None:
247          yield from self.bitset_used_exprs(self.isa.bitsets[bitset.extends])
248
249    def extractor_impl(self, bitset, name):
250        if bitset.encode is not None:
251            if name in bitset.encode.maps:
252                return bitset.encode.maps[name]
253        if bitset.extends is not None:
254            return self.extractor_impl(self.isa.bitsets[bitset.extends], name)
255        return None
256
257    # Default fallback when no mapping is defined, simply to avoid
258    # having to deal with encoding at the same time as r/e new
259    # instruction decoding.. but we can at least print warnings:
260    def extractor_fallback(self, bitset, name):
261        extr_name = bitset.name + '.' + name
262        if extr_name not in self.warned_missing_extractors:
263            print('WARNING: no encode mapping for {}.{}'.format(bitset.name, name))
264            self.warned_missing_extractors.append(extr_name)
265        return '0 /* XXX */'
266
267    def extractor(self, bitset, name):
268        extr = self.extractor_impl(bitset, name)
269        if extr is not None:
270            return extr
271        return self.extractor_fallback(bitset, name)
272
273    # In the special case of needing to access a field with bitset type
274    # for an expr, we need to encode the field so we end up with an
275    # integer, and not some pointer to a thing that will be encoded to
276    # an integer
277    def expr_extractor(self, bitset, name, p):
278        extr = self.extractor_impl(bitset, name)
279        field = self.resolve_simple_field(bitset, name)
280        if isinstance(field, BitSetDerivedField):
281            expr = self.isa.expressions[field.expr]
282            return self.expr_name(bitset.get_root(), expr) + '(s, p, src)'
283        if extr is None:
284            if name in self.unique_param_names():
285                extr = 'p->' + name
286            else:
287                extr = self.extractor_fallback(bitset, name)
288        if field and field.get_c_typename() == 'TYPE_BITSET':
289            extr = 'encode' + self.isa.roots[field.type].get_c_name() + '(s, ' + p + ', ' + extr + ')'
290        return extr
291
292    # A limited resolver for field type which doesn't properly account for
293    # overrides.  In particular, if a field is defined differently in multiple
294    # different cases, this just blindly picks the last one.
295    #
296    # TODO to do this properly, I don't think there is an alternative than
297    # to emit code which evaluates the case.expr
298    def resolve_simple_field(self, bitset, name):
299        field = None
300        for case in bitset.cases:
301            if name in case.fields:
302                field = case.fields[name]
303        if field is not None:
304            return field
305        if bitset.extends is not None:
306            return self.resolve_simple_field(bitset.isa.bitsets[bitset.extends], name)
307        return None
308
309    def encode_type(self, bitset):
310        if bitset.encode is not None:
311            if bitset.encode.type is not None:
312                return bitset.encode.type
313        if bitset.extends is not None:
314            return self.encode_type(bitset.isa.bitsets[bitset.extends])
315        return None
316
317    def expr_name(self, root, expr):
318       return root.get_c_name() + '_' + expr.get_c_name()
319
320template = """\
321/* Copyright (C) 2020 Google, Inc.
322 *
323 * Permission is hereby granted, free of charge, to any person obtaining a
324 * copy of this software and associated documentation files (the "Software"),
325 * to deal in the Software without restriction, including without limitation
326 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
327 * and/or sell copies of the Software, and to permit persons to whom the
328 * Software is furnished to do so, subject to the following conditions:
329 *
330 * The above copyright notice and this permission notice (including the next
331 * paragraph) shall be included in all copies or substantial portions of the
332 * Software.
333 *
334 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
335 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
336 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
337 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
338 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
339 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
340 * IN THE SOFTWARE.
341 */
342
343#include <assert.h>
344#include <stdbool.h>
345#include <stdint.h>
346#include <util/bitset.h>
347#include <util/log.h>
348
349<%
350isa = s.isa
351%>
352
353#define BITMASK_WORDS BITSET_WORDS(${isa.bitsize})
354
355typedef struct {
356    BITSET_WORD bitset[BITMASK_WORDS];
357} bitmask_t;
358
359static inline uint64_t
360bitmask_to_uint64_t(bitmask_t mask)
361{
362%   if isa.bitsize <= 32:
363    return mask.bitset[0];
364%   else:
365    return ((uint64_t)mask.bitset[1] << 32) | mask.bitset[0];
366%   endif
367}
368
369static inline bitmask_t
370uint64_t_to_bitmask(uint64_t val)
371{
372    bitmask_t mask = {
373        .bitset[0] = val & 0xffffffff,
374%   if isa.bitsize > 32:
375        .bitset[1] = (val >> 32) & 0xffffffff,
376%   endif
377    };
378
379    return mask;
380}
381
382static inline void
383store_instruction(BITSET_WORD *dst, bitmask_t instr)
384{
385%   for i in range(0, int(isa.bitsize / 32)):
386    *(dst + ${i}) = instr.bitset[${i}];
387%   endfor
388}
389
390/**
391 * Opaque type from the PoV of generated code, but allows state to be passed
392 * thru to the hand written helpers used by the generated code.
393 */
394struct encode_state;
395
396/**
397 * Allows to use gpu_id in expr functions
398 */
399#define ISA_GPU_ID() s->gen
400
401struct bitset_params;
402
403static bitmask_t
404pack_field(unsigned low, unsigned high, int64_t val, bool is_signed)
405{
406   bitmask_t field, mask;
407
408   if (is_signed) {
409      /* NOTE: Don't assume val is already sign-extended to 64b,
410       * just check that the bits above the valid range are either
411       * all zero or all one:
412       */
413      assert(!(( val & ~BITFIELD64_MASK(1 + high - low)) &&
414               (~val & ~BITFIELD64_MASK(1 + high - low))));
415   } else {
416      assert(!(val & ~BITFIELD64_MASK(1 + high - low)));
417   }
418
419   BITSET_ZERO(field.bitset);
420
421   if (!val)
422      return field;
423
424   BITSET_ZERO(mask.bitset);
425   BITSET_SET_RANGE(mask.bitset, 0, high - low);
426
427   field = uint64_t_to_bitmask(val);
428   BITSET_AND(field.bitset, field.bitset, mask.bitset);
429   BITSET_SHL(field.bitset, low);
430
431   return field;
432}
433
434/*
435 * Forward-declarations (so we don't have to figure out which order to
436 * emit various encoders when they have reference each other)
437 */
438
439%for root in s.encode_roots():
440static bitmask_t encode${root.get_c_name()}(struct encode_state *s, const struct bitset_params *p, const ${root.encode.type} src);
441%endfor
442
443## TODO before the expr evaluators, we should generate extract_FOO() for
444## derived fields.. which probably also need to be in the context of the
445## respective root so they take the correct src arg??
446
447/*
448 * Expression evaluators:
449 */
450
451struct bitset_params {
452%for name in s.unique_param_names():
453   int64_t ${name};
454%endfor
455};
456
457## TODO can we share this def between the two templates somehow?
458<%def name="encode_params(leaf, field)">
459 struct bitset_params bp = {
460%for param in field.params:
461    .${param[1]} = ${s.expr_extractor(leaf, param[0], 'p')},  /* ${param[0]} */
462%endfor
463 };
464</%def>
465
466<%def name="render_expr(leaf, expr)">
467static inline int64_t
468${s.expr_name(leaf.get_root(), expr)}(struct encode_state *s, const struct bitset_params *p, const ${leaf.get_root().encode.type} src)
469{
470%   for fieldname in expr.fieldnames:
471    int64_t ${fieldname};
472%   endfor
473%   for fieldname in expr.fieldnames:
474<% field = s.resolve_simple_field(leaf, fieldname) %>
475%      if field is not None and field.get_c_typename() == 'TYPE_BITSET':
476          { ${encode_params(leaf, field)}
477          const bitmask_t tmp = ${s.expr_extractor(leaf, fieldname, '&bp')};
478          ${fieldname} = bitmask_to_uint64_t(tmp);
479          }
480%      else:
481          ${fieldname} = ${s.expr_extractor(leaf, fieldname, 'p')};
482%      endif
483%   endfor
484    return ${expr.expr};
485}
486</%def>
487
488## note, we can't just iterate all the expressions, but we need to find
489## the context in which they are used to know the correct src type
490
491%for root in s.encode_roots():
492%   for leaf in s.encode_leafs(root):
493%      for expr in s.bitset_used_exprs(leaf):
494static inline int64_t ${s.expr_name(leaf.get_root(), expr)}(struct encode_state *s, const struct bitset_params *p, const ${leaf.get_root().encode.type} src);
495%      endfor
496%   endfor
497%endfor
498
499%for root in s.encode_roots():
500<%
501    rendered_exprs = []
502%>
503%   for leaf in s.encode_leafs(root):
504%      for expr in s.bitset_used_exprs(leaf):
505<%
506          if expr in rendered_exprs:
507             continue
508          rendered_exprs.append(expr)
509%>
510          ${render_expr(leaf, expr)}
511%      endfor
512%   endfor
513%endfor
514
515
516/*
517 * The actual encoder definitions
518 */
519
520%for root in s.encode_roots():
521%   for leaf in s.encode_leafs(root):
522<% snippet = encode_bitset.render(s=s, root=root, leaf=leaf) %>
523%      if snippet not in root.snippets.keys():
524<% snippet_name = "snippet" + root.get_c_name() + "_" + str(len(root.snippets)) %>
525static bitmask_t
526${snippet_name}(struct encode_state *s, const struct bitset_params *p, const ${root.encode.type} src)
527{
528   bitmask_t val = uint64_t_to_bitmask(0);
529${snippet}
530   return val;
531}
532<% root.snippets[snippet] = snippet_name %>
533%      endif
534%   endfor
535
536static bitmask_t
537encode${root.get_c_name()}(struct encode_state *s, const struct bitset_params *p, const ${root.encode.type} src)
538{
539%   if root.encode.case_prefix is not None:
540   switch (${root.get_c_name()}_case(s, src)) {
541%      for leafs in s.encode_leaf_groups(root):
542   case ${s.case_name(root, leafs[0].name)}: {
543%         for leaf in leafs:
544%           if leaf.has_gen_restriction():
545      if (s->gen >= ${leaf.gen_min} && s->gen <= ${leaf.gen_max}) {
546%           endif
547<% snippet = encode_bitset.render(s=s, root=root, leaf=leaf) %>
548<%    words = isa.split_bits((leaf.get_pattern().match), 64) %>
549      bitmask_t val = uint64_t_to_bitmask(${words[-1]});
550
551<%    words.pop() %>
552
553%     for x in reversed(range(len(words))):
554      {
555         bitmask_t word = uint64_t_to_bitmask(${words[x]});
556         BITSET_SHL(val.bitset, 64);
557         BITSET_OR(val.bitset, val.bitset, word.bitset);
558      }
559%     endfor
560
561      BITSET_OR(val.bitset, val.bitset, ${root.snippets[snippet]}(s, p, src).bitset);
562      return val;
563%           if leaf.has_gen_restriction():
564      }
565%           endif
566%         endfor
567%         if leaf.has_gen_restriction():
568      break;
569%         endif
570    }
571%      endfor
572   default:
573      /* Note that we need the default case, because there are
574       * instructions which we never expect to be encoded, (ie.
575       * meta/macro instructions) as they are removed/replace
576       * in earlier stages of the compiler.
577       */
578      break;
579   }
580   mesa_loge("Unhandled ${root.name} encode case: 0x%x\\n", ${root.get_c_name()}_case(s, src));
581   return uint64_t_to_bitmask(0);
582%   else: # single case bitset, no switch
583%      for leaf in s.encode_leafs(root):
584<% snippet = encode_bitset.render(s=s, root=root, leaf=leaf) %>
585      bitmask_t val = uint64_t_to_bitmask(${hex(leaf.get_pattern().match)});
586      BITSET_OR(val.bitset, val.bitset, ${root.snippets[snippet]}(s, p, src).bitset);
587      return val;
588%      endfor
589%   endif
590}
591%endfor
592"""
593
594encode_bitset_template = """
595<%
596isa = s.isa
597%>
598
599<%def name="case_pre(root, expr)">
600%if expr is not None:
601    if (${s.expr_name(root, expr)}(s, p, src)) {
602%else:
603    {
604%endif
605</%def>
606
607<%def name="case_post(root, expr)">
608%if expr is not None:
609    } else
610%else:
611    }
612%endif
613</%def>
614
615<%def name="encode_params(leaf, field)">
616 struct bitset_params bp = {
617%for param in field.params:
618    .${param[1]} = ${s.expr_extractor(leaf, param[0], 'p')},  /* ${param[0]} */
619%endfor
620 };
621</%def>
622
623      uint64_t fld;
624
625      (void)fld;
626<% visited_exprs = [] %>
627%for case in s.bitset_cases(leaf):
628<%
629    if case.expr is not None:
630        visited_exprs.append(case.expr)
631
632    # per-expression-case track display-field-names that we have
633    # already emitted encoding for.  It is possible that an
634    # <override> case overrides a given field (for ex. #cat5-src3)
635    # and we don't want to emit encoding for both the override and
636    # the fallback
637    seen_fields = {}
638%>
639    ${case_pre(root, case.expr)}
640%   for df in case.display_fields():
641%       for f in df.fields():
642<%
643          # simplify the control flow a bit to give the compiler a bit
644          # less to clean up
645          expr = f.expr
646          if expr == case.expr:
647              # Don't need to evaluate the same condition twice:
648              expr = None
649          elif expr in visited_exprs:
650              # We are in an 'else'/'else-if' leg that we wouldn't
651              # go down due to passing an earlier if()
652              continue
653
654          if not expr in seen_fields.keys():
655              seen_fields[expr] = []
656
657          if f.field.name in seen_fields[expr]:
658              continue
659          seen_fields[expr].append(f.field.name)
660%>
661           ${case_pre(root, expr)}
662%         if f.field.get_c_typename() == 'TYPE_BITSET':
663             { ${encode_params(leaf, f.field)}
664               bitmask_t tmp = encode${isa.roots[f.field.type].get_c_name()}(s, &bp, ${s.extractor(leaf, f.field.name)});
665               fld = bitmask_to_uint64_t(tmp);
666             }
667%         else:
668             fld = ${s.extractor(leaf, f.field.name)};
669%         endif
670             const bitmask_t packed = pack_field(${f.field.low}, ${f.field.high}, fld, ${f.signed()});  /* ${f.field.name} */
671             BITSET_OR(val.bitset, val.bitset, packed.bitset);
672             ${case_post(root, expr)}
673%       endfor
674%   endfor
675
676%   for f in case.assert_cases():
677<%
678      # simplify the control flow a bit to give the compiler a bit
679      # less to clean up
680      expr = f.expr
681      if expr == case.expr:
682          # Don't need to evaluate the same condition twice:
683          expr = None
684      elif expr in visited_exprs:
685          # We are in an 'else'/'else-if' leg that we wouldn't
686          # go down due to passing an earlier if()
687          continue
688%>
689       ${case_pre(root, expr)}
690       const bitmask_t packed = pack_field(${f.field.low}, ${f.field.high}, ${f.field.val}, ${f.signed()});
691       BITSET_OR(val.bitset, val.bitset, packed.bitset);
692       ${case_post(root, None)}
693%   endfor
694      {}  /* in case no unconditional field to close out last '} else' */
695    ${case_post(root, case.expr)}
696%endfor
697"""
698
699def main():
700    parser = argparse.ArgumentParser()
701    parser.add_argument('--xml', required=True, help='isaspec XML file.')
702    parser.add_argument('--out-h', required=True, help='Output H file.')
703    args = parser.parse_args()
704
705    isa = ISA(args.xml)
706    s = State(isa)
707
708    try:
709        with open(args.out_h, 'w', encoding='utf-8') as f:
710            encode_bitset = Template(encode_bitset_template)
711            f.write(Template(template).render(s=s, encode_bitset=encode_bitset))
712
713    except Exception:
714        # In the event there's an error, this imports some helpers from mako
715        # to print a useful stack trace and prints it, then exits with
716        # status 1, if python is run with debug; otherwise it just raises
717        # the exception
718        import sys
719        from mako import exceptions
720        print(exceptions.text_error_template().render(), file=sys.stderr)
721        sys.exit(1)
722
723if __name__ == '__main__':
724    main()
725