[Mesa-dev] [PATCH] glsl: correctly handle inout parameters post function inlining
Lars Hamre
chemecse at gmail.com
Fri May 6 12:49:51 UTC 2016
Inout parameters which depended on other inout parameters
where not assigned in the correct order.
Fixes the following piglit tests in shaders/out-parameter-indexing:
vs-inout-index-inout-float-array
vs-inout-index-inout-mat2-col
vs-inout-index-inout-mat2-row
vs-inout-index-inout-vec4
vs-inout-index-inout-vec4-array
vs-inout-index-inout-vec4-array-element
Signed-off-by: Lars Hamre <chemecse at gmail.com>
---
NOTES:
- Someone with access will need to commit this post
review process.
- Not sure if this is the "mesa" approach to this
problem, feedback is appreciated.
src/compiler/glsl/opt_function_inlining.cpp | 80 ++++++++++++++++++++++++++---
1 file changed, 73 insertions(+), 7 deletions(-)
diff --git a/src/compiler/glsl/opt_function_inlining.cpp b/src/compiler/glsl/opt_function_inlining.cpp
index 19f5fae..a5e7ea6 100644
--- a/src/compiler/glsl/opt_function_inlining.cpp
+++ b/src/compiler/glsl/opt_function_inlining.cpp
@@ -95,6 +95,54 @@ replace_return_with_assignment(ir_instruction *ir, void *data)
}
}
+static void
+gather_inout_vars_from_params(void *ctx,
+ exec_list *actual_params,
+ exec_list *callee_params,
+ exec_list *inout_vars)
+{
+ foreach_two_lists(formal_node, callee_params,
+ actual_node, actual_params) {
+ ir_rvalue *const param = (ir_rvalue *)actual_node;
+ const ir_variable *const sig_param = (ir_variable *)formal_node;
+
+ if (sig_param->data.mode == ir_var_function_inout &&
+ param->ir_type == ir_type_dereference_variable) {
+ inout_vars->push_tail(sig_param->clone(ctx, NULL));
+ }
+ }
+}
+
+static bool
+rvalue_depends_on_inout_var_helper(ir_rvalue *rv, exec_list *inout_vars)
+{
+ if (rv->ir_type == ir_type_dereference_array) {
+ ir_dereference_array *deref_arr = (ir_dereference_array *)rv;
+ return (rvalue_depends_on_inout_var_helper(deref_arr->array, inout_vars) ||
+ rvalue_depends_on_inout_var_helper(deref_arr->array_index, inout_vars));
+ } else if (rv->ir_type == ir_type_swizzle) {
+ return rvalue_depends_on_inout_var_helper(((ir_swizzle *)rv)->val, inout_vars);
+ } else if (rv->ir_type == ir_type_dereference_variable) {
+ const char *var_name = ((ir_dereference_variable *)rv)->var->name;
+ foreach_in_list(ir_variable, inout_var, inout_vars) {
+ if (!strcmp(var_name, inout_var->name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+rvalue_depends_on_inout_var(ir_rvalue *rv, exec_list *inout_vars)
+{
+ if (rv->ir_type == ir_type_dereference_array ||
+ rv->ir_type == ir_type_swizzle) {
+ return rvalue_depends_on_inout_var_helper(rv, inout_vars);
+ }
+ return false;
+}
+
void
ir_call::generate_inline(ir_instruction *next_ir)
{
@@ -185,7 +233,14 @@ ir_call::generate_inline(ir_instruction *next_ir)
/* Copy back the value of any 'out' parameters from the function body
* variables to our own.
*/
+
+ exec_list inout_vars;
+ gather_inout_vars_from_params(ctx, &this->actual_parameters,
+ &this->callee->parameters,
+ &inout_vars);
+
i = 0;
+ ir_instruction *last_non_dependent_inout_assigned = next_ir;
foreach_two_lists(formal_node, &this->callee->parameters,
actual_node, &this->actual_parameters) {
ir_rvalue *const param = (ir_rvalue *) actual_node;
@@ -194,12 +249,24 @@ ir_call::generate_inline(ir_instruction *next_ir)
/* Move our param variable into the actual param if it's an 'out' type. */
if (parameters[i] && (sig_param->data.mode == ir_var_function_out ||
sig_param->data.mode == ir_var_function_inout)) {
- ir_assignment *assign;
-
- assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
- new(ctx) ir_dereference_variable(parameters[i]),
- NULL);
- next_ir->insert_before(assign);
+ ir_assignment *assign;
+
+ assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(),
+ new(ctx) ir_dereference_variable(parameters[i]),
+ NULL);
+
+ if (sig_param->data.mode == ir_var_function_inout &&
+ rvalue_depends_on_inout_var(param, &inout_vars)) {
+ /*
+ * Insert assignment before the others if it depends on another
+ * inout parameter.
+ */
+ last_non_dependent_inout_assigned->insert_before(assign);
+ } else {
+ /* Otherwise insert assignment before the next_ir */
+ next_ir->insert_before(assign);
+ last_non_dependent_inout_assigned = assign;
+ }
}
++i;
@@ -210,7 +277,6 @@ ir_call::generate_inline(ir_instruction *next_ir)
hash_table_dtor(ht);
}
-
ir_visitor_status
ir_function_inlining_visitor::visit_enter(ir_expression *ir)
{
--
2.5.5
More information about the mesa-dev
mailing list