glsl: Put `sample`-qualified varyings in their own packing classes
[mesa.git] / src / glsl / lower_vec_index_to_cond_assign.cpp
index f8011a16e5ba1286ef00c74619f491aca7bb3829..8080006c1d0071496e6986c8e908374132dd36bd 100644 (file)
@@ -41,6 +41,8 @@
 #include "ir_optimization.h"
 #include "glsl_types.h"
 
+namespace {
+
 /**
  * Visitor class for replacing expressions with ir_constant values.
  */
@@ -52,7 +54,12 @@ public:
       progress = false;
    }
 
-   ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
+   ir_rvalue *convert_vec_index_to_cond_assign(void *mem_ctx,
+                                               ir_rvalue *orig_vector,
+                                               ir_rvalue *orig_index,
+                                               const glsl_type *type);
+
+   ir_rvalue *convert_vector_extract_to_cond_assign(ir_rvalue *ir);
 
    virtual ir_visitor_status visit_enter(ir_expression *);
    virtual ir_visitor_status visit_enter(ir_swizzle *);
@@ -64,72 +71,100 @@ public:
    bool progress;
 };
 
+} /* anonymous namespace */
+
 ir_rvalue *
-ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
+ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(void *mem_ctx,
+                                                                      ir_rvalue *orig_vector,
+                                                                      ir_rvalue *orig_index,
+                                                                      const glsl_type *type)
 {
-   ir_dereference_array *orig_deref = ir->as_dereference_array();
-   ir_assignment *assign;
-   ir_variable *index, *var;
-   ir_dereference *deref;
-   ir_expression *condition;
-   ir_swizzle *swizzle;
-   int i;
-
-   if (!orig_deref)
-      return ir;
+   ir_assignment *assign, *value_assign;
+   ir_variable *index, *var, *value;
+   ir_dereference *deref, *deref_value;
+   unsigned i;
 
-   if (orig_deref->array->type->is_matrix() ||
-       orig_deref->array->type->is_array())
-      return ir;
 
-   void *mem_ctx = talloc_parent(ir);
-
-   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
+   exec_list list;
 
    /* Store the index to a temporary to avoid reusing its tree. */
    index = new(base_ir) ir_variable(glsl_type::int_type,
                                    "vec_index_tmp_i",
                                    ir_var_temporary);
-   base_ir->insert_before(index);
+   list.push_tail(index);
    deref = new(base_ir) ir_dereference_variable(index);
-   assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
-   base_ir->insert_before(assign);
+   assign = new(base_ir) ir_assignment(deref, orig_index, NULL);
+   list.push_tail(assign);
+
+   /* Store the value inside a temp, thus avoiding matrixes duplication */
+   value = new(base_ir) ir_variable(orig_vector->type, "vec_value_tmp",
+                                    ir_var_temporary);
+   list.push_tail(value);
+   deref_value = new(base_ir) ir_dereference_variable(value);
+   value_assign = new(base_ir) ir_assignment(deref_value, orig_vector);
+   list.push_tail(value_assign);
 
    /* Temporary where we store whichever value we swizzle out. */
-   var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
+   var = new(base_ir) ir_variable(type, "vec_index_tmp_v",
                                  ir_var_temporary);
-   base_ir->insert_before(var);
+   list.push_tail(var);
+
+   /* Generate a single comparison condition "mask" for all of the components
+    * in the vector.
+    */
+   ir_rvalue *const cond_deref =
+      compare_index_block(&list, index, 0,
+                          orig_vector->type->vector_elements,
+                         mem_ctx);
 
    /* Generate a conditional move of each vector element to the temp. */
-   for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
-      deref = new(base_ir) ir_dereference_variable(index);
-      condition = new(base_ir) ir_expression(ir_binop_equal,
-                                            glsl_type::bool_type,
-                                            deref,
-                                            new(base_ir) ir_constant(i));
+   for (i = 0; i < orig_vector->type->vector_elements; i++) {
+      ir_rvalue *condition_swizzle =
+         new(base_ir) ir_swizzle(cond_deref->clone(mem_ctx, NULL),
+                                 i, 0, 0, 0, 1);
 
       /* Just clone the rest of the deref chain when trying to get at the
        * underlying variable.
        */
-      swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
-                                       i, 0, 0, 0, 1);
+      ir_rvalue *swizzle =
+        new(base_ir) ir_swizzle(deref_value->clone(mem_ctx, NULL),
+                                i, 0, 0, 0, 1);
 
       deref = new(base_ir) ir_dereference_variable(var);
-      assign = new(base_ir) ir_assignment(deref, swizzle, condition);
-      base_ir->insert_before(assign);
+      assign = new(base_ir) ir_assignment(deref, swizzle, condition_swizzle);
+      list.push_tail(assign);
    }
 
