<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 7, 2016 at 10:36 AM, Ian Romanick <span dir="ltr"><<a href="mailto:idr@freedesktop.org" target="_blank">idr@freedesktop.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 07/07/2016 04:15 AM, Jason Ekstrand wrote:<br>
> I can't help but think that we keep solving this problem... We have a<br>
> low-collision hash table for vkGetProcAddress, something for<br>
> glxGetProcAddress and eglGetProcAddress (hopefully the same?) and now<br>
> this.  Can we pick a method, make it a little Python helper, and use it<br>
> everywhere?<br>
><br>
> Not being critical; this is probably a fine solution for compile-time<br>
> string -> int mappings and possibly the best to date.  It just seems<br>
> like kind of a big hammer especially if glsl_to_nir is its only user.<br>
<br>
</span>Well... I went to this extreme partially for fun. :)  I think there are<br>
other places that could use this, and I mentioned one in the intro<br>
message.  I haven't gone looking through the code to find others, but I<br>
suspect there may be.  That might even be a cool newbie project.<br></blockquote><div><br></div><div>I wondered about that... This kind of smelled like show-off code.  :-)  Not that there's anything wrong with that...<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I don't think this particular solution is useful for GetProcAddress<br>
kinds of things because (by the end) it depends on callers only ever<br>
querying things that are in the set.  The other problem with<br>
glXGetProcAddress and eglGetProcAddress is the driver can add new things<br>
to the set.  I'm not sure if anything can add functions to the set used<br>
by vkGetProcAddress.<br></blockquote><div><br></div><div>Right.  I hadn't considered implementations adding things to the list.  For vkGetProcAddress, we don't do anything dynamic with it yet.  That may change in the future. I don't know.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
> On Jul 5, 2016 5:46 PM, "Ian Romanick" <<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a><br>
</span><span class="">> <mailto:<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>>> wrote:<br>
><br>
>     From: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a><br>
</span>>     <mailto:<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>>><br>
<span class="">><br>
>     If there is a way to do this cleanly in mako, I'm very interested to<br>
>     hear about it.<br>
><br>
>        text    data     bss     dec     hex filename<br>
>     7529003  273096   28584 7830683  777c9b /tmp/i965_dri-64bit-before.so<br>
>     7528883  273096   28584 7830563  777c23 /tmp/i965_dri-64bit-after.so<br>
><br>
>     Signed-off-by: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a><br>
</span>>     <mailto:<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>>><br>
<div><div class="h5">>     ---<br>
>      src/compiler/glsl/nir_intrinsic_map.py | 131<br>
>     ++++++++++++++++++++++++++++++---<br>
>      1 file changed, 119 insertions(+), 12 deletions(-)<br>
><br>
>     diff --git a/src/compiler/glsl/nir_intrinsic_map.py<br>
>     b/src/compiler/glsl/nir_intrinsic_map.py<br>
>     index 7f13c6c..5962d4b 100644<br>
>     --- a/src/compiler/glsl/nir_intrinsic_map.py<br>
>     +++ b/src/compiler/glsl/nir_intrinsic_map.py<br>
>     @@ -66,6 +66,123 @@ intrinsics = [("__intrinsic_atomic_read",<br>
>     ("nir_intrinsic_atomic_counter_read_va<br>
>                    ("__intrinsic_atomic_exchange_shared",<br>
>     ("nir_intrinsic_shared_atomic_exchange", None)),<br>
>                    ("__intrinsic_atomic_comp_swap_shared",<br>
>     ("nir_intrinsic_shared_atomic_comp_swap", None))]<br>
><br>
>     +def remove_prefix(table, prefix_length):<br>
>     +    """Strip prefix_length characters off the name of each entry in<br>
>     table."""<br>
>     +<br>
>     +    return [(s[prefix_length:], d) for (s, d) in table]<br>
>     +<br>
>     +<br>
>     +def generate_trie(table):<br>
>     +    """table is a list of (string, data) tuples.  It is assumed to<br>
>     be sorted by<br>
>     +    string.<br>
>     +<br>
>     +    A radix trie (or compact prefix trie) is recursively generated<br>
>     from the<br>
>     +    list of names.  Names are paritioned into groups that have at least<br>
>     +    prefix_thresh (tunable parameter) common prefix characters.<br>
>     Each of these<br>
>     +    groups becomes the branches at the current level of the tree.  The<br>
>     +    matching prefix characters from each group is removed, and the<br>
>     group is<br>
>     +    recursively operated on in the same fashion.<br>
>     +<br>
>     +    The recursion terminates when no groups can be formed with at least<br>
>     +    prefix_thresh matching characters.<br>
>     +<br>
>     +    Each node in the trie is a 3-element tuple:<br>
>     +<br>
>     +        (prefix_string, [child_nodes], client_data)<br>
>     +<br>
>     +    One of [child_nodes] or client_data will be None.<br>
>     +<br>
>     +    See <a href="https://en.wikipedia.org/wiki/Radix_tree" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Radix_tree</a> for more<br>
>     background details<br>
>     +    on the data structure.<br>
>     +<br>
>     +    """<br>
>     +<br>
>     +    # Threshold for considering two strings to have the same prefix.<br>
>     +    prefix_thresh = 1<br>
>     +<br>
>     +    if len(table) == 1 and table[0][0] == "":<br>
>     +        return [("", None, table[0][1])]<br>
>     +<br>
>     +    trie_level = []<br>
>     +<br>
>     +    (s, d) = table[0]<br>
>     +    candidates = [(s, d)]<br>
>     +    base = s<br>
>     +    prefix_length = len(s)<br>
>     +<br>
>     +    for (s, d) in table[1:]:<br>
>     +        if s[:prefix_thresh] == base[:prefix_thresh]:<br>
>     +            candidates.append((s, d))<br>
>     +<br>
>     +            l = len(s[:([x[0]==x[1] for x in zip(s,<br>
>     base)]+[0]).index(0)])<br>
>     +            if l < prefix_length:<br>
>     +                prefix_length = l<br>
>     +        else:<br>
>     +            trie_level.append((base[:prefix_length],<br>
>     generate_trie(remove_prefix(candidates, prefix_length)), None))<br>
>     +<br>
>     +            candidates = [(s, d)]<br>
>     +            base = s<br>
>     +            prefix_length = len(s)<br>
>     +<br>
>     +    trie_level.append((base[:prefix_length],<br>
>     generate_trie(remove_prefix(candidates, prefix_length)), None))<br>
>     +<br>
>     +    return trie_level<br>
>     +<br>
>     +<br>
>     +def emit_trie_leaf(indent, d):<br>
>     +    if d[1] is None:<br>
>     +        return "{}return {};\n".format(indent, d[0])<br>
>     +    else:<br>
>     +        c_code = "{}int_op = {};\n".format(indent, d[0])<br>
>     +        c_code += "{}uint_op = {};\n".format(indent, d[1])<br>
>     +        return c_code<br>
>     +<br>
>     +<br>
>     +def trie_as_C_code(trie, indent="   ", prefix_string="__intrinsic_"):<br>
>     +    conditional = "if"<br>
>     +<br>
>     +    c_code = ""<br>
>     +    for (s, t, d) in trie:<br>
>     +        if d is not None:<br>
>     +            c_code +=  "{}{} (name[0] == '\\0')<br>
>     {{\n".format(indent, conditional)<br>
>     +            c_code += "{}   /* {} */\n".format(indent, prefix_string)<br>
>     +            c_code += emit_trie_leaf(indent + "   ", d);<br>
>     +<br>
>     +        else:<br>
>     +            # Before emitting the string comparison, check to see<br>
>     of the<br>
>     +            # subtree has a single element with an empty string.<br>
>     In that<br>
>     +            # case, use strcmp() instead of strncmp() and don't<br>
>     advance the<br>
>     +            # name pointer.<br>
>     +<br>
>     +            if len(t) == 1 and t[0][2] is not None:<br>
>     +                if s == "":<br>
>     +                    c_code += "{}{} (name[0] == '\\0')<br>
>     {{\n".format(indent, conditional, s)<br>
>     +                else:<br>
>     +                    c_code += "{}{} (strcmp(name, \"{}\") == 0)<br>
>     {{\n".format(indent, conditional, s)<br>
>     +<br>
>     +                c_code += "{}   /* {} */\n".format(indent,<br>
>     prefix_string + s)<br>
>     +                c_code += emit_trie_leaf(indent + "   ", t[0][2]);<br>
>     +            else:<br>
>     +                c_code += "{}{} (strncmp(name, \"{}\", {}) == 0)<br>
>     {{\n".format(indent, conditional, s, len(s))<br>
>     +                c_code += "{}   name += {};\n\n".format(indent, len(s))<br>
>     +<br>
>     +                c_code += trie_as_C_code(t, indent + "   ",<br>
>     prefix_string + s)<br>
>     +<br>
>     +        conditional = "} else if"<br>
>     +<br>
>     +    c_code += "{}}} else\n".format(indent)<br>
>     +    c_code += "{}   unreachable(\"Invalid intrinsic<br>
>     name\");\n\n".format(indent)<br>
>     +    return c_code<br>
>     +<br>
>     +<br>
>     +intrinsics.sort(key=lambda tup: tup[0])<br>
>     +<br>
>     +trimmed_name_intrinsics = []<br>
>     +for (s, d) in intrinsics:<br>
>     +    trimmed_name_intrinsics.append((s[12:], d))<br>
>     +<br>
>     +trie_search = trie_as_C_code(generate_trie(trimmed_name_intrinsics))<br>
>     +<br>
>      template = """<br>
>      namespace _glsl_to_nir {<br>
><br>
>     @@ -80,17 +197,7 @@ get_intrinsic_opcode(const char *name, const<br>
>     ir_dereference *return_deref)<br>
>         nir_intrinsic_op int_op;<br>
>         nir_intrinsic_op uint_op;<br>
><br>
>     -    % for (name, ops) in intrinsics:<br>
>     -   if (strcmp(name, "${name[12:]}") == 0) {<br>
>     -        % if ops[1] is None:<br>
>     -      return ${ops[0]};<br>
>     -        % else:<br>
>     -      int_op = ${ops[0]};<br>
>     -      uint_op = ${ops[1]};<br>
>     -        % endif<br>
>     -   } else<br>
>     -    % endfor<br>
>     -      unreachable("Unknown intrinsic name");<br>
>     +${trie_search}<br>
><br>
>         assert(return_deref);<br>
>         if (return_deref->type == glsl_type::int_type)<br>
>     @@ -103,4 +210,4 @@ get_intrinsic_opcode(const char *name, const<br>
>     ir_dereference *return_deref)<br>
>      }<br>
>      """<br>
><br>
>     -print(Template(template).render(intrinsics=intrinsics))<br>
>     +print(Template(template).render(trie_search=trie_search))<br>
>     --<br>
>     2.5.5<br>
><br>
>     _______________________________________________<br>
>     mesa-dev mailing list<br>
</div></div>>     <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a> <mailto:<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a>><br>
>     <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
><br>
<br>
</blockquote></div><br></div></div>