freedreno/regs: Generate per-gen reg usage tables
authorDanylo Piliaiev <dpiliaiev@igalia.com>
Thu, 20 Apr 2023 15:03:29 +0000 (17:03 +0200)
committerMarge Bot <emma+marge@anholt.net>
Wed, 12 Jul 2023 13:33:28 +0000 (13:33 +0000)
"reg" and "array" now could have `usage="a,b,c"` attribute, for each
usage a separate array is generated.

Would be used for register stomping debug option.

Signed-off-by: Danylo Piliaiev <dpiliaiev@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23881>

src/freedreno/registers/gen_header.py
src/freedreno/registers/rules-ng.xsd
src/freedreno/rnn/rnn.c

index e41618d..8cd5914 100644 (file)
@@ -3,6 +3,7 @@
 import xml.parsers.expat
 import sys
 import os
+import collections
 
 class Error(Exception):
        def __init__(self, message):
@@ -263,6 +264,10 @@ class Array(object):
                self.offset = int(attrs["offset"], 0)
                self.stride = int(attrs["stride"], 0)
                self.length = int(attrs["length"], 0)
+               if "usage" in attrs:
+                       self.usages = attrs["usage"].split(',')
+               else:
+                       self.usages = None
 
        def dump(self):
                print("#define REG_%s_%s(i0) (0x%08x + 0x%x*(i0))\n" % (self.domain, self.name, self.offset, self.stride))
@@ -319,8 +324,12 @@ class Parser(object):
                # Regs that have multiple variants.. we only generated the C++
                # template based struct-packers for these
                self.variant_regs = {}
+               # Information in which contexts regs are used, to be used in
+               # debug options
+               self.usage_regs = collections.defaultdict(list)
                self.bitsets = {}
                self.enums = {}
+               self.variants = set()
                self.file = []
 
        def error(self, message):
@@ -404,6 +413,15 @@ class Parser(object):
 
                self.variant_regs[reg.name][variant] = reg;
 
+       def add_all_usages(self, reg, usages):
+               if not usages:
+                       return
+
+               for usage in usages:
+                       self.usage_regs[usage].append(reg)
+
+               self.variants.add(reg.domain)
+
        def do_validate(self, schemafile):
                try:
                        from lxml import etree
@@ -480,6 +498,14 @@ class Parser(object):
                if variant is not None:
                        self.add_all_variants(self.current_reg, attrs, variant)
 
+               usages = None
+               if "usage" in attrs:
+                       usages = attrs["usage"].split(',')
+               elif self.current_array:
+                       usages = self.current_array.usages
+
+               self.add_all_usages(self.current_reg, usages)
+
        def start_element(self, name, attrs):
                if name == "import":
                        filename = attrs["file"]
@@ -548,6 +574,47 @@ class Parser(object):
                elif name == "enum":
                        self.current_enum = None
 
+       def dump_reg_usages(self):
+               d = collections.defaultdict(list)
+               for usage, regs in self.usage_regs.items():
+                       for reg in regs:
+                               variants = self.variant_regs.get(reg.name)
+                               if variants:
+                                       for variant, vreg in variants.items():
+                                               if reg == vreg:
+                                                       d[(usage, variant)].append(reg)
+                               else:
+                                       for variant in self.variants:
+                                               d[(usage, variant)].append(reg)
+
+               print("#ifdef __cplusplus")
+
+               for usage, regs in self.usage_regs.items():
+                       print("template<chip CHIP> constexpr inline uint16_t %s_REGS[] = {};" % (usage.upper()))
+
+               for (usage, variant), regs in d.items():
+                       offsets = []
+
+                       for reg in regs:
+                               if reg.array:
+                                       for i in range(reg.array.length):
+                                               offsets.append(reg.array.offset + reg.offset + i * reg.array.stride)
+                                               if reg.bit_size == 64:
+                                                       offsets.append(offsets[-1] + 1)
+                               else:
+                                       offsets.append(reg.offset)
+                                       if reg.bit_size == 64:
+                                               offsets.append(offsets[-1] + 1)
+
+                       offsets.sort()
+
+                       print("template<> constexpr inline uint16_t %s_REGS<%s>[] = {" % (usage.upper(), variant))
+                       for offset in offsets:
+                               print("\t%s," % hex(offset))
+                       print("};")
+
+               print("#endif")
+
        def dump(self):
                enums = []
                bitsets = []
@@ -563,6 +630,8 @@ class Parser(object):
                for e in enums + bitsets + regs:
                        e.dump()
 
+               self.dump_reg_usages()
+
        def dump_reg_variants(self, regname, variants):
                # Don't bother for things that only have a single variant:
                if len(variants) == 1:
index a8166c2..414dee1 100644 (file)
                <attribute name="length" type="rng:HexOrNumber" use="required" />
                <attribute name="varset" type="NMTOKEN" use="optional" />
                <attribute name="variants" type="string" use="optional" />
+               <attribute name="usage" type="string" use="optional" />
        </complexType>
 
        <complexType name="stripeType">
                <attribute name="pos" type="nonNegativeInteger" use="optional" />
                <attribute name="align" type="nonNegativeInteger" use="optional" />
                <attribute name="radix" type="nonNegativeInteger" use="optional" />
+               <attribute name="usage" type="string" use="optional" />
        </complexType>
 
        <complexType name="bitsetType">
index e16a570..d696f17 100644 (file)
@@ -533,6 +533,8 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
                                if (!res->index) {
                                        rnn_err(db, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
                                }
+                       } else if (!strcmp(attr->name, "usage")) {
+                               // no-op
                        } else {
                                rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
                        }
@@ -601,6 +603,8 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
                                res->access = RNN_ACCESS_RW;
                        else
                                fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str);
+               } else if (!strcmp(attr->name, "usage")) {
+                       // no-op
                } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
                        rnn_err(db, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
                }