+   /* Put all of the new instructions in the IR stream before the old
+    * instruction.
+    */
+   base_ir->insert_before(&list);
+
    this->progress = true;
    return new(base_ir) ir_dereference_variable(var);
 }
 
+ir_rvalue *
+ir_vec_index_to_cond_assign_visitor::convert_vector_extract_to_cond_assign(ir_rvalue *ir)
+{
+   ir_expression *const expr = ir->as_expression();
+
+   if (expr == NULL || expr->operation != ir_binop_vector_extract)
+      return ir;
+
+   return convert_vec_index_to_cond_assign(ralloc_parent(ir),
+                                           expr->operands[0],
+                                           expr->operands[1],
+                                           ir->type);
+}
+
 ir_visitor_status
 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
 {
    unsigned int i;
 
    for (i = 0; i < ir->get_num_operands(); i++) {
-      ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
+      ir->operands[i] = convert_vector_extract_to_cond_assign(ir->operands[i]);
    }
 
    return visit_continue;
@@ -142,7 +177,7 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
     * the result of indexing a vector is.  But maybe at some point we'll end up
     * using swizzling of scalars for vector construction.
     */
-   ir->val = convert_vec_index_to_cond_assign(ir->val);
+   ir->val = convert_vector_extract_to_cond_assign(ir->val);
 
    return visit_continue;
 }
@@ -150,66 +185,11 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
 ir_visitor_status
 ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
 {
-   ir_variable *index, *var;
-   ir_dereference_variable *deref;
-   ir_assignment *assign;
-   int i;
-
-   ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
-   if (ir->condition)
-      ir->condition = convert_vec_index_to_cond_assign(ir->condition);
-
-   /* Last, handle the LHS */
-   ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
-
-   if (!orig_deref ||
-       orig_deref->array->type->is_matrix() ||
-       orig_deref->array->type->is_array())
-      return visit_continue;
-
-   void *mem_ctx = talloc_parent(ir);
+   ir->rhs = convert_vector_extract_to_cond_assign(ir->rhs);
 
-   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
-
-   /* Store the index to a temporary to avoid reusing its tree. */
-   index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
-                              ir_var_temporary);
-   ir->insert_before(index);
-   deref = new(ir) ir_dereference_variable(index);
-   assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
-   ir->insert_before(assign);
-
-   /* Store the RHS to a temporary to avoid reusing its tree. */
-   var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
-                            ir_var_temporary);
-   ir->insert_before(var);
-   deref = new(ir) ir_dereference_variable(var);
-   assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
-   ir->insert_before(assign);
-
-   /* Generate a conditional move of each vector element to the temp. */
-   for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
-      ir_rvalue *condition, *swizzle;
-
-      deref = new(ir) ir_dereference_variable(index);
-      condition = new(ir) ir_expression(ir_binop_equal,
-                                       glsl_type::bool_type,
-                                       deref,
-                                       new(ir) ir_constant(i));
-
-      /* Just clone the rest of the deref chain when trying to get at the
-       * underlying variable.
-       */
-      swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
-                                  i, 0, 0, 0, 1);
-
-      deref = new(ir) ir_dereference_variable(var);
-      assign = new(ir) ir_assignment(swizzle, deref, condition);
-      ir->insert_before(assign);
+   if (ir->condition) {
+      ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
    }
-   ir->remove();
-
-   this->progress = true;
 
    return visit_continue;
 }
@@ -219,7 +199,7 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
 {
    foreach_iter(exec_list_iterator, iter, *ir) {
       ir_rvalue *param = (ir_rvalue *)iter.get();
-      ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);
+      ir_rvalue *new_param = convert_vector_extract_to_cond_assign(param);
 
       if (new_param != param) {
         param->replace_with(new_param);
@@ -233,7 +213,7 @@ ir_visitor_status
 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
 {
    if (ir->value) {
-      ir->value = convert_vec_index_to_cond_assign(ir->value);
+      ir->value = convert_vector_extract_to_cond_assign(ir->value);
    }
 
    return visit_continue;
@@ -242,7 +222,7 @@ ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
 ir_visitor_status
 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
 {
-   ir->condition = convert_vec_index_to_cond_assign(ir->condition);
+   ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
 
    return visit_continue;
 }