anv: convert C generation to template in anv_entrypoints_gen.py
authorDylan Baker <dylan@pnwbakers.com>
Sat, 18 Feb 2017 00:54:27 +0000 (16:54 -0800)
committerDylan Baker <dylan@pnwbakers.com>
Wed, 22 Mar 2017 23:22:00 +0000 (16:22 -0700)
This produces a file that is identical except for whitespace, there is a
table that has 8 columns in the original and is easy to do with prints,
but is ugly using mako, so it doesn't have columns; the data is not
inherently tabular.

Signed-off-by: Dylan Baker <dylanx.c.baker@intel.com>
src/intel/vulkan/anv_entrypoints_gen.py

index 7dd98f960cea07a058d94516e8523bf2952fd6e3..bf6b20951ff593ee92c0ac57738abdd0b010e95d 100644 (file)
@@ -88,93 +88,7 @@ TEMPLATE_H = Template(textwrap.dedent("""\
     % endfor
     """))
 
-NONE = 0xffff
-HASH_SIZE = 256
-U32_MASK = 2**32 - 1
-HASH_MASK = HASH_SIZE - 1
-
-PRIME_FACTOR = 5024183
-PRIME_STEP = 19
-
-opt_header = False
-opt_code = False
-
-
-def hash(name):
-    h = 0
-    for c in name:
-        h = (h * PRIME_FACTOR + ord(c)) & U32_MASK
-
-    return h
-
-
-def print_guard_start(guard):
-    if guard is not None:
-        print "#ifdef {0}".format(guard)
-
-
-def print_guard_end(guard):
-    if guard is not None:
-        print "#endif // {0}".format(guard)
-
-
-def get_entrypoints(doc, entrypoints_to_defines):
-    """Extract the entry points from the registry."""
-    entrypoints = []
-
-    enabled_commands = set()
-    for feature in doc.findall('./feature'):
-        assert feature.attrib['api'] == 'vulkan'
-        if float(feature.attrib['number']) > MAX_API_VERSION:
-            continue
-
-        for command in feature.findall('./require/command'):
-            enabled_commands.add(command.attrib['name'])
-
-    for extension in doc.findall('.extensions/extension'):
-        if extension.attrib['name'] not in SUPPORTED_EXTENSIONS:
-            continue
-
-        assert extension.attrib['supported'] == 'vulkan'
-        for command in extension.findall('./require/command'):
-            enabled_commands.add(command.attrib['name'])
-
-    index = 0
-    for command in doc.findall('./commands/command'):
-        type = command.find('./proto/type').text
-        fullname = command.find('./proto/name').text
-
-        if fullname not in enabled_commands:
-            continue
-
-        shortname = fullname[2:]
-        params = (''.join(p.itertext()) for p in command.findall('./param'))
-        params = ', '.join(params)
-        if fullname in entrypoints_to_defines:
-            guard = entrypoints_to_defines[fullname]
-        else:
-            guard = None
-        entrypoints.append((type, shortname, params, index, hash(fullname), guard))
-        index += 1
-
-    return entrypoints
-
-
-def get_entrypoints_defines(doc):
-    """Maps entry points to extension defines."""
-    entrypoints_to_defines = {}
-    extensions = doc.findall('./extensions/extension')
-    for extension in extensions:
-        define = extension.get('protect')
-        entrypoints = extension.findall('./require/command')
-        for entrypoint in entrypoints:
-            fullname = entrypoint.get('name')
-            entrypoints_to_defines[fullname] = define
-    return entrypoints_to_defines
-
-
-def gen_code(entrypoints):
-    print textwrap.dedent("""\
+TEMPLATE_C = Template(textwrap.dedent(u"""\
     /*
      * Copyright © 2015 Intel Corporation
      *
@@ -198,58 +112,61 @@ def gen_code(entrypoints):
      * IN THE SOFTWARE.
      */
 
-    /* This file generated from {}, don't edit directly. */
+    /* This file generated from ${filename}, don't edit directly. */
 
     #include "anv_private.h"
 
-    struct anv_entrypoint {{
+    struct anv_entrypoint {
        uint32_t name;
        uint32_t hash;
-    }};
+    };
 
     /* We use a big string constant to avoid lots of reloctions from the entry
      * point table to lots of little strings. The entries in the entry point table
      * store the index into this big string.
      */
 
-    static const char strings[] =""".format(os.path.basename(__file__)))
-
-    offsets = []
-    i = 0
-    for type, name, args, num, h, guard in entrypoints:
-        print "   \"vk%s\\0\"" % name
-        offsets.append(i)
-        i += 2 + len(name) + 1
-    print "   ;"
-
-    # Now generate the table of all entry points
-
-    print "\nstatic const struct anv_entrypoint entrypoints[] = {"
-    for type, name, args, num, h, guard in entrypoints:
-        print "   { %5d, 0x%08x }," % (offsets[num], h)
-    print "};\n"
+    static const char strings[] =
+    % for _, name, _, _, _, _ in entrypoints:
+        "vk${name}\\0"
+    % endfor
+    ;
 
-    print textwrap.dedent("""
+    static const struct anv_entrypoint entrypoints[] = {
+    % for _, _, _, num, h, _ in entrypoints:
+        { ${offsets[num]}, ${'{:0=#8x}'.format(h)} },
+    % endfor
+    };
 
     /* Weak aliases for all potential implementations. These will resolve to
      * NULL if they're not defined, which lets the resolve_entrypoint() function
      * either pick the correct entry point.
      */
-    """)
-
-    for layer in ["anv", "gen7", "gen75", "gen8", "gen9"]:
-        for type, name, args, num, h, guard in entrypoints:
-            print_guard_start(guard)
-            print "%s %s_%s(%s) __attribute__ ((weak));" % (type, layer, name, args)
-            print_guard_end(guard)
-        print "\nconst struct anv_dispatch_table %s_layer = {" % layer
-        for type, name, args, num, h, guard in entrypoints:
-            print_guard_start(guard)
-            print "   .%s = %s_%s," % (name, layer, name)
-            print_guard_end(guard)
-        print "};\n"
-
-    print textwrap.dedent("""
+
+    % for layer in ['anv', 'gen7', 'gen75', 'gen8', 'gen9']:
+      % for type_, name, args, _, _, guard in entrypoints:
+        % if guard is not None:
+    #ifdef ${guard}
+        % endif
+        ${type_} ${layer}_${name}(${args}) __attribute__ ((weak));
+        % if guard is not None:
+    #endif // ${guard}
+        % endif
+      % endfor
+
+      const struct anv_dispatch_table ${layer}_layer = {
+      % for _, name, args, _, _, guard in entrypoints:
+        % if guard is not None:
+    #ifdef ${guard}
+        % endif
+        .${name} = ${layer}_${name},
+        % if guard is not None:
+    #endif // ${guard}
+        % endif
+      % endfor
+      };
+    % endfor
+
     static void * __attribute__ ((noinline))
     anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
     {
@@ -279,60 +196,34 @@ def gen_code(entrypoints):
           unreachable("unsupported gen\\n");
        }
     }
