<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>