<div dir="ltr">ping<br></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Oct 29, 2018 at 12:14 PM Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This has thrown a few people off recently and it's good to have the<br>
process and all the rational for it documented somewhere.  A comment at<br>
the top of nir_inline_functions seems as good a place as any.<br>
<br>
Cc: Matt Turner <<a href="mailto:mattst88@gmail.com" target="_blank">mattst88@gmail.com</a>><br>
Cc: Karol Herbst <<a href="mailto:kherbst@redhat.com" target="_blank">kherbst@redhat.com</a>><br>
---<br>
 src/compiler/nir/nir_inline_functions.c | 68 +++++++++++++++++++++++++<br>
 1 file changed, 68 insertions(+)<br>
<br>
diff --git a/src/compiler/nir/nir_inline_functions.c b/src/compiler/nir/nir_inline_functions.c<br>
index 06c90d93956..29474bb417b 100644<br>
--- a/src/compiler/nir/nir_inline_functions.c<br>
+++ b/src/compiler/nir/nir_inline_functions.c<br>
@@ -132,6 +132,74 @@ inline_function_impl(nir_function_impl *impl, struct set *inlined)<br>
    return progress;<br>
 }<br>
<br>
+/** A pass to inline all functions in a shader into their callers<br>
+ *<br>
+ * For most use-cases, function inlining is a multi-step process.  The general<br>
+ * pattern employed by SPIR-V consumers and others is as follows:<br>
+ *<br>
+ *  1. nir_lower_constant_initializers(shader, nir_var_local)<br>
+ *<br>
+ *     This is needed because local variables from the callee are simply added<br>
+ *     to the locals list for the caller and the information about where the<br>
+ *     constant initializer logically happens is lost.  If the callee is<br>
+ *     called in a loop, this can cause the variable to go from being<br>
+ *     initialized once per loop iteration to being initialized once at the<br>
+ *     top of the caller and values to persist from one invocation of the<br>
+ *     callee to the next.  The simple solution to this problem is to get rid<br>
+ *     of constant initializers before function inlining.<br>
+ *<br>
+ *  2. nir_lower_returns(shader)<br>
+ *<br>
+ *     nir_inline_functions assumes that all functions end "naturally" by<br>
+ *     execution reaching the end of the function without any return<br>
+ *     instructions causing instant jumps to the end.  Thanks to NIR being<br>
+ *     structured, we can't represent arbitrary jumps to various points in the<br>
+ *     program which is what an early return in the callee would have to turn<br>
+ *     into when we inline it into the caller.  Instead, we require returns to<br>
+ *     be lowered which lets us just copy+paste the callee directly into the<br>
+ *     caller.<br>
+ *<br>
+ *  3. nir_inline_functions(shader)<br>
+ *<br>
+ *     This does the actual function inlining and the resulting shader will<br>
+ *     contain no call instructions.<br>
+ *<br>
+ *  4. nir_copy_prop(shader)<br>
+ *<br>
+ *     Most functions contain pointer parameters where the result of a deref<br>
+ *     instruction is passed in as a parameter, loaded via a load_param<br>
+ *     intrinsic, and then turned back into a deref via a cast.  Running copy<br>
+ *     propagation gets rid of the intermediate steps and results in a whole<br>
+ *     deref chain again.  This is currently required by a number of<br>
+ *     optimizations and lowering passes at least for certain variable modes.<br>
+ *<br>
+ *  5. Loop over the functions and delete all but the main entrypoint.<br>
+ *<br>
+ *     In the Intel Vulkan driver this looks like this:<br>
+ *<br>
+ *        foreach_list_typed_safe(nir_function, func, node, &nir->functions) {<br>
+ *           if (func != entry_point)<br>
+ *              exec_node_remove(&func->node);<br>
+ *        }<br>
+ *        assert(exec_list_length(&nir->functions) == 1);<br>
+ *<br>
+ *    While nir_inline_functions does get rid of all call instructions, it<br>
+ *    doesn't get rid of any functions because it doesn't know what the "root<br>
+ *    function" is.  Instead, it's up to the individual driver to know how to<br>
+ *    decide on a root function and delete the rest.  With SPIR-V,<br>
+ *    spirv_to_nir returns the root function and so we can just use == whereas<br>
+ *    with GL, you may have to look for a function named "main".<br>
+ *<br>
+ *  6. nir_lower_constant_initializers(shader, ~nir_var_local)<br>
+ *<br>
+ *     Lowering constant initializers on inputs, outputs, global variables,<br>
+ *     etc. requires that we know the main entrypoint so that we know where to<br>
+ *     initialize them.  Otherwise, we would have to assume that anything<br>
+ *     could be a main entrypoint and initialize them at the start of every<br>
+ *     function but that would clearly be wrong if any of those functions were<br>
+ *     ever called within another function.  Simply requiring a single-<br>
+ *     entrypoint function shader is the best way to make it well-defined.<br>
+ */<br>
 bool<br>
 nir_inline_functions(nir_shader *shader)<br>
 {<br>
-- <br>
2.19.1<br>
<br>
</blockquote></div>