<p dir="ltr">I can't help but think that we keep solving this problem... We have a low-collision hash table for vkGetProcAddress, something for glxGetProcAddress and eglGetProcAddress (hopefully the same?) and now this. Can we pick a method, make it a little Python helper, and use it everywhere?</p>
<p dir="ltr">Not being critical; this is probably a fine solution for compile-time string -> int mappings and possibly the best to date. It just seems like kind of a big hammer especially if glsl_to_nir is its only user.</p>
<div class="gmail_quote">On Jul 5, 2016 5:46 PM, "Ian Romanick" <<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>><br>
<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>
---<br>
src/compiler/glsl/nir_intrinsic_map.py | 131 ++++++++++++++++++++++++++++++---<br>
1 file changed, 119 insertions(+), 12 deletions(-)<br>
<br>
diff --git a/src/compiler/glsl/nir_intrinsic_map.py 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", ("nir_intrinsic_atomic_counter_read_va<br>
("__intrinsic_atomic_exchange_shared", ("nir_intrinsic_shared_atomic_exchange", None)),<br>
("__intrinsic_atomic_comp_swap_shared", ("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 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 be sorted by<br>
+ string.<br>
+<br>
+ A radix trie (or compact prefix trie) is recursively generated from the<br>
+ list of names. Names are paritioned into groups that have at least<br>
+ prefix_thresh (tunable parameter) common prefix characters. 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 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 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, base)]+[0]).index(0)])<br>
+ if l < prefix_length:<br>
+ prefix_length = l<br>
+ else:<br>
+ trie_level.append((base[:prefix_length], 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], 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') {{\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 of the<br>
+ # subtree has a single element with an empty string. In that<br>
+ # case, use strcmp() instead of strncmp() and don't 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') {{\n".format(indent, conditional, s)<br>
+ else:<br>
+ c_code += "{}{} (strcmp(name, \"{}\") == 0) {{\n".format(indent, conditional, s)<br>
+<br>
+ c_code += "{} /* {} */\n".format(indent, prefix_string + s)<br>
+ c_code += emit_trie_leaf(indent + " ", t[0][2]);<br>
+ else:<br>
+ c_code += "{}{} (strncmp(name, \"{}\", {}) == 0) {{\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 + " ", prefix_string + s)<br>
+<br>
+ conditional = "} else if"<br>
+<br>
+ c_code += "{}}} else\n".format(indent)<br>
+ c_code += "{} unreachable(\"Invalid intrinsic 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 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 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>
<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>
</blockquote></div>