2 import argparse
as _argparse
3 import collections
as _collections
4 import dataclasses
as _dataclasses
6 import functools
as _functools
7 import operator
as _operator
9 from openpower
.decoder
.power_enums
import (
15 CROutSel
as _CROutSel
,
20 Function
as _Function
,
21 find_wiki_dir
as _find_wiki_dir
,
23 from openpower
.consts
import SVP64MODE
as _SVP64MODE
24 from openpower
.decoder
.power_insn
import Database
as _Database
25 from openpower
.decoder
.isa
.caller
import SVP64RMFields
as _SVP64RMFields
26 from openpower
.decoder
.isa
.caller
import SVP64PrefixFields
as _SVP64PrefixFields
27 from openpower
.decoder
.selectable_int
import SelectableIntMapping
32 Copyright (C) 2022 Free Software Foundation, Inc.
33 Written by Dmitry Selyutin (ghostmansd).
34 Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073.
36 This file is part of the GNU opcodes library.
38 This library is free software; you can redistribute it and/or modify
39 it under the terms of the GNU General Public License as published by
40 the Free Software Foundation; either version 3, or (at your option)
43 It is distributed in the hope that it will be useful, but WITHOUT
44 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
45 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
46 License for more details.
48 You should have received a copy of the GNU General Public License
49 along with this file; see the file COPYING. If not, write to the
50 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
51 MA 02110-1301, USA. */\
56 return map(lambda string
: (" " + string
), strings
)
59 class CTypeMeta(type):
60 def __new__(metacls
, name
, bases
, attrs
, typedef
="void"):
61 cls
= super().__new
__(metacls
, name
, bases
, attrs
)
64 if (hasattr(base
, "c_typedef") and
65 (base
.c_typedef
!= "void")):
66 typedef
= base
.c_typedef
68 cls
.__typedef
= typedef
72 def __getitem__(cls
, size
):
73 name
= f
"{cls.__name__}[{'' if size is Ellipsis else size}]"
74 return type(name
, (Array
,), {}, type=cls
, size
=size
)
84 def c_var(cls
, name
, prefix
="", suffix
=""):
85 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
88 class ArrayMeta(CTypeMeta
):
89 def __new__(metacls
, name
, bases
, attrs
, type, size
, **kwargs
):
90 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
92 cls
.__ellipsis
= (size
is Ellipsis)
93 cls
.__size
= 0 if cls
.__ellipsis
else size
101 size
= "" if cls
.__ellipsis
else f
"{cls.__size}"
102 yield f
"{cls.__type.c_typedef}[{size}]"
104 def c_var(cls
, name
, prefix
="", suffix
=""):
105 size
= "" if cls
.__ellipsis
else f
"{cls.__size}"
106 return f
"{prefix}{cls.__type.c_typedef} {name}[{size}]{suffix}"
109 class BitmapMeta(CTypeMeta
):
110 def __new__(metacls
, name
, bases
, attrs
,
111 typedef
="uint64_t", bits
=0, **kwargs
):
112 cls
= super().__new
__(metacls
,
113 name
, bases
, attrs
, typedef
=typedef
, **kwargs
)
120 def c_var(cls
, name
, prefix
="", suffix
=""):
121 return f
"{prefix}{cls.c_typedef} {name} : {cls.__bits}{suffix}"
124 class CType(metaclass
=CTypeMeta
):
126 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
130 class Array(CType
, tuple, metaclass
=ArrayMeta
, type=CType
, size
=...):
131 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
133 for (index
, item
) in enumerate(self
):
134 yield from indent(item
.c_value(suffix
=","))
138 class Bitmap(metaclass
=BitmapMeta
):
142 class Void(CType
, typedef
="void"):
143 def c_var(cls
, name
, prefix
="", suffix
=""):
144 raise NotImplementedError
147 class EnumMeta(_enum
.EnumMeta
, CTypeMeta
):
148 def __call__(metacls
, name
, entries
, tag
=None, exclude
=None, **kwargs
):
150 exclude
= frozenset()
151 if isinstance(entries
, type) and issubclass(entries
, _enum
.Enum
):
152 # Use __members__, not __iter__, otherwise aliases are lost.
153 entries
= dict(entries
.__members
__)
154 if isinstance(entries
, dict):
155 entries
= tuple(entries
.items())
156 entries
= ((key
, value
) for (key
, value
) in entries
if key
not in exclude
)
158 tag
= f
"svp64_{name.lower()}"
160 cls
= super().__call
__(value
=name
, names
=entries
, **kwargs
)
167 return f
"enum {cls.c_tag}"
174 yield f
"{cls.c_typedef} {{"
176 yield from indent(item
.c_value(suffix
=","))
179 def c_var(cls
, name
, prefix
="", suffix
=""):
180 return f
"{prefix}{cls.c_typedef} {name}{suffix}"
183 class Enum(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
186 return f
"{self.__class__.c_tag.upper()}_{self.name.upper()}"
188 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
189 yield f
"{prefix}{self.c_name}{suffix}"
192 In1Sel
= Enum("In1Sel", _In1Sel
, tag
="svp64_in1_sel")
193 In2Sel
= Enum("In2Sel", _In2Sel
, tag
="svp64_in2_sel")
194 In3Sel
= Enum("In3Sel", _In3Sel
, tag
="svp64_in3_sel")
195 OutSel
= Enum("OutSel", _OutSel
, tag
="svp64_out_sel")
196 CRInSel
= Enum("CRInSel", _CRInSel
, tag
="svp64_cr_in_sel")
197 CROutSel
= Enum("CROutSel", _CROutSel
, tag
="svp64_cr_out_sel")
198 PType
= Enum("PType", _SVPtype
, tag
="svp64_ptype")
199 EType
= Enum("EType", _SVEtype
, tag
="svp64_etype", exclude
="NONE")
200 Extra
= Enum("Extra", _SVExtra
, tag
="svp64_extra", exclude
="Idx_1_2")
201 Function
= Enum("Function", _Function
, tag
="svp64_function")
204 class Constant(CType
, _enum
.Enum
, metaclass
=EnumMeta
):
207 yield f
"/* {cls.c_tag.upper()} constants */"
208 # Use __members__, not __iter__, otherwise aliases are lost.
209 for (key
, item
) in cls
.__members
__.items():
210 key
= f
"{cls.c_tag.upper()}_{key.upper()}"
211 value
= f
"0x{item.value:08x}U"
212 yield f
"#define {key} {value}"
214 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
215 yield f
"{prefix}{self.__class__.c_tag.upper()}_{self.c_name.upper()}{suffix}"
218 Mode
= Constant("Mode", _SVP64MODE
)
221 class StructMeta(CTypeMeta
):
222 def __new__(metacls
, name
, bases
, attrs
, tag
=None, **kwargs
):
224 tag
= f
"svp64_{name.lower()}"
225 if "typedef" not in kwargs
:
226 kwargs
["typedef"] = f
"struct {tag}"
228 cls
= super().__new
__(metacls
, name
, bases
, attrs
, **kwargs
)
238 def transform(field
):
239 return field
.type.c_var(name
=f
"{field.name}", suffix
=";")
241 yield f
"{cls.c_typedef} {{"
242 yield from indent(map(transform
, _dataclasses
.fields(cls
)))
246 @_dataclasses.dataclass(eq
=True, frozen
=True)
247 class Struct(CType
, metaclass
=StructMeta
):
248 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
250 for field
in _dataclasses
.fields(self
):
252 attr
= getattr(self
, name
)
253 yield from indent(attr
.c_value(prefix
=f
".{name} = ", suffix
=","))
257 class Integer(CType
, str):
258 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
259 yield f
"{prefix}{self}{suffix}"
262 class Byte(Integer
, typedef
="uint8_t"):
266 class Size(Integer
, typedef
="size_t"):
270 class UInt32(Integer
, typedef
="uint32_t"):
274 class Name(CType
, str, typedef
="const char *"):
276 escaped
= self
.replace("\"", "\\\"")
277 return f
"\"{escaped}\""
279 def c_value(self
, *, prefix
="", suffix
="", **kwargs
):
280 yield f
"{prefix}{self!r}{suffix}"
283 def c_var(cls
, name
, prefix
="", suffix
=""):
284 return f
"{prefix}const char *{name}{suffix}"
287 @_dataclasses.dataclass(eq
=True, frozen
=True)
288 class Opcode(Struct
):
290 def __new__(cls
, value
):
291 if isinstance(value
, int):
292 value
= f
"0x{value:08x}"
293 return super().__new
__(cls
, value
)
296 def __new__(cls
, value
):
297 if isinstance(value
, int):
298 value
= f
"0x{value:08x}"
299 return super().__new
__(cls
, value
)
305 @_dataclasses.dataclass(eq
=True, frozen
=True)
328 yield f
"struct svp64_desc {{"
329 for field
in _dataclasses
.fields(cls
):
330 bits
= len(field
.type).bit_length()
331 yield from indent([f
"uint64_t {field.name} : {bits};"])
333 bits_rsvd
= (64 - (bits_all
% 64))
335 yield from indent([f
"uint64_t : {bits_rsvd};"])
339 @_dataclasses.dataclass(eq
=True, frozen
=True)
340 class Record(Struct
):
345 def __lt__(self
, other
):
346 if not isinstance(other
, self
.__class
__):
347 return NotImplemented
349 return self
.name
< other
.name
352 class FunctionMeta(CTypeMeta
):
353 def __new__(metacls
, name
, bases
, attrs
, rv
, args
):
354 cls
= super().__new
__(metacls
, name
, bases
, attrs
)
360 def c_var(cls
, name
, prefix
="", suffix
=""):
361 rv
= cls
.__rv
.c_typedef
362 args
= ", ".join(arg_cls
.c_var(arg_name
) \
363 for (arg_name
, arg_cls
) in cls
.__args
)
364 return f
"{prefix}{rv} {name}({args}){suffix}"
367 class FieldsMappingMeta(EnumMeta
):
368 class HelperMeta(FunctionMeta
):
369 def __new__(metacls
, name
, bases
, attrs
, rv
, args
, enum
):
370 cls
= super().__new
__(metacls
, name
, bases
, attrs
, rv
=rv
, args
=args
)
375 short_c_tag
= cls
.__enum
.c_tag
[:-len("_field")]
376 # Use __members__, not __iter__, otherwise aliases are lost.
377 for (name
, value
) in cls
.__enum
.__members
__.items():
378 yield (f
"{short_c_tag}_{name}".upper(), value
)
380 class GetterMeta(HelperMeta
):
381 def __new__(metacls
, name
, bases
, attrs
, enum
, struct
):
382 return super().__new
__(metacls
, name
, bases
, attrs
,
383 enum
=enum
, rv
=UInt32
, args
=(
388 class SetterMeta(HelperMeta
):
389 def __new__(metacls
, name
, bases
, attrs
, enum
, struct
):
390 return super().__new
__(metacls
, name
, bases
, attrs
, enum
=enum
,
392 ("*storage", struct
),
397 def __call__(metacls
, name
, base
=SelectableIntMapping
, **kwargs
):
398 def flatten(mapping
, parent
=""):
399 for (key
, value
) in mapping
.items():
400 key
= f
"{parent}_{key}" if parent
else key
401 if isinstance(value
, dict):
402 yield from flatten(mapping
=value
, parent
=key
)
404 value
= map(lambda bit
: bit
, reversed(value
))
405 yield (key
.upper(), tuple(value
))
407 tag
= f
"svp64_{name.lower()}"
408 entries
= dict(flatten(mapping
=dict(base
)))
409 bitmap
= type(name
, (Bitmap
,), {}, typedef
="uint32_t", bits
=base
.bits
)
410 struct
= _dataclasses
.make_dataclass(name
, (("value", bitmap
),),
411 bases
=(Struct
,), frozen
=True, eq
=True)
413 cls
= super().__call
__(name
=name
,
414 entries
=entries
, tag
=f
"{tag}_field", **kwargs
)
416 def c_value(entries
, stmt
):
417 yield "switch (field) {"
418 for (field_name
, field_value
) in entries
:
419 yield from indent([f
"case {field_name}:"])
420 yield from indent(indent(map(stmt
,
421 enumerate(field_value
.value
))))
422 yield from indent(indent(["break;"]))
425 class Getter(metaclass
=FieldsMappingMeta
.GetterMeta
,
426 enum
=cls
, struct
=struct
):
427 def c_value(self
, prefix
="", suffix
=""):
430 UInt32
.c_var(name
="result", suffix
=" = UINT32_C(0);"),
431 UInt32
.c_var(name
="origin", suffix
=" = storage.value;"),
434 yield from indent(c_value(entries
=self
.__class
__,
435 stmt
=lambda kv
: f
"result |= SVP64_FIELD_GET(origin, {kv[1]}, {kv[0]});"))
437 yield from indent(["return result;"])
440 class Setter(metaclass
=FieldsMappingMeta
.SetterMeta
,
441 enum
=cls
, struct
=struct
):
442 def c_value(self
, prefix
="", suffix
=""):
445 UInt32
.c_var(name
="result", suffix
=" = storage->value;"),
448 yield from indent(c_value(entries
=self
.__class
__,
449 stmt
=lambda kv
: f
"SVP64_FIELD_SET(&result, value, {kv[0]}, {kv[1]});"))
451 yield from indent(["storage->value = result;"])
455 cls
.__struct
= struct
456 cls
.__getter
= Getter()
457 cls
.__setter
= Setter()
470 yield f
"{cls.c_typedef} {{"
471 for field_name
in cls
.__members
__.keys():
472 short_c_tag
= cls
.c_tag
[:-len("_field")]
473 yield from indent([f
"{short_c_tag}_{field_name},".upper()])
475 yield from cls
.__struct
.c_decl()
476 yield cls
.__getter
.__class
__.c_var(name
=f
"{cls.__tag}_get", suffix
=";")
477 yield cls
.__setter
.__class
__.c_var(name
=f
"{cls.__tag}_set", suffix
=";")
480 class FieldsMapping(Enum
, metaclass
=FieldsMappingMeta
):
483 short_c_tag
= self
.__class
__.c_tag
[:-len("_field")]
484 return f
"{short_c_tag}_{self.name}".upper()
487 Prefix
= FieldsMapping("Prefix", base
=_SVP64PrefixFields
)
488 RM
= FieldsMapping("RM", base
=_SVP64RMFields
)
491 class Codegen(_enum
.Enum
):
492 PPC_SVP64_GEN_H
= _enum
.auto()
493 PPC_SVP64_OPC_GEN_C
= _enum
.auto()
496 def _missing_(cls
, value
):
498 "ppc-svp64-gen.h": Codegen
.PPC_SVP64_GEN_H
,
499 "ppc-svp64-opc-gen.c": Codegen
.PPC_SVP64_OPC_GEN_C
,
504 Codegen
.PPC_SVP64_GEN_H
: "ppc-svp64-gen.h",
505 Codegen
.PPC_SVP64_OPC_GEN_C
: "ppc-svp64-opc-gen.c",
508 def generate(self
, records
):
509 def ppc_svp64_h(records
, num_records
):
510 disclaimer
= DISCLAIMER
.format(path
=str(self
),
511 desc
="Header file for PowerPC opcode table (SVP64 extensions)")
512 yield from disclaimer
.splitlines()
515 yield f
"#ifndef {self.name}"
516 yield f
"#define {self.name}"
519 yield "#include <stdint.h>"
522 yield "#ifdef __cplusplus"
523 yield "extern \"C\" {"
528 In1Sel
, In2Sel
, In3Sel
, OutSel
,
534 yield from enum
.c_decl()
537 for cls
in (Desc
, Opcode
, Record
, Prefix
, RM
):
538 yield from cls
.c_decl()
541 yield records
.__class
__.c_var("svp64_records",
542 prefix
="extern const ", suffix
=";")
543 yield num_records
.__class
__.c_var("svp64_num_records",
544 prefix
="extern const ", suffix
=";")
547 yield "extern const struct powerpc_pd_reg svp64_regs[];"
548 yield Size
.c_var("svp64_num_regs", prefix
="extern const ", suffix
=";")
551 yield "#ifdef __cplusplus"
556 yield f
"#endif /* {self.name} */"
559 def ppc_svp64_opc_c(records
, num_records
):
560 disclaimer
= DISCLAIMER
.format(path
=str(self
),
561 desc
="PowerPC opcode list (SVP64 extensions)")
562 yield from disclaimer
.splitlines()
565 yield "#include \"opcode/ppc-svp64.h\""
568 def opindex(enum
, name
, table
):
569 sep
= (max(map(len, list(table
.values()) + ["UNUSED"])) + 1)
570 c_tag
= f
"svp64_{enum.__name__.lower()}"
571 yield "static inline ppc_opindex_t"
572 yield f
"svp64_desc_{name}_opindex(const struct svp64_desc *desc)"
574 yield from indent(["static const ppc_opindex_t table[] = {"])
576 value
= table
.get(key
, "UNUSED")
577 yield from indent(indent([f
"{value:{sep}}, /* {key.c_name} */"]))
578 yield from indent(["};"])
580 yield from indent([f
"return table[desc->{name}];"])
584 yield from opindex(In1Sel
, "in1", {
586 In1Sel
.RA_OR_ZERO
: "RA0",
592 yield from opindex(In2Sel
, "in2", {
598 yield from opindex(In3Sel
, "in3", {
606 for name
in ("out", "out2"):
607 yield from opindex(OutSel
, name
, {
611 OutSel
.RT_OR_ZERO
: "RT",
615 yield from opindex(CRInSel
, "cr_in", {
619 CRInSel
.WHOLE_REG
: "FXM",
621 yield from opindex(CROutSel
, "cr_out", {
624 CROutSel
.WHOLE_REG
: "FXM",
627 yield records
.__class
__.c_var("svp64_records",
628 prefix
="const ", suffix
=" = \\")
629 yield from records
.c_value(prefix
="", suffix
=";")
631 yield num_records
.__class
__.c_var("svp64_num_records",
632 prefix
="const ", suffix
=" = \\")
633 yield from indent(num_records
.c_value(suffix
=";"))
636 bit_shl
= lambda val
, pos
: f
"({val} << UINT32_C({pos}))"
637 bit_shr
= lambda val
, pos
: f
"({val} >> UINT32_C({pos}))"
638 bit_get
= lambda val
, pos
: f
"({bit_shr(val, pos)} & UINT32_C(1))"
639 bit_or
= lambda lhs
, rhs
: f
"({lhs} | {rhs})"
640 bit_and
= lambda lhs
, rhs
: f
"({lhs} & {rhs})"
641 bit_not
= lambda val
: f
"~({val})"
647 bit_and("VALUE", bit_not(bit_shl("UINT32_C(1)", "BIT"))),
651 ("VALUE", "SRC", "DST"),
652 bit_shl(bit_get("VALUE", "SRC"), "DST"),
656 ("ORIGIN", "SRC", "DST"),
657 "SVP64_FIELD_REMAP(ORIGIN, SRC, DST)",
661 ("RESULT", "VALUE", "SRC", "DST"),
662 ("do { (*RESULT) = " + bit_or(
663 lhs
="SVP64_FIELD_CLEAR(*(RESULT), DST)",
664 rhs
="SVP64_FIELD_REMAP(VALUE, SRC, DST)",
665 ) + "; } while (0)"),
668 for (name
, args
, body
) in macros
:
669 yield f
"#define {name}({', '.join(args)}) \\"
670 yield from indent([body
])
673 for cls
in (Prefix
, RM
):
678 for (mode
, subcls
) in table
.items():
679 yield subcls
.__class
__.c_var(name
=f
"svp64_{cls.__name__.lower()}_{mode}")
680 yield from subcls
.c_value()
683 for name
in map(_operator
.itemgetter(0), macros
):
684 yield f
"#undef {name}"
687 yield "const struct powerpc_pd_reg svp64_regs[] = {"
689 for (category
, count
, flags
) in sorted((
690 ("r", 128, "PPC_OPERAND_GPR"),
691 ("f", 128, "PPC_OPERAND_FPR"),
692 ("cr", 128, "PPC_OPERAND_CR_REG"),
694 for index
in range(count
):
695 regs
[f
"{category}{index}"] = (index
, flags
)
696 regs
[f
"{category}.{index}"] = (index
, flags
)
697 for (name
, (index
, flags
)) in sorted(regs
.items()):
698 yield from indent([f
"{{\"{name}\", {index}, {flags}}},"])
702 num_regs
= Size("(sizeof (svp64_regs) / sizeof (svp64_regs[0]))")
703 yield Size
.c_var("svp64_num_regs",
704 prefix
="const ", suffix
=" = \\")
705 yield from indent(num_regs
.c_value(suffix
=";"))
709 records
= Record
[...](records
)
710 num_records
= Size("(sizeof (svp64_records) / sizeof (svp64_records[0]))")
713 Codegen
.PPC_SVP64_GEN_H
: ppc_svp64_h
,
714 Codegen
.PPC_SVP64_OPC_GEN_C
: ppc_svp64_opc_c
,
715 }[self
](records
, num_records
)
719 fields
= {field
.name
:field
.type for field
in _dataclasses
.fields(Desc
)}
721 for insn
in filter(lambda insn
: insn
.svp64
is not None, db
):
724 for (key
, cls
) in fields
.items():
725 value
= getattr(insn
, key
)
727 if (((cls
is EType
) and (value
is _SVEtype
.NONE
)) or
728 ((cls
is Extra
) and (value
is _SVExtra
.Idx_1_2
))):
732 if issubclass(cls
, _enum
.Enum
):
733 value
= cls
[value
.name
]
741 name
= Name(f
"sv.{insn.name}")
742 value
= Opcode
.Value(insn
.opcode
.value
)
743 mask
= Opcode
.Mask(insn
.opcode
.mask
)
744 opcode
= Opcode(value
=value
, mask
=mask
)
747 yield Record(name
=name
, opcode
=opcode
, desc
=desc
)
751 db
= _Database(_find_wiki_dir())
752 for line
in codegen
.generate(records(db
)):
756 if __name__
== "__main__":
757 parser
= _argparse
.ArgumentParser()
758 parser
.add_argument("codegen",
759 type=Codegen
, choices
=Codegen
,
760 help="code generator")
762 args
= vars(parser
.parse_args())