]> git.proxmox.com Git - mirror_qemu.git/blob - scripts/decodetree.py
hw/net: e1000: Remove the logic of padding short frames in the receive path
[mirror_qemu.git] / scripts / decodetree.py
1 #!/usr/bin/env python3
2 # Copyright (c) 2018 Linaro Limited
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 #
17
18 #
19 # Generate a decoding tree from a specification file.
20 # See the syntax and semantics in docs/devel/decodetree.rst.
21 #
22
23 import io
24 import os
25 import re
26 import sys
27 import getopt
28
29 insnwidth = 32
30 bitop_width = 32
31 insnmask = 0xffffffff
32 variablewidth = False
33 fields = {}
34 arguments = {}
35 formats = {}
36 allpatterns = []
37 anyextern = False
38 testforerror = False
39
40 translate_prefix = 'trans'
41 translate_scope = 'static '
42 input_file = ''
43 output_file = None
44 output_fd = None
45 output_null = False
46 insntype = 'uint32_t'
47 decode_function = 'decode'
48
49 # An identifier for C.
50 re_C_ident = '[a-zA-Z][a-zA-Z0-9_]*'
51
52 # Identifiers for Arguments, Fields, Formats and Patterns.
53 re_arg_ident = '&[a-zA-Z0-9_]*'
54 re_fld_ident = '%[a-zA-Z0-9_]*'
55 re_fmt_ident = '@[a-zA-Z0-9_]*'
56 re_pat_ident = '[a-zA-Z0-9_]*'
57
58 # Local implementation of a topological sort. We use the same API that
59 # the Python graphlib does, so that when QEMU moves forward to a
60 # baseline of Python 3.9 or newer this code can all be dropped and
61 # replaced with:
62 # from graphlib import TopologicalSorter, CycleError
63 #
64 # https://docs.python.org/3.9/library/graphlib.html#graphlib.TopologicalSorter
65 #
66 # We only implement the parts of TopologicalSorter we care about:
67 # ts = TopologicalSorter(graph=None)
68 # create the sorter. graph is a dictionary whose keys are
69 # nodes and whose values are lists of the predecessors of that node.
70 # (That is, if graph contains "A" -> ["B", "C"] then we must output
71 # B and C before A.)
72 # ts.static_order()
73 # returns a list of all the nodes in sorted order, or raises CycleError
74 # CycleError
75 # exception raised if there are cycles in the graph. The second
76 # element in the args attribute is a list of nodes which form a
77 # cycle; the first and last element are the same, eg [a, b, c, a]
78 # (Our implementation doesn't give the order correctly.)
79 #
80 # For our purposes we can assume that the data set is always small
81 # (typically 10 nodes or less, actual links in the graph very rare),
82 # so we don't need to worry about efficiency of implementation.
83 #
84 # The core of this implementation is from
85 # https://code.activestate.com/recipes/578272-topological-sort/
86 # (but updated to Python 3), and is under the MIT license.
87
88 class CycleError(ValueError):
89 """Subclass of ValueError raised if cycles exist in the graph"""
90 pass
91
92 class TopologicalSorter:
93 """Topologically sort a graph"""
94 def __init__(self, graph=None):
95 self.graph = graph
96
97 def static_order(self):
98 # We do the sort right here, unlike the stdlib version
99 from functools import reduce
100 data = {}
101 r = []
102
103 if not self.graph:
104 return []
105
106 # This code wants the values in the dict to be specifically sets
107 for k, v in self.graph.items():
108 data[k] = set(v)
109
110 # Find all items that don't depend on anything.
111 extra_items_in_deps = (reduce(set.union, data.values())
112 - set(data.keys()))
113 # Add empty dependencies where needed
114 data.update({item:{} for item in extra_items_in_deps})
115 while True:
116 ordered = set(item for item, dep in data.items() if not dep)
117 if not ordered:
118 break
119 r.extend(ordered)
120 data = {item: (dep - ordered)
121 for item, dep in data.items()
122 if item not in ordered}
123 if data:
124 # This doesn't give as nice results as the stdlib, which
125 # gives you the cycle by listing the nodes in order. Here
126 # we only know the nodes in the cycle but not their order.
127 raise CycleError(f'nodes are in a cycle', list(data.keys()))
128
129 return r
130 # end TopologicalSorter
131
132 def error_with_file(file, lineno, *args):
133 """Print an error message from file:line and args and exit."""
134 global output_file
135 global output_fd
136
137 prefix = ''
138 if file:
139 prefix += f'{file}:'
140 if lineno:
141 prefix += f'{lineno}:'
142 if prefix:
143 prefix += ' '
144 print(prefix, end='error: ', file=sys.stderr)
145 print(*args, file=sys.stderr)
146
147 if output_file and output_fd:
148 output_fd.close()
149 os.remove(output_file)
150 exit(0 if testforerror else 1)
151 # end error_with_file
152
153
154 def error(lineno, *args):
155 error_with_file(input_file, lineno, *args)
156 # end error
157
158
159 def output(*args):
160 global output_fd
161 for a in args:
162 output_fd.write(a)
163
164
165 def output_autogen():
166 output('/* This file is autogenerated by scripts/decodetree.py. */\n\n')
167
168
169 def str_indent(c):
170 """Return a string with C spaces"""
171 return ' ' * c
172
173
174 def str_fields(fields):
175 """Return a string uniquely identifying FIELDS"""
176 r = ''
177 for n in sorted(fields.keys()):
178 r += '_' + n
179 return r[1:]
180
181
182 def whex(val):
183 """Return a hex string for val padded for insnwidth"""
184 global insnwidth
185 return f'0x{val:0{insnwidth // 4}x}'
186
187
188 def whexC(val):
189 """Return a hex string for val padded for insnwidth,
190 and with the proper suffix for a C constant."""
191 suffix = ''
192 if val >= 0x100000000:
193 suffix = 'ull'
194 elif val >= 0x80000000:
195 suffix = 'u'
196 return whex(val) + suffix
197
198
199 def str_match_bits(bits, mask):
200 """Return a string pretty-printing BITS/MASK"""
201 global insnwidth
202
203 i = 1 << (insnwidth - 1)
204 space = 0x01010100
205 r = ''
206 while i != 0:
207 if i & mask:
208 if i & bits:
209 r += '1'
210 else:
211 r += '0'
212 else:
213 r += '.'
214 if i & space:
215 r += ' '
216 i >>= 1
217 return r
218
219
220 def is_pow2(x):
221 """Return true iff X is equal to a power of 2."""
222 return (x & (x - 1)) == 0
223
224
225 def ctz(x):
226 """Return the number of times 2 factors into X."""
227 assert x != 0
228 r = 0
229 while ((x >> r) & 1) == 0:
230 r += 1
231 return r
232
233
234 def is_contiguous(bits):
235 if bits == 0:
236 return -1
237 shift = ctz(bits)
238 if is_pow2((bits >> shift) + 1):
239 return shift
240 else:
241 return -1
242
243
244 def eq_fields_for_args(flds_a, arg):
245 if len(flds_a) != len(arg.fields):
246 return False
247 # Only allow inference on default types
248 for t in arg.types:
249 if t != 'int':
250 return False
251 for k, a in flds_a.items():
252 if k not in arg.fields:
253 return False
254 return True
255
256
257 def eq_fields_for_fmts(flds_a, flds_b):
258 if len(flds_a) != len(flds_b):
259 return False
260 for k, a in flds_a.items():
261 if k not in flds_b:
262 return False
263 b = flds_b[k]
264 if a.__class__ != b.__class__ or a != b:
265 return False
266 return True
267
268
269 class Field:
270 """Class representing a simple instruction field"""
271 def __init__(self, sign, pos, len):
272 self.sign = sign
273 self.pos = pos
274 self.len = len
275 self.mask = ((1 << len) - 1) << pos
276
277 def __str__(self):
278 if self.sign:
279 s = 's'
280 else:
281 s = ''
282 return str(self.pos) + ':' + s + str(self.len)
283
284 def str_extract(self, lvalue_formatter):
285 global bitop_width
286 s = 's' if self.sign else ''
287 return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})'
288
289 def referenced_fields(self):
290 return []
291
292 def __eq__(self, other):
293 return self.sign == other.sign and self.mask == other.mask
294
295 def __ne__(self, other):
296 return not self.__eq__(other)
297 # end Field
298
299
300 class MultiField:
301 """Class representing a compound instruction field"""
302 def __init__(self, subs, mask):
303 self.subs = subs
304 self.sign = subs[0].sign
305 self.mask = mask
306
307 def __str__(self):
308 return str(self.subs)
309
310 def str_extract(self, lvalue_formatter):
311 global bitop_width
312 ret = '0'
313 pos = 0
314 for f in reversed(self.subs):
315 ext = f.str_extract(lvalue_formatter)
316 if pos == 0:
317 ret = ext
318 else:
319 ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - pos}, {ext})'
320 pos += f.len
321 return ret
322
323 def referenced_fields(self):
324 l = []
325 for f in self.subs:
326 l.extend(f.referenced_fields())
327 return l
328
329 def __ne__(self, other):
330 if len(self.subs) != len(other.subs):
331 return True
332 for a, b in zip(self.subs, other.subs):
333 if a.__class__ != b.__class__ or a != b:
334 return True
335 return False
336
337 def __eq__(self, other):
338 return not self.__ne__(other)
339 # end MultiField
340
341
342 class ConstField:
343 """Class representing an argument field with constant value"""
344 def __init__(self, value):
345 self.value = value
346 self.mask = 0
347 self.sign = value < 0
348
349 def __str__(self):
350 return str(self.value)
351
352 def str_extract(self, lvalue_formatter):
353 return str(self.value)
354
355 def referenced_fields(self):
356 return []
357
358 def __cmp__(self, other):
359 return self.value - other.value
360 # end ConstField
361
362
363 class FunctionField:
364 """Class representing a field passed through a function"""
365 def __init__(self, func, base):
366 self.mask = base.mask
367 self.sign = base.sign
368 self.base = base
369 self.func = func
370
371 def __str__(self):
372 return self.func + '(' + str(self.base) + ')'
373
374 def str_extract(self, lvalue_formatter):
375 return (self.func + '(ctx, '
376 + self.base.str_extract(lvalue_formatter) + ')')
377
378 def referenced_fields(self):
379 return self.base.referenced_fields()
380
381 def __eq__(self, other):
382 return self.func == other.func and self.base == other.base
383
384 def __ne__(self, other):
385 return not self.__eq__(other)
386 # end FunctionField
387
388
389 class ParameterField:
390 """Class representing a pseudo-field read from a function"""
391 def __init__(self, func):
392 self.mask = 0
393 self.sign = 0
394 self.func = func
395
396 def __str__(self):
397 return self.func
398
399 def str_extract(self, lvalue_formatter):
400 return self.func + '(ctx)'
401
402 def referenced_fields(self):
403 return []
404
405 def __eq__(self, other):
406 return self.func == other.func
407
408 def __ne__(self, other):
409 return not self.__eq__(other)
410 # end ParameterField
411
412 class NamedField:
413 """Class representing a field already named in the pattern"""
414 def __init__(self, name, sign, len):
415 self.mask = 0
416 self.sign = sign
417 self.len = len
418 self.name = name
419
420 def __str__(self):
421 return self.name
422
423 def str_extract(self, lvalue_formatter):
424 global bitop_width
425 s = 's' if self.sign else ''
426 lvalue = lvalue_formatter(self.name)
427 return f'{s}extract{bitop_width}({lvalue}, 0, {self.len})'
428
429 def referenced_fields(self):
430 return [self.name]
431
432 def __eq__(self, other):
433 return self.name == other.name
434
435 def __ne__(self, other):
436 return not self.__eq__(other)
437 # end NamedField
438
439 class Arguments:
440 """Class representing the extracted fields of a format"""
441 def __init__(self, nm, flds, types, extern):
442 self.name = nm
443 self.extern = extern
444 self.fields = flds
445 self.types = types
446
447 def __str__(self):
448 return self.name + ' ' + str(self.fields)
449
450 def struct_name(self):
451 return 'arg_' + self.name
452
453 def output_def(self):
454 if not self.extern:
455 output('typedef struct {\n')
456 for (n, t) in zip(self.fields, self.types):
457 output(f' {t} {n};\n')
458 output('} ', self.struct_name(), ';\n\n')
459 # end Arguments
460
461 class General:
462 """Common code between instruction formats and instruction patterns"""
463 def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
464 self.name = name
465 self.file = input_file
466 self.lineno = lineno
467 self.base = base
468 self.fixedbits = fixb
469 self.fixedmask = fixm
470 self.undefmask = udfm
471 self.fieldmask = fldm
472 self.fields = flds
473 self.width = w
474 self.dangling = None
475
476 def __str__(self):
477 return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
478
479 def str1(self, i):
480 return str_indent(i) + self.__str__()
481
482 def dangling_references(self):
483 # Return a list of all named references which aren't satisfied
484 # directly by this format/pattern. This will be either:
485 # * a format referring to a field which is specified by the
486 # pattern(s) using it
487 # * a pattern referring to a field which is specified by the
488 # format it uses
489 # * a user error (referring to a field that doesn't exist at all)
490 if self.dangling is None:
491 # Compute this once and cache the answer
492 dangling = []
493 for n, f in self.fields.items():
494 for r in f.referenced_fields():
495 if r not in self.fields:
496 dangling.append(r)
497 self.dangling = dangling
498 return self.dangling
499
500 def output_fields(self, indent, lvalue_formatter):
501 # We use a topological sort to ensure that any use of NamedField
502 # comes after the initialization of the field it is referencing.
503 graph = {}
504 for n, f in self.fields.items():
505 refs = f.referenced_fields()
506 graph[n] = refs
507
508 try:
509 ts = TopologicalSorter(graph)
510 for n in ts.static_order():
511 # We only want to emit assignments for the keys
512 # in our fields list, not for anything that ends up
513 # in the tsort graph only because it was referenced as
514 # a NamedField.
515 try:
516 f = self.fields[n]
517 output(indent, lvalue_formatter(n), ' = ',
518 f.str_extract(lvalue_formatter), ';\n')
519 except KeyError:
520 pass
521 except CycleError as e:
522 # The second element of args is a list of nodes which form
523 # a cycle (there might be others too, but only one is reported).
524 # Pretty-print it to tell the user.
525 cycle = ' => '.join(e.args[1])
526 error(self.lineno, 'field definitions form a cycle: ' + cycle)
527 # end General
528
529
530 class Format(General):
531 """Class representing an instruction format"""
532
533 def extract_name(self):
534 global decode_function
535 return decode_function + '_extract_' + self.name
536
537 def output_extract(self):
538 output('static void ', self.extract_name(), '(DisasContext *ctx, ',
539 self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n')
540 self.output_fields(str_indent(4), lambda n: 'a->' + n)
541 output('}\n\n')
542 # end Format
543
544
545 class Pattern(General):
546 """Class representing an instruction pattern"""
547
548 def output_decl(self):
549 global translate_scope
550 global translate_prefix
551 output('typedef ', self.base.base.struct_name(),
552 ' arg_', self.name, ';\n')
553 output(translate_scope, 'bool ', translate_prefix, '_', self.name,
554 '(DisasContext *ctx, arg_', self.name, ' *a);\n')
555
556 def output_code(self, i, extracted, outerbits, outermask):
557 global translate_prefix
558 ind = str_indent(i)
559 arg = self.base.base.name
560 output(ind, '/* ', self.file, ':', str(self.lineno), ' */\n')
561 # We might have named references in the format that refer to fields
562 # in the pattern, or named references in the pattern that refer
563 # to fields in the format. This affects whether we extract the fields
564 # for the format before or after the ones for the pattern.
565 # For simplicity we don't allow cross references in both directions.
566 # This is also where we catch the syntax error of referring to
567 # a nonexistent field.
568 fmt_refs = self.base.dangling_references()
569 for r in fmt_refs:
570 if r not in self.fields:
571 error(self.lineno, f'format refers to undefined field {r}')
572 pat_refs = self.dangling_references()
573 for r in pat_refs:
574 if r not in self.base.fields:
575 error(self.lineno, f'pattern refers to undefined field {r}')
576 if pat_refs and fmt_refs:
577 error(self.lineno, ('pattern that uses fields defined in format '
578 'cannot use format that uses fields defined '
579 'in pattern'))
580 if fmt_refs:
581 # pattern fields first
582 self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
583 assert not extracted, "dangling fmt refs but it was already extracted"
584 if not extracted:
585 output(ind, self.base.extract_name(),
586 '(ctx, &u.f_', arg, ', insn);\n')
587 if not fmt_refs:
588 # pattern fields last
589 self.output_fields(ind, lambda n: 'u.f_' + arg + '.' + n)
590
591 output(ind, 'if (', translate_prefix, '_', self.name,
592 '(ctx, &u.f_', arg, ')) return true;\n')
593
594 # Normal patterns do not have children.
595 def build_tree(self):
596 return
597 def prop_masks(self):
598 return
599 def prop_format(self):
600 return
601 def prop_width(self):
602 return
603
604 # end Pattern
605
606
607 class MultiPattern(General):
608 """Class representing a set of instruction patterns"""
609
610 def __init__(self, lineno):
611 self.file = input_file
612 self.lineno = lineno
613 self.pats = []
614 self.base = None
615 self.fixedbits = 0
616 self.fixedmask = 0
617 self.undefmask = 0
618 self.width = None
619
620 def __str__(self):
621 r = 'group'
622 if self.fixedbits is not None:
623 r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
624 return r
625
626 def output_decl(self):
627 for p in self.pats:
628 p.output_decl()
629
630 def prop_masks(self):
631 global insnmask
632
633 fixedmask = insnmask
634 undefmask = insnmask
635
636 # Collect fixedmask/undefmask for all of the children.
637 for p in self.pats:
638 p.prop_masks()
639 fixedmask &= p.fixedmask
640 undefmask &= p.undefmask
641
642 # Widen fixedmask until all fixedbits match
643 repeat = True
644 fixedbits = 0
645 while repeat and fixedmask != 0:
646 fixedbits = None
647 for p in self.pats:
648 thisbits = p.fixedbits & fixedmask
649 if fixedbits is None:
650 fixedbits = thisbits
651 elif fixedbits != thisbits:
652 fixedmask &= ~(fixedbits ^ thisbits)
653 break
654 else:
655 repeat = False
656
657 self.fixedbits = fixedbits
658 self.fixedmask = fixedmask
659 self.undefmask = undefmask
660
661 def build_tree(self):
662 for p in self.pats:
663 p.build_tree()
664
665 def prop_format(self):
666 for p in self.pats:
667 p.prop_format()
668
669 def prop_width(self):
670 width = None
671 for p in self.pats:
672 p.prop_width()
673 if width is None:
674 width = p.width
675 elif width != p.width:
676 error_with_file(self.file, self.lineno,
677 'width mismatch in patterns within braces')
678 self.width = width
679
680 # end MultiPattern
681
682
683 class IncMultiPattern(MultiPattern):
684 """Class representing an overlapping set of instruction patterns"""
685
686 def output_code(self, i, extracted, outerbits, outermask):
687 global translate_prefix
688 ind = str_indent(i)
689 for p in self.pats:
690 if outermask != p.fixedmask:
691 innermask = p.fixedmask & ~outermask
692 innerbits = p.fixedbits & ~outermask
693 output(ind, f'if ((insn & {whexC(innermask)}) == {whexC(innerbits)}) {{\n')
694 output(ind, f' /* {str_match_bits(p.fixedbits, p.fixedmask)} */\n')
695 p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
696 output(ind, '}\n')
697 else:
698 p.output_code(i, extracted, p.fixedbits, p.fixedmask)
699
700 def build_tree(self):
701 if not self.pats:
702 error_with_file(self.file, self.lineno, 'empty pattern group')
703 super().build_tree()
704
705 #end IncMultiPattern
706
707
708 class Tree:
709 """Class representing a node in a decode tree"""
710
711 def __init__(self, fm, tm):
712 self.fixedmask = fm
713 self.thismask = tm
714 self.subs = []
715 self.base = None
716
717 def str1(self, i):
718 ind = str_indent(i)
719 r = ind + whex(self.fixedmask)
720 if self.format:
721 r += ' ' + self.format.name
722 r += ' [\n'
723 for (b, s) in self.subs:
724 r += ind + f' {whex(b)}:\n'
725 r += s.str1(i + 4) + '\n'
726 r += ind + ']'
727 return r
728
729 def __str__(self):
730 return self.str1(0)
731
732 def output_code(self, i, extracted, outerbits, outermask):
733 ind = str_indent(i)
734
735 # If we identified all nodes below have the same format,
736 # extract the fields now. But don't do it if the format relies
737 # on named fields from the insn pattern, as those won't have
738 # been initialised at this point.
739 if not extracted and self.base and not self.base.dangling_references():
740 output(ind, self.base.extract_name(),
741 '(ctx, &u.f_', self.base.base.name, ', insn);\n')
742 extracted = True
743
744 # Attempt to aid the compiler in producing compact switch statements.
745 # If the bits in the mask are contiguous, extract them.
746 sh = is_contiguous(self.thismask)
747 if sh > 0:
748 # Propagate SH down into the local functions.
749 def str_switch(b, sh=sh):
750 return f'(insn >> {sh}) & {b >> sh:#x}'
751
752 def str_case(b, sh=sh):
753 return hex(b >> sh)
754 else:
755 def str_switch(b):
756 return f'insn & {whexC(b)}'
757
758 def str_case(b):
759 return whexC(b)
760
761 output(ind, 'switch (', str_switch(self.thismask), ') {\n')
762 for b, s in sorted(self.subs):
763 assert (self.thismask & ~s.fixedmask) == 0
764 innermask = outermask | self.thismask
765 innerbits = outerbits | b
766 output(ind, 'case ', str_case(b), ':\n')
767 output(ind, ' /* ',
768 str_match_bits(innerbits, innermask), ' */\n')
769 s.output_code(i + 4, extracted, innerbits, innermask)
770 output(ind, ' break;\n')
771 output(ind, '}\n')
772 # end Tree
773
774
775 class ExcMultiPattern(MultiPattern):
776 """Class representing a non-overlapping set of instruction patterns"""
777
778 def output_code(self, i, extracted, outerbits, outermask):
779 # Defer everything to our decomposed Tree node
780 self.tree.output_code(i, extracted, outerbits, outermask)
781
782 @staticmethod
783 def __build_tree(pats, outerbits, outermask):
784 # Find the intersection of all remaining fixedmask.
785 innermask = ~outermask & insnmask
786 for i in pats:
787 innermask &= i.fixedmask
788
789 if innermask == 0:
790 # Edge condition: One pattern covers the entire insnmask
791 if len(pats) == 1:
792 t = Tree(outermask, innermask)
793 t.subs.append((0, pats[0]))
794 return t
795
796 text = 'overlapping patterns:'
797 for p in pats:
798 text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
799 error_with_file(pats[0].file, pats[0].lineno, text)
800
801 fullmask = outermask | innermask
802
803 # Sort each element of pats into the bin selected by the mask.
804 bins = {}
805 for i in pats:
806 fb = i.fixedbits & innermask
807 if fb in bins:
808 bins[fb].append(i)
809 else:
810 bins[fb] = [i]
811
812 # We must recurse if any bin has more than one element or if
813 # the single element in the bin has not been fully matched.
814 t = Tree(fullmask, innermask)
815
816 for b, l in bins.items():
817 s = l[0]
818 if len(l) > 1 or s.fixedmask & ~fullmask != 0:
819 s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
820 t.subs.append((b, s))
821
822 return t
823
824 def build_tree(self):
825 super().build_tree()
826 self.tree = self.__build_tree(self.pats, self.fixedbits,
827 self.fixedmask)
828
829 @staticmethod
830 def __prop_format(tree):
831 """Propagate Format objects into the decode tree"""
832
833 # Depth first search.
834 for (b, s) in tree.subs:
835 if isinstance(s, Tree):
836 ExcMultiPattern.__prop_format(s)
837
838 # If all entries in SUBS have the same format, then
839 # propagate that into the tree.
840 f = None
841 for (b, s) in tree.subs:
842 if f is None:
843 f = s.base
844 if f is None:
845 return
846 if f is not s.base:
847 return
848 tree.base = f
849
850 def prop_format(self):
851 super().prop_format()
852 self.__prop_format(self.tree)
853
854 # end ExcMultiPattern
855
856
857 def parse_field(lineno, name, toks):
858 """Parse one instruction field from TOKS at LINENO"""
859 global fields
860 global insnwidth
861 global re_C_ident
862
863 # A "simple" field will have only one entry;
864 # a "multifield" will have several.
865 subs = []
866 width = 0
867 func = None
868 for t in toks:
869 if re.match('^!function=', t):
870 if func:
871 error(lineno, 'duplicate function')
872 func = t.split('=')
873 func = func[1]
874 continue
875
876 if re.fullmatch(re_C_ident + ':s[0-9]+', t):
877 # Signed named field
878 subtoks = t.split(':')
879 n = subtoks[0]
880 le = int(subtoks[1])
881 f = NamedField(n, True, le)
882 subs.append(f)
883 width += le
884 continue
885 if re.fullmatch(re_C_ident + ':[0-9]+', t):
886 # Unsigned named field
887 subtoks = t.split(':')
888 n = subtoks[0]
889 le = int(subtoks[1])
890 f = NamedField(n, False, le)
891 subs.append(f)
892 width += le
893 continue
894
895 if re.fullmatch('[0-9]+:s[0-9]+', t):
896 # Signed field extract
897 subtoks = t.split(':s')
898 sign = True
899 elif re.fullmatch('[0-9]+:[0-9]+', t):
900 # Unsigned field extract
901 subtoks = t.split(':')
902 sign = False
903 else:
904 error(lineno, f'invalid field token "{t}"')
905 po = int(subtoks[0])
906 le = int(subtoks[1])
907 if po + le > insnwidth:
908 error(lineno, f'field {t} too large')
909 f = Field(sign, po, le)
910 subs.append(f)
911 width += le
912
913 if width > insnwidth:
914 error(lineno, 'field too large')
915 if len(subs) == 0:
916 if func:
917 f = ParameterField(func)
918 else:
919 error(lineno, 'field with no value')
920 else:
921 if len(subs) == 1:
922 f = subs[0]
923 else:
924 mask = 0
925 for s in subs:
926 if mask & s.mask:
927 error(lineno, 'field components overlap')
928 mask |= s.mask
929 f = MultiField(subs, mask)
930 if func:
931 f = FunctionField(func, f)
932
933 if name in fields:
934 error(lineno, 'duplicate field', name)
935 fields[name] = f
936 # end parse_field
937
938
939 def parse_arguments(lineno, name, toks):
940 """Parse one argument set from TOKS at LINENO"""
941 global arguments
942 global re_C_ident
943 global anyextern
944
945 flds = []
946 types = []
947 extern = False
948 for n in toks:
949 if re.fullmatch('!extern', n):
950 extern = True
951 anyextern = True
952 continue
953 if re.fullmatch(re_C_ident + ':' + re_C_ident, n):
954 (n, t) = n.split(':')
955 elif re.fullmatch(re_C_ident, n):
956 t = 'int'
957 else:
958 error(lineno, f'invalid argument set token "{n}"')
959 if n in flds:
960 error(lineno, f'duplicate argument "{n}"')
961 flds.append(n)
962 types.append(t)
963
964 if name in arguments:
965 error(lineno, 'duplicate argument set', name)
966 arguments[name] = Arguments(name, flds, types, extern)
967 # end parse_arguments
968
969
970 def lookup_field(lineno, name):
971 global fields
972 if name in fields:
973 return fields[name]
974 error(lineno, 'undefined field', name)
975
976
977 def add_field(lineno, flds, new_name, f):
978 if new_name in flds:
979 error(lineno, 'duplicate field', new_name)
980 flds[new_name] = f
981 return flds
982
983
984 def add_field_byname(lineno, flds, new_name, old_name):
985 return add_field(lineno, flds, new_name, lookup_field(lineno, old_name))
986
987
988 def infer_argument_set(flds):
989 global arguments
990 global decode_function
991
992 for arg in arguments.values():
993 if eq_fields_for_args(flds, arg):
994 return arg
995
996 name = decode_function + str(len(arguments))
997 arg = Arguments(name, flds.keys(), ['int'] * len(flds), False)
998 arguments[name] = arg
999 return arg
1000
1001
1002 def infer_format(arg, fieldmask, flds, width):
1003 global arguments
1004 global formats
1005 global decode_function
1006
1007 const_flds = {}
1008 var_flds = {}
1009 for n, c in flds.items():
1010 if c is ConstField:
1011 const_flds[n] = c
1012 else:
1013 var_flds[n] = c
1014
1015 # Look for an existing format with the same argument set and fields
1016 for fmt in formats.values():
1017 if arg and fmt.base != arg:
1018 continue
1019 if fieldmask != fmt.fieldmask:
1020 continue
1021 if width != fmt.width:
1022 continue
1023 if not eq_fields_for_fmts(flds, fmt.fields):
1024 continue
1025 return (fmt, const_flds)
1026
1027 name = decode_function + '_Fmt_' + str(len(formats))
1028 if not arg:
1029 arg = infer_argument_set(flds)
1030
1031 fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
1032 formats[name] = fmt
1033
1034 return (fmt, const_flds)
1035 # end infer_format
1036
1037
1038 def parse_generic(lineno, parent_pat, name, toks):
1039 """Parse one instruction format from TOKS at LINENO"""
1040 global fields
1041 global arguments
1042 global formats
1043 global allpatterns
1044 global re_arg_ident
1045 global re_fld_ident
1046 global re_fmt_ident
1047 global re_C_ident
1048 global insnwidth
1049 global insnmask
1050 global variablewidth
1051
1052 is_format = parent_pat is None
1053
1054 fixedmask = 0
1055 fixedbits = 0
1056 undefmask = 0
1057 width = 0
1058 flds = {}
1059 arg = None
1060 fmt = None
1061 for t in toks:
1062 # '&Foo' gives a format an explicit argument set.
1063 if re.fullmatch(re_arg_ident, t):
1064 tt = t[1:]
1065 if arg:
1066 error(lineno, 'multiple argument sets')
1067 if tt in arguments:
1068 arg = arguments[tt]
1069 else:
1070 error(lineno, 'undefined argument set', t)
1071 continue
1072
1073 # '@Foo' gives a pattern an explicit format.
1074 if re.fullmatch(re_fmt_ident, t):
1075 tt = t[1:]
1076 if fmt:
1077 error(lineno, 'multiple formats')
1078 if tt in formats:
1079 fmt = formats[tt]
1080 else:
1081 error(lineno, 'undefined format', t)
1082 continue
1083
1084 # '%Foo' imports a field.
1085 if re.fullmatch(re_fld_ident, t):
1086 tt = t[1:]
1087 flds = add_field_byname(lineno, flds, tt, tt)
1088 continue
1089
1090 # 'Foo=%Bar' imports a field with a different name.
1091 if re.fullmatch(re_C_ident + '=' + re_fld_ident, t):
1092 (fname, iname) = t.split('=%')
1093 flds = add_field_byname(lineno, flds, fname, iname)
1094 continue
1095
1096 # 'Foo=number' sets an argument field to a constant value
1097 if re.fullmatch(re_C_ident + '=[+-]?[0-9]+', t):
1098 (fname, value) = t.split('=')
1099 value = int(value)
1100 flds = add_field(lineno, flds, fname, ConstField(value))
1101 continue
1102
1103 # Pattern of 0s, 1s, dots and dashes indicate required zeros,
1104 # required ones, or dont-cares.
1105 if re.fullmatch('[01.-]+', t):
1106 shift = len(t)
1107 fms = t.replace('0', '1')
1108 fms = fms.replace('.', '0')
1109 fms = fms.replace('-', '0')
1110 fbs = t.replace('.', '0')
1111 fbs = fbs.replace('-', '0')
1112 ubm = t.replace('1', '0')
1113 ubm = ubm.replace('.', '0')
1114 ubm = ubm.replace('-', '1')
1115 fms = int(fms, 2)
1116 fbs = int(fbs, 2)
1117 ubm = int(ubm, 2)
1118 fixedbits = (fixedbits << shift) | fbs
1119 fixedmask = (fixedmask << shift) | fms
1120 undefmask = (undefmask << shift) | ubm
1121 # Otherwise, fieldname:fieldwidth
1122 elif re.fullmatch(re_C_ident + ':s?[0-9]+', t):
1123 (fname, flen) = t.split(':')
1124 sign = False
1125 if flen[0] == 's':
1126 sign = True
1127 flen = flen[1:]
1128 shift = int(flen, 10)
1129 if shift + width > insnwidth:
1130 error(lineno, f'field {fname} exceeds insnwidth')
1131 f = Field(sign, insnwidth - width - shift, shift)
1132 flds = add_field(lineno, flds, fname, f)
1133 fixedbits <<= shift
1134 fixedmask <<= shift
1135 undefmask <<= shift
1136 else:
1137 error(lineno, f'invalid token "{t}"')
1138 width += shift
1139
1140 if variablewidth and width < insnwidth and width % 8 == 0:
1141 shift = insnwidth - width
1142 fixedbits <<= shift
1143 fixedmask <<= shift
1144 undefmask <<= shift
1145 undefmask |= (1 << shift) - 1
1146
1147 # We should have filled in all of the bits of the instruction.
1148 elif not (is_format and width == 0) and width != insnwidth:
1149 error(lineno, f'definition has {width} bits')
1150
1151 # Do not check for fields overlapping fields; one valid usage
1152 # is to be able to duplicate fields via import.
1153 fieldmask = 0
1154 for f in flds.values():
1155 fieldmask |= f.mask
1156
1157 # Fix up what we've parsed to match either a format or a pattern.
1158 if is_format:
1159 # Formats cannot reference formats.
1160 if fmt:
1161 error(lineno, 'format referencing format')
1162 # If an argument set is given, then there should be no fields
1163 # without a place to store it.
1164 if arg:
1165 for f in flds.keys():
1166 if f not in arg.fields:
1167 error(lineno, f'field {f} not in argument set {arg.name}')
1168 else:
1169 arg = infer_argument_set(flds)
1170 if name in formats:
1171 error(lineno, 'duplicate format name', name)
1172 fmt = Format(name, lineno, arg, fixedbits, fixedmask,
1173 undefmask, fieldmask, flds, width)
1174 formats[name] = fmt
1175 else:
1176 # Patterns can reference a format ...
1177 if fmt:
1178 # ... but not an argument simultaneously
1179 if arg:
1180 error(lineno, 'pattern specifies both format and argument set')
1181 if fixedmask & fmt.fixedmask:
1182 error(lineno, 'pattern fixed bits overlap format fixed bits')
1183 if width != fmt.width:
1184 error(lineno, 'pattern uses format of different width')
1185 fieldmask |= fmt.fieldmask
1186 fixedbits |= fmt.fixedbits
1187 fixedmask |= fmt.fixedmask
1188 undefmask |= fmt.undefmask
1189 else:
1190 (fmt, flds) = infer_format(arg, fieldmask, flds, width)
1191 arg = fmt.base
1192 for f in flds.keys():
1193 if f not in arg.fields:
1194 error(lineno, f'field {f} not in argument set {arg.name}')
1195 if f in fmt.fields.keys():
1196 error(lineno, f'field {f} set by format and pattern')
1197 for f in arg.fields:
1198 if f not in flds.keys() and f not in fmt.fields.keys():
1199 error(lineno, f'field {f} not initialized')
1200 pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
1201 undefmask, fieldmask, flds, width)
1202 parent_pat.pats.append(pat)
1203 allpatterns.append(pat)
1204
1205 # Validate the masks that we have assembled.
1206 if fieldmask & fixedmask:
1207 error(lineno, 'fieldmask overlaps fixedmask ',
1208 f'({whex(fieldmask)} & {whex(fixedmask)})')
1209 if fieldmask & undefmask:
1210 error(lineno, 'fieldmask overlaps undefmask ',
1211 f'({whex(fieldmask)} & {whex(undefmask)})')
1212 if fixedmask & undefmask:
1213 error(lineno, 'fixedmask overlaps undefmask ',
1214 f'({whex(fixedmask)} & {whex(undefmask)})')
1215 if not is_format:
1216 allbits = fieldmask | fixedmask | undefmask
1217 if allbits != insnmask:
1218 error(lineno, 'bits left unspecified ',
1219 f'({whex(allbits ^ insnmask)})')
1220 # end parse_general
1221
1222
1223 def parse_file(f, parent_pat):
1224 """Parse all of the patterns within a file"""
1225 global re_arg_ident
1226 global re_fld_ident
1227 global re_fmt_ident
1228 global re_pat_ident
1229
1230 # Read all of the lines of the file. Concatenate lines
1231 # ending in backslash; discard empty lines and comments.
1232 toks = []
1233 lineno = 0
1234 nesting = 0
1235 nesting_pats = []
1236
1237 for line in f:
1238 lineno += 1
1239
1240 # Expand and strip spaces, to find indent.
1241 line = line.rstrip()
1242 line = line.expandtabs()
1243 len1 = len(line)
1244 line = line.lstrip()
1245 len2 = len(line)
1246
1247 # Discard comments
1248 end = line.find('#')
1249 if end >= 0:
1250 line = line[:end]
1251
1252 t = line.split()
1253 if len(toks) != 0:
1254 # Next line after continuation
1255 toks.extend(t)
1256 else:
1257 # Allow completely blank lines.
1258 if len1 == 0:
1259 continue
1260 indent = len1 - len2
1261 # Empty line due to comment.
1262 if len(t) == 0:
1263 # Indentation must be correct, even for comment lines.
1264 if indent != nesting:
1265 error(lineno, 'indentation ', indent, ' != ', nesting)
1266 continue
1267 start_lineno = lineno
1268 toks = t
1269
1270 # Continuation?
1271 if toks[-1] == '\\':
1272 toks.pop()
1273 continue
1274
1275 name = toks[0]
1276 del toks[0]
1277
1278 # End nesting?
1279 if name == '}' or name == ']':
1280 if len(toks) != 0:
1281 error(start_lineno, 'extra tokens after close brace')
1282
1283 # Make sure { } and [ ] nest properly.
1284 if (name == '}') != isinstance(parent_pat, IncMultiPattern):
1285 error(lineno, 'mismatched close brace')
1286
1287 try:
1288 parent_pat = nesting_pats.pop()
1289 except:
1290 error(lineno, 'extra close brace')
1291
1292 nesting -= 2
1293 if indent != nesting:
1294 error(lineno, 'indentation ', indent, ' != ', nesting)
1295
1296 toks = []
1297 continue
1298
1299 # Everything else should have current indentation.
1300 if indent != nesting:
1301 error(start_lineno, 'indentation ', indent, ' != ', nesting)
1302
1303 # Start nesting?
1304 if name == '{' or name == '[':
1305 if len(toks) != 0:
1306 error(start_lineno, 'extra tokens after open brace')
1307
1308 if name == '{':
1309 nested_pat = IncMultiPattern(start_lineno)
1310 else:
1311 nested_pat = ExcMultiPattern(start_lineno)
1312 parent_pat.pats.append(nested_pat)
1313 nesting_pats.append(parent_pat)
1314 parent_pat = nested_pat
1315
1316 nesting += 2
1317 toks = []
1318 continue
1319
1320 # Determine the type of object needing to be parsed.
1321 if re.fullmatch(re_fld_ident, name):
1322 parse_field(start_lineno, name[1:], toks)
1323 elif re.fullmatch(re_arg_ident, name):
1324 parse_arguments(start_lineno, name[1:], toks)
1325 elif re.fullmatch(re_fmt_ident, name):
1326 parse_generic(start_lineno, None, name[1:], toks)
1327 elif re.fullmatch(re_pat_ident, name):
1328 parse_generic(start_lineno, parent_pat, name, toks)
1329 else:
1330 error(lineno, f'invalid token "{name}"')
1331 toks = []
1332
1333 if nesting != 0:
1334 error(lineno, 'missing close brace')
1335 # end parse_file
1336
1337
1338 class SizeTree:
1339 """Class representing a node in a size decode tree"""
1340
1341 def __init__(self, m, w):
1342 self.mask = m
1343 self.subs = []
1344 self.base = None
1345 self.width = w
1346
1347 def str1(self, i):
1348 ind = str_indent(i)
1349 r = ind + whex(self.mask) + ' [\n'
1350 for (b, s) in self.subs:
1351 r += ind + f' {whex(b)}:\n'
1352 r += s.str1(i + 4) + '\n'
1353 r += ind + ']'
1354 return r
1355
1356 def __str__(self):
1357 return self.str1(0)
1358
1359 def output_code(self, i, extracted, outerbits, outermask):
1360 ind = str_indent(i)
1361
1362 # If we need to load more bytes to test, do so now.
1363 if extracted < self.width:
1364 output(ind, f'insn = {decode_function}_load_bytes',
1365 f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
1366 extracted = self.width
1367
1368 # Attempt to aid the compiler in producing compact switch statements.
1369 # If the bits in the mask are contiguous, extract them.
1370 sh = is_contiguous(self.mask)
1371 if sh > 0:
1372 # Propagate SH down into the local functions.
1373 def str_switch(b, sh=sh):
1374 return f'(insn >> {sh}) & {b >> sh:#x}'
1375
1376 def str_case(b, sh=sh):
1377 return hex(b >> sh)
1378 else:
1379 def str_switch(b):
1380 return f'insn & {whexC(b)}'
1381
1382 def str_case(b):
1383 return whexC(b)
1384
1385 output(ind, 'switch (', str_switch(self.mask), ') {\n')
1386 for b, s in sorted(self.subs):
1387 innermask = outermask | self.mask
1388 innerbits = outerbits | b
1389 output(ind, 'case ', str_case(b), ':\n')
1390 output(ind, ' /* ',
1391 str_match_bits(innerbits, innermask), ' */\n')
1392 s.output_code(i + 4, extracted, innerbits, innermask)
1393 output(ind, '}\n')
1394 output(ind, 'return insn;\n')
1395 # end SizeTree
1396
1397 class SizeLeaf:
1398 """Class representing a leaf node in a size decode tree"""
1399
1400 def __init__(self, m, w):
1401 self.mask = m
1402 self.width = w
1403
1404 def str1(self, i):
1405 return str_indent(i) + whex(self.mask)
1406
1407 def __str__(self):
1408 return self.str1(0)
1409
1410 def output_code(self, i, extracted, outerbits, outermask):
1411 global decode_function
1412 ind = str_indent(i)
1413
1414 # If we need to load more bytes, do so now.
1415 if extracted < self.width:
1416 output(ind, f'insn = {decode_function}_load_bytes',
1417 f'(ctx, insn, {extracted // 8}, {self.width // 8});\n')
1418 extracted = self.width
1419 output(ind, 'return insn;\n')
1420 # end SizeLeaf
1421
1422
1423 def build_size_tree(pats, width, outerbits, outermask):
1424 global insnwidth
1425
1426 # Collect the mask of bits that are fixed in this width
1427 innermask = 0xff << (insnwidth - width)
1428 innermask &= ~outermask
1429 minwidth = None
1430 onewidth = True
1431 for i in pats:
1432 innermask &= i.fixedmask
1433 if minwidth is None:
1434 minwidth = i.width
1435 elif minwidth != i.width:
1436 onewidth = False;
1437 if minwidth < i.width:
1438 minwidth = i.width
1439
1440 if onewidth:
1441 return SizeLeaf(innermask, minwidth)
1442
1443 if innermask == 0:
1444 if width < minwidth:
1445 return build_size_tree(pats, width + 8, outerbits, outermask)
1446
1447 pnames = []
1448 for p in pats:
1449 pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
1450 error_with_file(pats[0].file, pats[0].lineno,
1451 f'overlapping patterns size {width}:', pnames)
1452
1453 bins = {}
1454 for i in pats:
1455 fb = i.fixedbits & innermask
1456 if fb in bins:
1457 bins[fb].append(i)
1458 else:
1459 bins[fb] = [i]
1460
1461 fullmask = outermask | innermask
1462 lens = sorted(bins.keys())
1463 if len(lens) == 1:
1464 b = lens[0]
1465 return build_size_tree(bins[b], width + 8, b | outerbits, fullmask)
1466
1467 r = SizeTree(innermask, width)
1468 for b, l in bins.items():
1469 s = build_size_tree(l, width, b | outerbits, fullmask)
1470 r.subs.append((b, s))
1471 return r
1472 # end build_size_tree
1473
1474
1475 def prop_size(tree):
1476 """Propagate minimum widths up the decode size tree"""
1477
1478 if isinstance(tree, SizeTree):
1479 min = None
1480 for (b, s) in tree.subs:
1481 width = prop_size(s)
1482 if min is None or min > width:
1483 min = width
1484 assert min >= tree.width
1485 tree.width = min
1486 else:
1487 min = tree.width
1488 return min
1489 # end prop_size
1490
1491
1492 def main():
1493 global arguments
1494 global formats
1495 global allpatterns
1496 global translate_scope
1497 global translate_prefix
1498 global output_fd
1499 global output_file
1500 global output_null
1501 global input_file
1502 global insnwidth
1503 global insntype
1504 global insnmask
1505 global decode_function
1506 global bitop_width
1507 global variablewidth
1508 global anyextern
1509 global testforerror
1510
1511 decode_scope = 'static '
1512
1513 long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
1514 'static-decode=', 'varinsnwidth=', 'test-for-error',
1515 'output-null']
1516 try:
1517 (opts, args) = getopt.gnu_getopt(sys.argv[1:], 'o:vw:', long_opts)
1518 except getopt.GetoptError as err:
1519 error(0, err)
1520 for o, a in opts:
1521 if o in ('-o', '--output'):
1522 output_file = a
1523 elif o == '--decode':
1524 decode_function = a
1525 decode_scope = ''
1526 elif o == '--static-decode':
1527 decode_function = a
1528 elif o == '--translate':
1529 translate_prefix = a
1530 translate_scope = ''
1531 elif o in ('-w', '--insnwidth', '--varinsnwidth'):
1532 if o == '--varinsnwidth':
1533 variablewidth = True
1534 insnwidth = int(a)
1535 if insnwidth == 16:
1536 insntype = 'uint16_t'
1537 insnmask = 0xffff
1538 elif insnwidth == 64:
1539 insntype = 'uint64_t'
1540 insnmask = 0xffffffffffffffff
1541 bitop_width = 64
1542 elif insnwidth != 32:
1543 error(0, 'cannot handle insns of width', insnwidth)
1544 elif o == '--test-for-error':
1545 testforerror = True
1546 elif o == '--output-null':
1547 output_null = True
1548 else:
1549 assert False, 'unhandled option'
1550
1551 if len(args) < 1:
1552 error(0, 'missing input file')
1553
1554 toppat = ExcMultiPattern(0)
1555
1556 for filename in args:
1557 input_file = filename
1558 f = open(filename, 'rt', encoding='utf-8')
1559 parse_file(f, toppat)
1560 f.close()
1561
1562 # We do not want to compute masks for toppat, because those masks
1563 # are used as a starting point for build_tree. For toppat, we must
1564 # insist that decode begins from naught.
1565 for i in toppat.pats:
1566 i.prop_masks()
1567
1568 toppat.build_tree()
1569 toppat.prop_format()
1570
1571 if variablewidth:
1572 for i in toppat.pats:
1573 i.prop_width()
1574 stree = build_size_tree(toppat.pats, 8, 0, 0)
1575 prop_size(stree)
1576
1577 if output_null:
1578 output_fd = open(os.devnull, 'wt', encoding='utf-8', errors="ignore")
1579 elif output_file:
1580 output_fd = open(output_file, 'wt', encoding='utf-8')
1581 else:
1582 output_fd = io.TextIOWrapper(sys.stdout.buffer,
1583 encoding=sys.stdout.encoding,
1584 errors="ignore")
1585
1586 output_autogen()
1587 for n in sorted(arguments.keys()):
1588 f = arguments[n]
1589 f.output_def()
1590
1591 # A single translate function can be invoked for different patterns.
1592 # Make sure that the argument sets are the same, and declare the
1593 # function only once.
1594 #
1595 # If we're sharing formats, we're likely also sharing trans_* functions,
1596 # but we can't tell which ones. Prevent issues from the compiler by
1597 # suppressing redundant declaration warnings.
1598 if anyextern:
1599 output("#pragma GCC diagnostic push\n",
1600 "#pragma GCC diagnostic ignored \"-Wredundant-decls\"\n",
1601 "#ifdef __clang__\n"
1602 "# pragma GCC diagnostic ignored \"-Wtypedef-redefinition\"\n",
1603 "#endif\n\n")
1604
1605 out_pats = {}
1606 for i in allpatterns:
1607 if i.name in out_pats:
1608 p = out_pats[i.name]
1609 if i.base.base != p.base.base:
1610 error(0, i.name, ' has conflicting argument sets')
1611 else:
1612 i.output_decl()
1613 out_pats[i.name] = i
1614 output('\n')
1615
1616 if anyextern:
1617 output("#pragma GCC diagnostic pop\n\n")
1618
1619 for n in sorted(formats.keys()):
1620 f = formats[n]
1621 f.output_extract()
1622
1623 output(decode_scope, 'bool ', decode_function,
1624 '(DisasContext *ctx, ', insntype, ' insn)\n{\n')
1625
1626 i4 = str_indent(4)
1627
1628 if len(allpatterns) != 0:
1629 output(i4, 'union {\n')
1630 for n in sorted(arguments.keys()):
1631 f = arguments[n]
1632 output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
1633 output(i4, '} u;\n\n')
1634 toppat.output_code(4, False, 0, 0)
1635
1636 output(i4, 'return false;\n')
1637 output('}\n')
1638
1639 if variablewidth:
1640 output('\n', decode_scope, insntype, ' ', decode_function,
1641 '_load(DisasContext *ctx)\n{\n',
1642 ' ', insntype, ' insn = 0;\n\n')
1643 stree.output_code(4, 0, 0, 0)
1644 output('}\n')
1645
1646 if output_file:
1647 output_fd.close()
1648 exit(1 if testforerror else 0)
1649 # end main
1650
1651
1652 if __name__ == '__main__':
1653 main()