-    """)
-
-    # Now generate the hash table used for entry point look up.  This is a
-    # uint16_t table of entry point indices. We use 0xffff to indicate an entry
-    # in the hash table is empty.
-
-    map = [NONE] * HASH_SIZE
-    collisions = [0] * 10
-    for type, name, args, num, h, guard in entrypoints:
-        level = 0
-        while map[h & HASH_MASK] != NONE:
-            h = h + PRIME_STEP
-            level = level + 1
-        if level > 9:
-            collisions[9] += 1
-        else:
-            collisions[level] += 1
-        map[h & HASH_MASK] = num
-
-    print "/* Hash table stats:"
-    print " * size %d entries" % HASH_SIZE
-    print " * collisions  entries"
-    for i in xrange(10):
-        if i == 9:
-            plus = "+"
-        else:
-            plus = " "
 
-        print " *     %2d%s     %4d" % (i, plus, collisions[i])
-    print " */\n"
-
-    print "#define none 0x%04x\n" % NONE
-
-    print "static const uint16_t map[] = {"
-    for i in xrange(0, HASH_SIZE, 8):
-        print "   ",
-        for j in xrange(i, i + 8):
-            if map[j] & 0xffff == 0xffff:
-                print "  none,",
-            else:
-                print "0x%04x," % (map[j] & 0xffff),
-        print
-
-    print "};"
+    /* Hash table stats:
+     * size ${hash_size} entries
+     * collisions entries:
+    % for i in xrange(10):
+     *     ${i}${'+' if i == 9 else ''}     ${collisions[i]}
+    % endfor
+     */
 
-    # Finally we generate the hash table lookup function.  The hash function and
-    # linear probing algorithm matches the hash table generated above.
+    #define none ${'{:#x}'.format(none)}
+    static const uint16_t map[] = {
+    % for i in xrange(0, hash_size, 8):
+      % for j in xrange(i, i + 8):
+        ## This is 6 because the 0x is counted in the length
+        % if mapping[j] & 0xffff == 0xffff:
+          none,
+        % else:
+          ${'{:0=#6x}'.format(mapping[j] & 0xffff)},
+        % endif
+      % endfor
+    % endfor
+    };
 
-    print textwrap.dedent("""
     void *
     anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name)
     {
-       static const uint32_t prime_factor = %d;
-       static const uint32_t prime_step = %d;
+       static const uint32_t prime_factor = ${prime_factor};
+       static const uint32_t prime_step = ${prime_step};
        const struct anv_entrypoint *e;
        uint32_t hash, h, i;
        const char *p;
@@ -343,7 +234,7 @@ def gen_code(entrypoints):
 
        h = hash;
        do {
-          i = map[h & %d];
+          i = map[h & ${hash_mask}];
           if (i == none)
              return NULL;
           e = &entrypoints[i];
@@ -354,8 +245,111 @@ def gen_code(entrypoints):
           return NULL;
 
        return anv_resolve_entrypoint(devinfo, i);
-    }
-    """) % (PRIME_FACTOR, PRIME_STEP, HASH_MASK)
+    }"""), output_encoding='utf-8')
+
+NONE = 0xffff
+HASH_SIZE = 256
+U32_MASK = 2**32 - 1
+HASH_MASK = HASH_SIZE - 1
+
+PRIME_FACTOR = 5024183
+PRIME_STEP = 19
+
+
+def hash(name):
+    h = 0
+    for c in name:
+        h = (h * PRIME_FACTOR + ord(c)) & U32_MASK
+
+    return h
+
+
+def get_entrypoints(doc, entrypoints_to_defines):
+    """Extract the entry points from the registry."""
+    entrypoints = []
+
+    enabled_commands = set()
+    for feature in doc.findall('./feature'):
+        assert feature.attrib['api'] == 'vulkan'
+        if float(feature.attrib['number']) > MAX_API_VERSION:
+            continue
+
+        for command in feature.findall('./require/command'):
+            enabled_commands.add(command.attrib['name'])
+
+    for extension in doc.findall('.extensions/extension'):
+        if extension.attrib['name'] not in SUPPORTED_EXTENSIONS:
+            continue
+
+        assert extension.attrib['supported'] == 'vulkan'
+        for command in extension.findall('./require/command'):
+            enabled_commands.add(command.attrib['name'])
+
+    index = 0
+    for command in doc.findall('./commands/command'):
+        type = command.find('./proto/type').text
+        fullname = command.find('./proto/name').text
+
+        if fullname not in enabled_commands:
+            continue
+
+        shortname = fullname[2:]
+        params = (''.join(p.itertext()) for p in command.findall('./param'))
+        params = ', '.join(params)
+        if fullname in entrypoints_to_defines:
+            guard = entrypoints_to_defines[fullname]
+        else:
+            guard = None
+        entrypoints.append((type, shortname, params, index, hash(fullname), guard))
+        index += 1
+
+    return entrypoints
+
+
+def get_entrypoints_defines(doc):
+    """Maps entry points to extension defines."""
+    entrypoints_to_defines = {}
+    extensions = doc.findall('./extensions/extension')
+    for extension in extensions:
+        define = extension.get('protect')
+        entrypoints = extension.findall('./require/command')
+        for entrypoint in entrypoints:
+            fullname = entrypoint.get('name')
+            entrypoints_to_defines[fullname] = define
+    return entrypoints_to_defines
+
+
+def gen_code(entrypoints):
+    """Generate the C code."""
+    i = 0
+    offsets = []
+    for _, name, _, _, _, _ in entrypoints:
+        offsets.append(i)
+        i += 2 + len(name) + 1
+
+    mapping = [NONE] * HASH_SIZE
+    collisions = [0] * 10
+    for _, name, _, num, h, _ in entrypoints:
+        level = 0
+        while mapping[h & HASH_MASK] != NONE:
+            h = h + PRIME_STEP
+            level = level + 1
+        if level > 9:
+            collisions[9] += 1
+        else:
+            collisions[level] += 1
+        mapping[h & HASH_MASK] = num
+
+    print TEMPLATE_C.render(entrypoints=entrypoints,
+                            offsets=offsets,
+                            collisions=collisions,
+                            mapping=mapping,
+                            hash_mask=HASH_MASK,
+                            prime_step=PRIME_STEP,
+                            prime_factor=PRIME_FACTOR,
+                            none=NONE,
+                            hash_size=HASH_SIZE,
+                            filename=os.path.basename(__file__))
 
 
 def main():