glsl: Rename various ir_* files to lower_* and opt_*.
authorKenneth Graunke <kenneth@whitecape.org>
Mon, 15 Nov 2010 22:35:46 +0000 (14:35 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Tue, 16 Nov 2010 00:34:20 +0000 (16:34 -0800)
This helps distinguish between lowering passes, optimization passes, and
other compiler code.

48 files changed:
src/glsl/Makefile
src/glsl/SConscript
src/glsl/ir_algebraic.cpp [deleted file]
src/glsl/ir_constant_folding.cpp [deleted file]
src/glsl/ir_constant_propagation.cpp [deleted file]
src/glsl/ir_constant_variable.cpp [deleted file]
src/glsl/ir_copy_propagation.cpp [deleted file]
src/glsl/ir_dead_code.cpp [deleted file]
src/glsl/ir_dead_code_local.cpp [deleted file]
src/glsl/ir_dead_functions.cpp [deleted file]
src/glsl/ir_div_to_mul_rcp.cpp [deleted file]
src/glsl/ir_explog_to_explog2.cpp [deleted file]
src/glsl/ir_function_inlining.cpp [deleted file]
src/glsl/ir_if_simplification.cpp [deleted file]
src/glsl/ir_if_to_cond_assign.cpp [deleted file]
src/glsl/ir_lower_jumps.cpp [deleted file]
src/glsl/ir_mat_op_to_vec.cpp [deleted file]
src/glsl/ir_mod_to_fract.cpp [deleted file]
src/glsl/ir_noop_swizzle.cpp [deleted file]
src/glsl/ir_structure_splitting.cpp [deleted file]
src/glsl/ir_sub_to_add_neg.cpp [deleted file]
src/glsl/ir_swizzle_swizzle.cpp [deleted file]
src/glsl/ir_tree_grafting.cpp [deleted file]
src/glsl/ir_vec_index_to_cond_assign.cpp [deleted file]
src/glsl/ir_vec_index_to_swizzle.cpp [deleted file]
src/glsl/lower_div_to_mul_rcp.cpp [new file with mode: 0644]
src/glsl/lower_explog_to_explog2.cpp [new file with mode: 0644]
src/glsl/lower_if_to_cond_assign.cpp [new file with mode: 0644]
src/glsl/lower_jumps.cpp [new file with mode: 0644]
src/glsl/lower_mat_op_to_vec.cpp [new file with mode: 0644]
src/glsl/lower_mod_to_fract.cpp [new file with mode: 0644]
src/glsl/lower_sub_to_add_neg.cpp [new file with mode: 0644]
src/glsl/lower_vec_index_to_cond_assign.cpp [new file with mode: 0644]
src/glsl/lower_vec_index_to_swizzle.cpp [new file with mode: 0644]
src/glsl/opt_algebraic.cpp [new file with mode: 0644]
src/glsl/opt_constant_folding.cpp [new file with mode: 0644]
src/glsl/opt_constant_propagation.cpp [new file with mode: 0644]
src/glsl/opt_constant_variable.cpp [new file with mode: 0644]
src/glsl/opt_copy_propagation.cpp [new file with mode: 0644]
src/glsl/opt_dead_code.cpp [new file with mode: 0644]
src/glsl/opt_dead_code_local.cpp [new file with mode: 0644]
src/glsl/opt_dead_functions.cpp [new file with mode: 0644]
src/glsl/opt_function_inlining.cpp [new file with mode: 0644]
src/glsl/opt_if_simplification.cpp [new file with mode: 0644]
src/glsl/opt_noop_swizzle.cpp [new file with mode: 0644]
src/glsl/opt_structure_splitting.cpp [new file with mode: 0644]
src/glsl/opt_swizzle_swizzle.cpp [new file with mode: 0644]
src/glsl/opt_tree_grafting.cpp [new file with mode: 0644]

index 4cfecb130f2c3e62ebf7796fdeb60bb31a92924c..62984f81c0a75a9cc021bb9305e89eea47df33b6 100644 (file)
@@ -30,55 +30,55 @@ CXX_SOURCES = \
        glsl_types.cpp \
        glsl_symbol_table.cpp \
        hir_field_selection.cpp \
-       ir_algebraic.cpp \
        ir_basic_block.cpp \
        ir_clone.cpp \
        ir_constant_expression.cpp \
-       ir_constant_folding.cpp \
-       ir_constant_propagation.cpp \
-       ir_constant_variable.cpp \
-       ir_copy_propagation.cpp \
        ir.cpp \
-       ir_dead_code.cpp \
-       ir_dead_code_local.cpp \
-       ir_dead_functions.cpp \
-       ir_div_to_mul_rcp.cpp \
-       ir_explog_to_explog2.cpp \
        ir_expression_flattening.cpp \
        ir_function_can_inline.cpp \
        ir_function.cpp \
-       ir_function_inlining.cpp \
        ir_hierarchical_visitor.cpp \
        ir_hv_accept.cpp \
-       ir_if_simplification.cpp \
-       ir_if_to_cond_assign.cpp \
        ir_import_prototypes.cpp \
-       ir_lower_jumps.cpp \
-       ir_mat_op_to_vec.cpp \
-       ir_mod_to_fract.cpp \
-       ir_noop_swizzle.cpp \
        ir_print_visitor.cpp \
        ir_reader.cpp \
        ir_rvalue_visitor.cpp \
        ir_set_program_inouts.cpp \
-       ir_structure_splitting.cpp \
-       ir_sub_to_add_neg.cpp \
-       ir_swizzle_swizzle.cpp \
-       ir_tree_grafting.cpp \
        ir_validate.cpp \
        ir_variable.cpp \
        ir_variable_refcount.cpp \
-       ir_vec_index_to_cond_assign.cpp \
-       ir_vec_index_to_swizzle.cpp \
        linker.cpp \
        link_functions.cpp \
        loop_analysis.cpp \
        loop_controls.cpp \
        loop_unroll.cpp \
+       lower_div_to_mul_rcp.cpp \
+       lower_explog_to_explog2.cpp \
+       lower_if_to_cond_assign.cpp \
+       lower_jumps.cpp \
+       lower_mat_op_to_vec.cpp \
+       lower_mod_to_fract.cpp \
        lower_noise.cpp \
+       lower_sub_to_add_neg.cpp \
        lower_texture_projection.cpp \
        lower_variable_index_to_cond_assign.cpp \
+       lower_vec_index_to_cond_assign.cpp \
+       lower_vec_index_to_swizzle.cpp \
+       opt_algebraic.cpp \
+       opt_constant_folding.cpp \
+       opt_constant_propagation.cpp \
+       opt_constant_variable.cpp \
+       opt_copy_propagation.cpp \
+       opt_dead_code.cpp \
+       opt_dead_code_local.cpp \
+       opt_dead_functions.cpp \
+       opt_function_inlining.cpp \
+       opt_if_simplification.cpp \
+       opt_noop_swizzle.cpp \
        opt_redundant_jumps.cpp \
+       opt_structure_splitting.cpp \
+       opt_swizzle_swizzle.cpp \
+       opt_tree_grafting.cpp \
        s_expression.cpp
 
 LIBS = \
index c183e208d6358c6366c0a7e55d3fdbce67173b4f..f9cc823a2d5201367e8611e28d0c9f4e5f1b9665 100644 (file)
@@ -27,54 +27,54 @@ sources = [
     'glsl_types.cpp',
     'glsl_symbol_table.cpp',
     'hir_field_selection.cpp',
-    'ir_algebraic.cpp',
     'ir_basic_block.cpp',
     'ir_clone.cpp',
-    'ir_constant_expression.cpp',
-    'ir_constant_folding.cpp',
-    'ir_constant_propagation.cpp',
-    'ir_constant_variable.cpp',
-    'ir_copy_propagation.cpp',
     'ir.cpp',
-    'ir_dead_code.cpp',
-    'ir_dead_code_local.cpp',
-    'ir_dead_functions.cpp',
-    'ir_div_to_mul_rcp.cpp',
-    'ir_explog_to_explog2.cpp',
     'ir_expression_flattening.cpp',
     'ir_function_can_inline.cpp',
     'ir_function.cpp',
-    'ir_function_inlining.cpp',
     'ir_hierarchical_visitor.cpp',
     'ir_hv_accept.cpp',
-    'ir_if_simplification.cpp',
-    'ir_if_to_cond_assign.cpp',
     'ir_import_prototypes.cpp',
-    'ir_lower_jumps.cpp',
-    'ir_mat_op_to_vec.cpp',
-    'ir_mod_to_fract.cpp',
-    'ir_noop_swizzle.cpp',
     'ir_print_visitor.cpp',
     'ir_reader.cpp',
     'ir_rvalue_visitor.cpp',
     'ir_set_program_inouts.cpp',
-    'ir_structure_splitting.cpp',
-    'ir_sub_to_add_neg.cpp',
-    'ir_swizzle_swizzle.cpp',
-    'ir_tree_grafting.cpp',
     'ir_validate.cpp',
     'ir_variable.cpp',
     'ir_variable_refcount.cpp',
-    'ir_vec_index_to_cond_assign.cpp',
-    'ir_vec_index_to_swizzle.cpp',
     'linker.cpp',
     'link_functions.cpp',
     'loop_analysis.cpp',
     'loop_controls.cpp',
     'loop_unroll.cpp',
+    'lower_div_to_mul_rcp.cpp',
+    'lower_explog_to_explog2.cpp',
+    'lower_if_to_cond_assign.cpp',
+    'lower_jumps.cpp',
+    'lower_mat_op_to_vec.cpp',
+    'lower_mod_to_fract.cpp',
     'lower_noise.cpp',
+    'lower_sub_to_add_neg.cpp',
     'lower_variable_index_to_cond_assign.cpp',
+    'lower_vec_index_to_cond_assign.cpp',
+    'lower_vec_index_to_swizzle.cpp',
+    'opt_algebraic.cpp',
+    'opt_constant_folding.cpp',
+    'opt_noop_swizzle.cpp',
     'opt_redundant_jumps.cpp',
+    'opt_constant_expression.cpp',
+    'opt_constant_propagation.cpp',
+    'opt_constant_variable.cpp',
+    'opt_copy_propagation.cpp',
+    'opt_dead_code.cpp',
+    'opt_dead_code_local.cpp',
+    'opt_dead_functions.cpp',
+    'opt_function_inlining.cpp',
+    'opt_if_simplification.cpp',
+    'opt_structure_splitting.cpp',
+    'opt_swizzle_swizzle.cpp',
+    'opt_tree_grafting.cpp',
     's_expression.cpp',
 ]
 
diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp
deleted file mode 100644 (file)
index 2ed66db..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_algebraic.cpp
- *
- * Takes advantage of association, commutivity, and other algebraic
- * properties to simplify expressions.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_algebraic_visitor : public ir_rvalue_visitor {
-public:
-   ir_algebraic_visitor()
-   {
-      this->progress = false;
-      this->mem_ctx = NULL;
-   }
-
-   virtual ~ir_algebraic_visitor()
-   {
-   }
-
-   ir_rvalue *handle_expression(ir_expression *ir);
-   void handle_rvalue(ir_rvalue **rvalue);
-   bool reassociate_constant(ir_expression *ir1,
-                            int const_index,
-                            ir_constant *constant,
-                            ir_expression *ir2);
-   void reassociate_operands(ir_expression *ir1,
-                            int op1,
-                            ir_expression *ir2,
-                            int op2);
-   ir_rvalue *swizzle_if_required(ir_expression *expr,
-                                 ir_rvalue *operand);
-
-   void *mem_ctx;
-
-   bool progress;
-};
-
-static bool
-is_vec_zero(ir_constant *ir)
-{
-   int c;
-
-   if (!ir)
-      return false;
-   if (!ir->type->is_scalar() &&
-       !ir->type->is_vector())
-      return false;
-
-   for (c = 0; c < ir->type->vector_elements; c++) {
-      switch (ir->type->base_type) {
-      case GLSL_TYPE_FLOAT:
-        if (ir->value.f[c] != 0.0)
-           return false;
-        break;
-      case GLSL_TYPE_INT:
-        if (ir->value.i[c] != 0)
-           return false;
-        break;
-      case GLSL_TYPE_UINT:
-        if (ir->value.u[c] != 0)
-           return false;
-        break;
-      case GLSL_TYPE_BOOL:
-        if (ir->value.b[c] != false)
-           return false;
-        break;
-      default:
-        assert(!"bad base type");
-        return false;
-      }
-   }
-
-   return true;
-}
-
-static bool
-is_vec_one(ir_constant *ir)
-{
-   int c;
-
-   if (!ir)
-      return false;
-   if (!ir->type->is_scalar() &&
-       !ir->type->is_vector())
-      return false;
-
-   for (c = 0; c < ir->type->vector_elements; c++) {
-      switch (ir->type->base_type) {
-      case GLSL_TYPE_FLOAT:
-        if (ir->value.f[c] != 1.0)
-           return false;
-        break;
-      case GLSL_TYPE_INT:
-        if (ir->value.i[c] != 1)
-           return false;
-        break;
-      case GLSL_TYPE_UINT:
-        if (ir->value.u[c] != 1)
-           return false;
-        break;
-      case GLSL_TYPE_BOOL:
-        if (ir->value.b[c] != true)
-           return false;
-        break;
-      default:
-        assert(!"bad base type");
-        return false;
-      }
-   }
-
-   return true;
-}
-
-static void
-update_type(ir_expression *ir)
-{
-   if (ir->operands[0]->type->is_vector())
-      ir->type = ir->operands[0]->type;
-   else
-      ir->type = ir->operands[1]->type;
-}
-
-void
-ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
-                                          int op1,
-                                          ir_expression *ir2,
-                                          int op2)
-{
-   ir_rvalue *temp = ir2->operands[op2];
-   ir2->operands[op2] = ir1->operands[op1];
-   ir1->operands[op1] = temp;
-
-   /* Update the type of ir2.  The type of ir1 won't have changed --
-    * base types matched, and at least one of the operands of the 2
-    * binops is still a vector if any of them were.
-    */
-   update_type(ir2);
-
-   this->progress = true;
-}
-
-/**
- * Reassociates a constant down a tree of adds or multiplies.
- *
- * Consider (2 * (a * (b * 0.5))).  We want to send up with a * b.
- */
-bool
-ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
-                                          ir_constant *constant,
-                                          ir_expression *ir2)
-{
-   if (!ir2 || ir1->operation != ir2->operation)
-      return false;
-
-   /* Don't want to even think about matrices. */
-   if (ir1->operands[0]->type->is_matrix() ||
-       ir1->operands[0]->type->is_matrix() ||
-       ir2->operands[1]->type->is_matrix() ||
-       ir2->operands[1]->type->is_matrix())
-      return false;
-
-   ir_constant *ir2_const[2];
-   ir2_const[0] = ir2->operands[0]->constant_expression_value();
-   ir2_const[1] = ir2->operands[1]->constant_expression_value();
-
-   if (ir2_const[0] && ir2_const[1])
-      return false;
-
-   if (ir2_const[0]) {
-      reassociate_operands(ir1, const_index, ir2, 1);
-      return true;
-   } else if (ir2_const[1]) {
-      reassociate_operands(ir1, const_index, ir2, 0);
-      return true;
-   }
-
-   if (reassociate_constant(ir1, const_index, constant,
-                           ir2->operands[0]->as_expression())) {
-      update_type(ir2);
-      return true;
-   }
-
-   if (reassociate_constant(ir1, const_index, constant,
-                           ir2->operands[1]->as_expression())) {
-      update_type(ir2);
-      return true;
-   }
-
-   return false;
-}
-
-/* When eliminating an expression and just returning one of its operands,
- * we may need to swizzle that operand out to a vector if the expression was
- * vector type.
- */
-ir_rvalue *
-ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
-                                         ir_rvalue *operand)
-{
-   if (expr->type->is_vector() && operand->type->is_scalar()) {
-      return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0,
-                                    expr->type->vector_elements);
-   } else
-      return operand;
-}
-
-ir_rvalue *
-ir_algebraic_visitor::handle_expression(ir_expression *ir)
-{
-   ir_constant *op_const[2] = {NULL, NULL};
-   ir_expression *op_expr[2] = {NULL, NULL};
-   ir_expression *temp;
-   unsigned int i;
-
-   for (i = 0; i < ir->get_num_operands(); i++) {
-      if (ir->operands[i]->type->is_matrix())
-        return ir;
-
-      op_const[i] = ir->operands[i]->constant_expression_value();
-      op_expr[i] = ir->operands[i]->as_expression();
-   }
-
-   if (this->mem_ctx == NULL)
-      this->mem_ctx = talloc_parent(ir);
-
-   switch (ir->operation) {
-   case ir_unop_logic_not: {
-      enum ir_expression_operation new_op = ir_unop_logic_not;
-
-      if (op_expr[0] == NULL)
-        break;
-
-      switch (op_expr[0]->operation) {
-      case ir_binop_less:    new_op = ir_binop_gequal;  break;
-      case ir_binop_greater: new_op = ir_binop_lequal;  break;
-      case ir_binop_lequal:  new_op = ir_binop_greater; break;
-      case ir_binop_gequal:  new_op = ir_binop_less;    break;
-      case ir_binop_equal:   new_op = ir_binop_nequal;  break;
-      case ir_binop_nequal:  new_op = ir_binop_equal;   break;
-      case ir_binop_all_equal:   new_op = ir_binop_any_nequal;  break;
-      case ir_binop_any_nequal:  new_op = ir_binop_all_equal;   break;
-
-      default:
-        /* The default case handler is here to silence a warning from GCC.
-         */
-        break;
-      }
-
-      if (new_op != ir_unop_logic_not) {
-        this->progress = true;
-        return new(mem_ctx) ir_expression(new_op,
-                                          ir->type,
-                                          op_expr[0]->operands[0],
-                                          op_expr[0]->operands[1]);
-      }
-
-      break;
-   }
-
-   case ir_binop_add:
-      if (is_vec_zero(op_const[0])) {
-        this->progress = true;
-        return swizzle_if_required(ir, ir->operands[1]);
-      }
-      if (is_vec_zero(op_const[1])) {
-        this->progress = true;
-        return swizzle_if_required(ir, ir->operands[0]);
-      }
-
-      /* Reassociate addition of constants so that we can do constant
-       * folding.
-       */
-      if (op_const[0] && !op_const[1])
-        reassociate_constant(ir, 0, op_const[0],
-                             ir->operands[1]->as_expression());
-      if (op_const[1] && !op_const[0])
-        reassociate_constant(ir, 1, op_const[1],
-                             ir->operands[0]->as_expression());
-      break;
-
-   case ir_binop_sub:
-      if (is_vec_zero(op_const[0])) {
-        this->progress = true;
-        temp = new(mem_ctx) ir_expression(ir_unop_neg,
-                                          ir->operands[1]->type,
-                                          ir->operands[1],
-                                          NULL);
-        return swizzle_if_required(ir, temp);
-      }
-      if (is_vec_zero(op_const[1])) {
-        this->progress = true;
-        return swizzle_if_required(ir, ir->operands[0]);
-      }
-      break;
-
-   case ir_binop_mul:
-      if (is_vec_one(op_const[0])) {
-        this->progress = true;
-        return swizzle_if_required(ir, ir->operands[1]);
-      }
-      if (is_vec_one(op_const[1])) {
-        this->progress = true;
-        return swizzle_if_required(ir, ir->operands[0]);
-      }
-
-      if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
-        this->progress = true;
-        return ir_constant::zero(ir, ir->type);
-      }
-
-      /* Reassociate multiplication of constants so that we can do
-       * constant folding.
-       */
-      if (op_const[0] && !op_const[1])
-        reassociate_constant(ir, 0, op_const[0],
-                             ir->operands[1]->as_expression());
-      if (op_const[1] && !op_const[0])
-        reassociate_constant(ir, 1, op_const[1],
-                             ir->operands[0]->as_expression());
-
-      break;
-
-   case ir_binop_div:
-      if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
-        this->progress = true;
-        temp = new(mem_ctx) ir_expression(ir_unop_rcp,
-                                          ir->operands[1]->type,
-                                          ir->operands[1],
-                                          NULL);
-        return swizzle_if_required(ir, temp);
-      }
-      if (is_vec_one(op_const[1])) {
-        this->progress = true;
-        return swizzle_if_required(ir, ir->operands[0]);
-      }
-      break;
-
-   case ir_binop_logic_and:
-      /* FINISHME: Also simplify (a && a) to (a). */
-      if (is_vec_one(op_const[0])) {
-        this->progress = true;
-        return ir->operands[1];
-      } else if (is_vec_one(op_const[1])) {
-        this->progress = true;
-        return ir->operands[0];
-      } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
-        this->progress = true;
-        return ir_constant::zero(mem_ctx, ir->type);
-      }
-      break;
-
-   case ir_binop_logic_xor:
-      /* FINISHME: Also simplify (a ^^ a) to (false). */
-      if (is_vec_zero(op_const[0])) {
-        this->progress = true;
-        return ir->operands[1];
-      } else if (is_vec_zero(op_const[1])) {
-        this->progress = true;
-        return ir->operands[0];
-      } else if (is_vec_one(op_const[0])) {
-        this->progress = true;
-        return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
-                                          ir->operands[1], NULL);
-      } else if (is_vec_one(op_const[1])) {
-        this->progress = true;
-        return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
-                                          ir->operands[0], NULL);
-      }
-      break;
-
-   case ir_binop_logic_or:
-      /* FINISHME: Also simplify (a || a) to (a). */
-      if (is_vec_zero(op_const[0])) {
-        this->progress = true;
-        return ir->operands[1];
-      } else if (is_vec_zero(op_const[1])) {
-        this->progress = true;
-        return ir->operands[0];
-      } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) {
-        ir_constant_data data;
-
-        for (unsigned i = 0; i < 16; i++)
-           data.b[i] = true;
-
-        this->progress = true;
-        return new(mem_ctx) ir_constant(ir->type, &data);
-      }
-      break;
-
-   case ir_unop_rcp:
-      if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) {
-        this->progress = true;
-        return op_expr[0]->operands[0];
-      }
-
-      /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
-       * backends, except that some backends will have done sqrt ->
-       * rcp(rsq(x)) and we don't want to undo it for them.
-       */
-
-      /* As far as we know, all backends are OK with rsq. */
-      if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) {
-        this->progress = true;
-        temp = new(mem_ctx) ir_expression(ir_unop_rsq,
-                                          op_expr[0]->operands[0]->type,
-                                          op_expr[0]->operands[0],
-                                          NULL);
-        return swizzle_if_required(ir, temp);
-      }
-
-      break;
-
-   default:
-      break;
-   }
-
-   return ir;
-}
-
-void
-ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
-   if (!*rvalue)
-      return;
-
-   ir_expression *expr = (*rvalue)->as_expression();
-   if (!expr)
-      return;
-
-   *rvalue = handle_expression(expr);
-}
-
-bool
-do_algebraic(exec_list *instructions)
-{
-   ir_algebraic_visitor v;
-
-   visit_list_elements(&v, instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_constant_folding.cpp b/src/glsl/ir_constant_folding.cpp
deleted file mode 100644 (file)
index 554c54f..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_constant_folding.cpp
- * Replace constant-valued expressions with references to constant values.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_constant_folding_visitor : public ir_rvalue_visitor {
-public:
-   ir_constant_folding_visitor()
-   {
-      this->progress = false;
-   }
-
-   virtual ~ir_constant_folding_visitor()
-   {
-      /* empty */
-   }
-
-   virtual ir_visitor_status visit_enter(ir_assignment *ir);
-   virtual ir_visitor_status visit_enter(ir_call *ir);
-
-   virtual void handle_rvalue(ir_rvalue **rvalue);
-
-   bool progress;
-};
-
-void
-ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
-   if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant)
-      return;
-
-   /* Note that we do rvalue visitoring on leaving.  So if an
-    * expression has a non-constant operand, no need to go looking
-    * down it to find if it's constant.  This cuts the time of this
-    * pass down drastically.
-    */
-   ir_expression *expr = (*rvalue)->as_expression();
-   if (expr) {
-      for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
-        if (!expr->operands[i]->as_constant())
-           return;
-      }
-   }
-
-   ir_constant *constant = (*rvalue)->constant_expression_value();
-   if (constant) {
-      *rvalue = constant;
-      this->progress = true;
-   } else {
-      (*rvalue)->accept(this);
-   }
-}
-
-ir_visitor_status
-ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
-{
-   ir->rhs->accept(this);
-   handle_rvalue(&ir->rhs);
-
-   if (ir->condition) {
-      ir->condition->accept(this);
-      handle_rvalue(&ir->condition);
-
-      ir_constant *const_val = ir->condition->as_constant();
-      /* If the condition is constant, either remove the condition or
-       * remove the never-executed assignment.
-       */
-      if (const_val) {
-        if (const_val->value.b[0])
-           ir->condition = NULL;
-        else
-           ir->remove();
-        this->progress = true;
-      }
-   }
-
-   /* Don't descend into the LHS because we want it to stay as a
-    * variable dereference.  FINISHME: We probably should to get array
-    * indices though.
-    */
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_folding_visitor::visit_enter(ir_call *ir)
-{
-   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
-   foreach_iter(exec_list_iterator, iter, *ir) {
-      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
-      ir_variable *sig_param = (ir_variable *)sig_iter.get();
-
-      if (sig_param->mode == ir_var_in) {
-        ir_rvalue *new_param = param_rval;
-
-        handle_rvalue(&new_param);
-        if (new_param != param_rval) {
-           param_rval->replace_with(new_param);
-        }
-      }
-      sig_iter.next();
-   }
-
-   return visit_continue_with_parent;
-}
-
-bool
-do_constant_folding(exec_list *instructions)
-{
-   ir_constant_folding_visitor constant_folding;
-
-   visit_list_elements(&constant_folding, instructions);
-
-   return constant_folding.progress;
-}
diff --git a/src/glsl/ir_constant_propagation.cpp b/src/glsl/ir_constant_propagation.cpp
deleted file mode 100644 (file)
index 5d875b7..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * constant of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, constant, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above constantright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR CONSTANTRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_constant_propagation.cpp
- *
- * Tracks assignments of constants to channels of variables, and
- * usage of those constant channels with direct usage of the constants.
- *
- * This can lead to constant folding and algebraic optimizations in
- * those later expressions, while causing no increase in instruction
- * count (due to constants being generally free to load from a
- * constant push buffer or as instruction immediate values) and
- * possibly reducing register pressure.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-class acp_entry : public exec_node
-{
-public:
-   acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
-   {
-      assert(var);
-      assert(constant);
-      this->var = var;
-      this->write_mask = write_mask;
-      this->constant = constant;
-   }
-
-   ir_variable *var;
-   ir_constant *constant;
-   unsigned write_mask;
-};
-
-
-class kill_entry : public exec_node
-{
-public:
-   kill_entry(ir_variable *var, unsigned write_mask)
-   {
-      assert(var);
-      this->var = var;
-      this->write_mask = write_mask;
-   }
-
-   ir_variable *var;
-   unsigned write_mask;
-};
-
-class ir_constant_propagation_visitor : public ir_rvalue_visitor {
-public:
-   ir_constant_propagation_visitor()
-   {
-      progress = false;
-      mem_ctx = talloc_new(0);
-      this->acp = new(mem_ctx) exec_list;
-      this->kills = new(mem_ctx) exec_list;
-   }
-   ~ir_constant_propagation_visitor()
-   {
-      talloc_free(mem_ctx);
-   }
-
-   virtual ir_visitor_status visit_enter(class ir_loop *);
-   virtual ir_visitor_status visit_enter(class ir_function_signature *);
-   virtual ir_visitor_status visit_enter(class ir_function *);
-   virtual ir_visitor_status visit_leave(class ir_assignment *);
-   virtual ir_visitor_status visit_enter(class ir_call *);
-   virtual ir_visitor_status visit_enter(class ir_if *);
-
-   void add_constant(ir_assignment *ir);
-   void kill(ir_variable *ir, unsigned write_mask);
-   void handle_if_block(exec_list *instructions);
-   void handle_rvalue(ir_rvalue **rvalue);
-
-   /** List of acp_entry: The available constants to propagate */
-   exec_list *acp;
-
-   /**
-    * List of kill_entry: The masks of variables whose values were
-    * killed in this block.
-    */
-   exec_list *kills;
-
-   bool progress;
-
-   bool killed_all;
-
-   void *mem_ctx;
-};
-
-
-void
-ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
-   if (this->in_assignee || !*rvalue)
-      return;
-
-   const glsl_type *type = (*rvalue)->type;
-   if (!type->is_scalar() && !type->is_vector())
-      return;
-
-   ir_swizzle *swiz = NULL;
-   ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
-   if (!deref) {
-      swiz = (*rvalue)->as_swizzle();
-      if (!swiz)
-        return;
-
-      deref = swiz->val->as_dereference_variable();
-      if (!deref)
-        return;
-   }
-
-   ir_constant_data data;
-   memset(&data, 0, sizeof(data));
-
-   for (unsigned int i = 0; i < type->components(); i++) {
-      int channel;
-      acp_entry *found = NULL;
-
-      if (swiz) {
-        switch (i) {
-        case 0: channel = swiz->mask.x; break;
-        case 1: channel = swiz->mask.y; break;
-        case 2: channel = swiz->mask.z; break;
-        case 3: channel = swiz->mask.w; break;
-        default: assert(!"shouldn't be reached"); channel = 0; break;
-        }
-      } else {
-        channel = i;
-      }
-
-      foreach_iter(exec_list_iterator, iter, *this->acp) {
-        acp_entry *entry = (acp_entry *)iter.get();
-        if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
-           found = entry;
-           break;
-        }
-      }
-
-      if (!found)
-        return;
-
-      int rhs_channel = 0;
-      for (int j = 0; j < 4; j++) {
-        if (j == channel)
-           break;
-        if (found->write_mask & (1 << j))
-           rhs_channel++;
-      }
-
-      switch (type->base_type) {
-      case GLSL_TYPE_FLOAT:
-        data.f[i] = found->constant->value.f[rhs_channel];
-        break;
-      case GLSL_TYPE_INT:
-        data.i[i] = found->constant->value.i[rhs_channel];
-        break;
-      case GLSL_TYPE_UINT:
-        data.u[i] = found->constant->value.u[rhs_channel];
-        break;
-      case GLSL_TYPE_BOOL:
-        data.b[i] = found->constant->value.b[rhs_channel];
-        break;
-      default:
-        assert(!"not reached");
-        break;
-      }
-   }
-
-   *rvalue = new(talloc_parent(deref)) ir_constant(type, &data);
-   this->progress = true;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
-{
-   /* Treat entry into a function signature as a completely separate
-    * block.  Any instructions at global scope will be shuffled into
-    * main() at link time, so they're irrelevant to us.
-    */
-   exec_list *orig_acp = this->acp;
-   exec_list *orig_kills = this->kills;
-   bool orig_killed_all = this->killed_all;
-
-   this->acp = new(mem_ctx) exec_list;
-   this->kills = new(mem_ctx) exec_list;
-   this->killed_all = false;
-
-   visit_list_elements(this, &ir->body);
-
-   this->kills = orig_kills;
-   this->acp = orig_acp;
-   this->killed_all = orig_killed_all;
-
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
-{
-   if (this->in_assignee)
-      return visit_continue;
-
-   kill(ir->lhs->variable_referenced(), ir->write_mask);
-
-   add_constant(ir);
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_function *ir)
-{
-   (void) ir;
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_call *ir)
-{
-   /* Do constant propagation on call parameters, but skip any out params */
-   exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
-   foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
-      ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
-      ir_rvalue *param = (ir_rvalue *)iter.get();
-      if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
-        ir_rvalue *new_param = param;
-        handle_rvalue(&new_param);
-         if (new_param != param)
-           param->replace_with(new_param);
-        else
-           param->accept(this);
-      }
-      sig_param_iter.next();
-   }
-
-   /* Since we're unlinked, we don't (necssarily) know the side effects of
-    * this call.  So kill all copies.
-    */
-   acp->make_empty();
-   this->killed_all = true;
-
-   return visit_continue_with_parent;
-}
-
-void
-ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
-{
-   exec_list *orig_acp = this->acp;
-   exec_list *orig_kills = this->kills;
-   bool orig_killed_all = this->killed_all;
-
-   this->acp = new(mem_ctx) exec_list;
-   this->kills = new(mem_ctx) exec_list;
-   this->killed_all = false;
-
-   /* Populate the initial acp with a constant of the original */
-   foreach_iter(exec_list_iterator, iter, *orig_acp) {
-      acp_entry *a = (acp_entry *)iter.get();
-      this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask,
-                                                       a->constant));
-   }
-
-   visit_list_elements(this, instructions);
-
-   if (this->killed_all) {
-      orig_acp->make_empty();
-   }
-
-   exec_list *new_kills = this->kills;
-   this->kills = orig_kills;
-   this->acp = orig_acp;
-   this->killed_all = this->killed_all || orig_killed_all;
-
-   foreach_iter(exec_list_iterator, iter, *new_kills) {
-      kill_entry *k = (kill_entry *)iter.get();
-      kill(k->var, k->write_mask);
-   }
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_if *ir)
-{
-   ir->condition->accept(this);
-   handle_rvalue(&ir->condition);
-
-   handle_if_block(&ir->then_instructions);
-   handle_if_block(&ir->else_instructions);
-
-   /* handle_if_block() already descended into the children. */
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
-{
-   exec_list *orig_acp = this->acp;
-   exec_list *orig_kills = this->kills;
-   bool orig_killed_all = this->killed_all;
-
-   /* FINISHME: For now, the initial acp for loops is totally empty.
-    * We could go through once, then go through again with the acp
-    * cloned minus the killed entries after the first run through.
-    */
-   this->acp = new(mem_ctx) exec_list;
-   this->kills = new(mem_ctx) exec_list;
-   this->killed_all = false;
-
-   visit_list_elements(this, &ir->body_instructions);
-
-   if (this->killed_all) {
-      orig_acp->make_empty();
-   }
-
-   exec_list *new_kills = this->kills;
-   this->kills = orig_kills;
-   this->acp = orig_acp;
-   this->killed_all = this->killed_all || orig_killed_all;
-
-   foreach_iter(exec_list_iterator, iter, *new_kills) {
-      kill_entry *k = (kill_entry *)iter.get();
-      kill(k->var, k->write_mask);
-   }
-
-   /* already descended into the children. */
-   return visit_continue_with_parent;
-}
-
-void
-ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
-{
-   assert(var != NULL);
-
-   /* We don't track non-vectors. */
-   if (!var->type->is_vector() && !var->type->is_scalar())
-      return;
-
-   /* Remove any entries currently in the ACP for this kill. */
-   foreach_iter(exec_list_iterator, iter, *this->acp) {
-      acp_entry *entry = (acp_entry *)iter.get();
-
-      if (entry->var == var) {
-        entry->write_mask &= ~write_mask;
-        if (entry->write_mask == 0)
-           entry->remove();
-      }
-   }
-
-   /* Add this writemask of the variable to the list of killed
-    * variables in this block.
-    */
-   foreach_iter(exec_list_iterator, iter, *this->kills) {
-      kill_entry *entry = (kill_entry *)iter.get();
-
-      if (entry->var == var) {
-        entry->write_mask |= write_mask;
-        return;
-      }
-   }
-   /* Not already in the list.  Make new entry. */
-   this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
-}
-
-/**
- * Adds an entry to the available constant list if it's a plain assignment
- * of a variable to a variable.
- */
-void
-ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
-{
-   acp_entry *entry;
-
-   if (ir->condition) {
-      ir_constant *condition = ir->condition->as_constant();
-      if (!condition || !condition->value.b[0])
-        return;
-   }
-
-   if (!ir->write_mask)
-      return;
-
-   ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
-   ir_constant *constant = ir->rhs->as_constant();
-
-   if (!deref || !constant)
-      return;
-
-   /* Only do constant propagation on vectors.  Constant matrices,
-    * arrays, or structures would require more work elsewhere.
-    */
-   if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
-      return;
-
-   entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
-   this->acp->push_tail(entry);
-}
-
-/**
- * Does a constant propagation pass on the code present in the instruction stream.
- */
-bool
-do_constant_propagation(exec_list *instructions)
-{
-   ir_constant_propagation_visitor v;
-
-   visit_list_elements(&v, instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_constant_variable.cpp b/src/glsl/ir_constant_variable.cpp
deleted file mode 100644 (file)
index 1fb73e7..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_constant_variable.cpp
- *
- * Marks variables assigned a single constant value over the course
- * of the program as constant.
- *
- * The goal here is to trigger further constant folding and then dead
- * code elimination.  This is common with vector/matrix constructors
- * and calls to builtin functions.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-struct assignment_entry {
-   exec_node link;
-   int assignment_count;
-   ir_variable *var;
-   ir_constant *constval;
-   bool our_scope;
-};
-
-class ir_constant_variable_visitor : public ir_hierarchical_visitor {
-public:
-   virtual ir_visitor_status visit_enter(ir_dereference_variable *);
-   virtual ir_visitor_status visit(ir_variable *);
-   virtual ir_visitor_status visit_enter(ir_assignment *);
-   virtual ir_visitor_status visit_enter(ir_call *);
-
-   exec_list list;
-};
-
-static struct assignment_entry *
-get_assignment_entry(ir_variable *var, exec_list *list)
-{
-   struct assignment_entry *entry;
-
-   foreach_list_typed(struct assignment_entry, entry, link, list) {
-      if (entry->var == var)
-        return entry;
-   }
-
-   entry = (struct assignment_entry *)calloc(1, sizeof(*entry));
-   entry->var = var;
-   list->push_head(&entry->link);
-   return entry;
-}
-
-ir_visitor_status
-ir_constant_variable_visitor::visit(ir_variable *ir)
-{
-   struct assignment_entry *entry = get_assignment_entry(ir, &this->list);
-   entry->our_scope = true;
-   return visit_continue;
-}
-
-/* Skip derefs of variables so that we can detect declarations. */
-ir_visitor_status
-ir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir)
-{
-   (void)ir;
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
-{
-   ir_constant *constval;
-   struct assignment_entry *entry;
-
-   entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list);
-   assert(entry);
-   entry->assignment_count++;
-
-   /* If it's already constant, don't do the work. */
-   if (entry->var->constant_value)
-      return visit_continue;
-
-   /* OK, now find if we actually have all the right conditions for
-    * this to be a constant value assigned to the var.
-    */
-   if (ir->condition) {
-      constval = ir->condition->constant_expression_value();
-      if (!constval || !constval->value.b[0])
-        return visit_continue;
-   }
-
-   ir_variable *var = ir->whole_variable_written();
-   if (!var)
-      return visit_continue;
-
-   constval = ir->rhs->constant_expression_value();
-   if (!constval)
-      return visit_continue;
-
-   /* Mark this entry as having a constant assignment (if the
-    * assignment count doesn't go >1).  do_constant_variable will fix
-    * up the variable with the constant value later.
-    */
-   entry->constval = constval;
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_constant_variable_visitor::visit_enter(ir_call *ir)
-{
-   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
-   foreach_iter(exec_list_iterator, iter, *ir) {
-      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
-      ir_variable *param = (ir_variable *)sig_iter.get();
-
-      if (param->mode == ir_var_out ||
-         param->mode == ir_var_inout) {
-        ir_variable *var = param_rval->variable_referenced();
-        struct assignment_entry *entry;
-
-        assert(var);
-        entry = get_assignment_entry(var, &this->list);
-        entry->assignment_count++;
-      }
-      sig_iter.next();
-   }
-   return visit_continue;
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_constant_variable(exec_list *instructions)
-{
-   bool progress = false;
-   ir_constant_variable_visitor v;
-
-   v.run(instructions);
-
-   while (!v.list.is_empty()) {
-
-      struct assignment_entry *entry;
-      entry = exec_node_data(struct assignment_entry, v.list.head, link);
-
-      if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
-        entry->var->constant_value = entry->constval;
-        progress = true;
-      }
-      entry->link.remove();
-      free(entry);
-   }
-
-   return progress;
-}
-
-bool
-do_constant_variable_unlinked(exec_list *instructions)
-{
-   bool progress = false;
-
-   foreach_iter(exec_list_iterator, iter, *instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
-      ir_function *f = ir->as_function();
-      if (f) {
-        foreach_iter(exec_list_iterator, sigiter, *f) {
-           ir_function_signature *sig =
-              (ir_function_signature *) sigiter.get();
-           if (do_constant_variable(&sig->body))
-              progress = true;
-        }
-      }
-   }
-
-   return progress;
-}
diff --git a/src/glsl/ir_copy_propagation.cpp b/src/glsl/ir_copy_propagation.cpp
deleted file mode 100644 (file)
index 0fe8fa6..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_copy_propagation.cpp
- *
- * Moves usage of recently-copied variables to the previous copy of
- * the variable.
- *
- * This should reduce the number of MOV instructions in the generated
- * programs unless copy propagation is also done on the LIR, and may
- * help anyway by triggering other optimizations that live in the HIR.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-class acp_entry : public exec_node
-{
-public:
-   acp_entry(ir_variable *lhs, ir_variable *rhs)
-   {
-      assert(lhs);
-      assert(rhs);
-      this->lhs = lhs;
-      this->rhs = rhs;
-   }
-
-   ir_variable *lhs;
-   ir_variable *rhs;
-};
-
-
-class kill_entry : public exec_node
-{
-public:
-   kill_entry(ir_variable *var)
-   {
-      assert(var);
-      this->var = var;
-   }
-
-   ir_variable *var;
-};
-
-class ir_copy_propagation_visitor : public ir_hierarchical_visitor {
-public:
-   ir_copy_propagation_visitor()
-   {
-      progress = false;
-      mem_ctx = talloc_new(0);
-      this->acp = new(mem_ctx) exec_list;
-      this->kills = new(mem_ctx) exec_list;
-   }
-   ~ir_copy_propagation_visitor()
-   {
-      talloc_free(mem_ctx);
-   }
-
-   virtual ir_visitor_status visit(class ir_dereference_variable *);
-   virtual ir_visitor_status visit_enter(class ir_loop *);
-   virtual ir_visitor_status visit_enter(class ir_function_signature *);
-   virtual ir_visitor_status visit_enter(class ir_function *);
-   virtual ir_visitor_status visit_leave(class ir_assignment *);
-   virtual ir_visitor_status visit_enter(class ir_call *);
-   virtual ir_visitor_status visit_enter(class ir_if *);
-
-   void add_copy(ir_assignment *ir);
-   void kill(ir_variable *ir);
-   void handle_if_block(exec_list *instructions);
-
-   /** List of acp_entry: The available copies to propagate */
-   exec_list *acp;
-   /**
-    * List of kill_entry: The variables whose values were killed in this
-    * block.
-    */
-   exec_list *kills;
-
-   bool progress;
-
-   bool killed_all;
-
-   void *mem_ctx;
-};
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir)
-{
-   /* Treat entry into a function signature as a completely separate
-    * block.  Any instructions at global scope will be shuffled into
-    * main() at link time, so they're irrelevant to us.
-    */
-   exec_list *orig_acp = this->acp;
-   exec_list *orig_kills = this->kills;
-   bool orig_killed_all = this->killed_all;
-
-   this->acp = new(mem_ctx) exec_list;
-   this->kills = new(mem_ctx) exec_list;
-   this->killed_all = false;
-
-   visit_list_elements(this, &ir->body);
-
-   this->kills = orig_kills;
-   this->acp = orig_acp;
-   this->killed_all = orig_killed_all;
-
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_leave(ir_assignment *ir)
-{
-   kill(ir->lhs->variable_referenced());
-
-   add_copy(ir);
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_function *ir)
-{
-   (void) ir;
-   return visit_continue;
-}
-
-/**
- * Replaces dereferences of ACP RHS variables with ACP LHS variables.
- *
- * This is where the actual copy propagation occurs.  Note that the
- * rewriting of ir_dereference means that the ir_dereference instance
- * must not be shared by multiple IR operations!
- */
-ir_visitor_status
-ir_copy_propagation_visitor::visit(ir_dereference_variable *ir)
-{
-   if (this->in_assignee)
-      return visit_continue;
-
-   ir_variable *var = ir->var;
-
-   foreach_iter(exec_list_iterator, iter, *this->acp) {
-      acp_entry *entry = (acp_entry *)iter.get();
-
-      if (var == entry->lhs) {
-        ir->var = entry->rhs;
-        this->progress = true;
-        break;
-      }
-   }
-
-   return visit_continue;
-}
-
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_call *ir)
-{
-   /* Do copy propagation on call parameters, but skip any out params */
-   exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
-   foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
-      ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
-      ir_instruction *ir = (ir_instruction *)iter.get();
-      if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
-         ir->accept(this);
-      }
-      sig_param_iter.next();
-   }
-
-   /* Since we're unlinked, we don't (necssarily) know the side effects of
-    * this call.  So kill all copies.
-    */
-   acp->make_empty();
-   this->killed_all = true;
-
-   return visit_continue_with_parent;
-}
-
-void
-ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
-{
-   exec_list *orig_acp = this->acp;
-   exec_list *orig_kills = this->kills;
-   bool orig_killed_all = this->killed_all;
-
-   this->acp = new(mem_ctx) exec_list;
-   this->kills = new(mem_ctx) exec_list;
-   this->killed_all = false;
-
-   /* Populate the initial acp with a copy of the original */
-   foreach_iter(exec_list_iterator, iter, *orig_acp) {
-      acp_entry *a = (acp_entry *)iter.get();
-      this->acp->push_tail(new(this->mem_ctx) acp_entry(a->lhs, a->rhs));
-   }
-
-   visit_list_elements(this, instructions);
-
-   if (this->killed_all) {
-      orig_acp->make_empty();
-   }
-
-   exec_list *new_kills = this->kills;
-   this->kills = orig_kills;
-   this->acp = orig_acp;
-   this->killed_all = this->killed_all || orig_killed_all;
-
-   foreach_iter(exec_list_iterator, iter, *new_kills) {
-      kill_entry *k = (kill_entry *)iter.get();
-      kill(k->var);
-   }
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_if *ir)
-{
-   ir->condition->accept(this);
-
-   handle_if_block(&ir->then_instructions);
-   handle_if_block(&ir->else_instructions);
-
-   /* handle_if_block() already descended into the children. */
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_copy_propagation_visitor::visit_enter(ir_loop *ir)
-{
-   exec_list *orig_acp = this->acp;
-   exec_list *orig_kills = this->kills;
-   bool orig_killed_all = this->killed_all;
-
-   /* FINISHME: For now, the initial acp for loops is totally empty.
-    * We could go through once, then go through again with the acp
-    * cloned minus the killed entries after the first run through.
-    */
-   this->acp = new(mem_ctx) exec_list;
-   this->kills = new(mem_ctx) exec_list;
-   this->killed_all = false;
-
-   visit_list_elements(this, &ir->body_instructions);
-
-   if (this->killed_all) {
-      orig_acp->make_empty();
-   }
-
-   exec_list *new_kills = this->kills;
-   this->kills = orig_kills;
-   this->acp = orig_acp;
-   this->killed_all = this->killed_all || orig_killed_all;
-
-   foreach_iter(exec_list_iterator, iter, *new_kills) {
-      kill_entry *k = (kill_entry *)iter.get();
-      kill(k->var);
-   }
-
-   /* already descended into the children. */
-   return visit_continue_with_parent;
-}
-
-void
-ir_copy_propagation_visitor::kill(ir_variable *var)
-{
-   assert(var != NULL);
-
-   /* Remove any entries currently in the ACP for this kill. */
-   foreach_iter(exec_list_iterator, iter, *acp) {
-      acp_entry *entry = (acp_entry *)iter.get();
-
-      if (entry->lhs == var || entry->rhs == var) {
-        entry->remove();
-      }
-   }
-
-   /* Add the LHS variable to the list of killed variables in this block.
-    */
-   this->kills->push_tail(new(this->mem_ctx) kill_entry(var));
-}
-
-/**
- * Adds an entry to the available copy list if it's a plain assignment
- * of a variable to a variable.
- */
-void
-ir_copy_propagation_visitor::add_copy(ir_assignment *ir)
-{
-   acp_entry *entry;
-
-   if (ir->condition) {
-      ir_constant *condition = ir->condition->as_constant();
-      if (!condition || !condition->value.b[0])
-        return;
-   }
-
-   ir_variable *lhs_var = ir->whole_variable_written();
-   ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
-
-   if ((lhs_var != NULL) && (rhs_var != NULL)) {
-      if (lhs_var == rhs_var) {
-        /* This is a dumb assignment, but we've conveniently noticed
-         * it here.  Removing it now would mess up the loop iteration
-         * calling us.  Just flag it to not execute, and someone else
-         * will clean up the mess.
-         */
-        ir->condition = new(talloc_parent(ir)) ir_constant(false);
-        this->progress = true;
-      } else {
-        entry = new(this->mem_ctx) acp_entry(lhs_var, rhs_var);
-        this->acp->push_tail(entry);
-      }
-   }
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_copy_propagation(exec_list *instructions)
-{
-   ir_copy_propagation_visitor v;
-
-   visit_list_elements(&v, instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_dead_code.cpp b/src/glsl/ir_dead_code.cpp
deleted file mode 100644 (file)
index 5cf5e99..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_dead_code.cpp
- *
- * Eliminates dead assignments and variable declarations from the code.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_variable_refcount.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-/**
- * Do a dead code pass over instructions and everything that instructions
- * references.
- *
- * Note that this will remove assignments to globals, so it is not suitable
- * for usage on an unlinked instruction stream.
- */
-bool
-do_dead_code(exec_list *instructions)
-{
-   ir_variable_refcount_visitor v;
-   bool progress = false;
-
-   v.run(instructions);
-
-   foreach_iter(exec_list_iterator, iter, v.variable_list) {
-      variable_entry *entry = (variable_entry *)iter.get();
-
-      /* Since each assignment is a reference, the refereneced count must be
-       * greater than or equal to the assignment count.  If they are equal,
-       * then all of the references are assignments, and the variable is
-       * dead.
-       *
-       * Note that if the variable is neither assigned nor referenced, both
-       * counts will be zero and will be caught by the equality test.
-       */
-      assert(entry->referenced_count >= entry->assigned_count);
-
-      if (debug) {
-        printf("%s@%p: %d refs, %d assigns, %sdeclared in our scope\n",
-               entry->var->name, (void *) entry->var,
-               entry->referenced_count, entry->assigned_count,
-               entry->declaration ? "" : "not ");
-      }
-
-      if ((entry->referenced_count > entry->assigned_count)
-         || !entry->declaration)
-        continue;
-
-      if (entry->assign) {
-        /* Remove a single dead assignment to the variable we found.
-         * Don't do so if it's a shader output, though.
-         */
-        if (entry->var->mode != ir_var_out &&
-            entry->var->mode != ir_var_inout &&
-            !ir_has_call(entry->assign)) {
-           entry->assign->remove();
-           progress = true;
-
-           if (debug) {
-              printf("Removed assignment to %s@%p\n",
-                     entry->var->name, (void *) entry->var);
-           }
-        }
-      } else {
-        /* If there are no assignments or references to the variable left,
-         * then we can remove its declaration.
-         */
-
-        /* uniform initializers are precious, and could get used by another
-         * stage.
-         */
-        if (entry->var->mode == ir_var_uniform &&
-            entry->var->constant_value)
-           continue;
-
-        entry->var->remove();
-        progress = true;
-
-        if (debug) {
-           printf("Removed declaration of %s@%p\n",
-                  entry->var->name, (void *) entry->var);
-        }
-      }
-   }
-
-   return progress;
-}
-
-/**
- * Does a dead code pass on the functions present in the instruction stream.
- *
- * This is suitable for use while the program is not linked, as it will
- * ignore variable declarations (and the assignments to them) for variables
- * with global scope.
- */
-bool
-do_dead_code_unlinked(exec_list *instructions)
-{
-   bool progress = false;
-
-   foreach_iter(exec_list_iterator, iter, *instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
-      ir_function *f = ir->as_function();
-      if (f) {
-        foreach_iter(exec_list_iterator, sigiter, *f) {
-           ir_function_signature *sig =
-              (ir_function_signature *) sigiter.get();
-           if (do_dead_code(&sig->body))
-              progress = true;
-        }
-      }
-   }
-
-   return progress;
-}
diff --git a/src/glsl/ir_dead_code_local.cpp b/src/glsl/ir_dead_code_local.cpp
deleted file mode 100644 (file)
index 4bbedf0..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_dead_code_local.cpp
- *
- * Eliminates local dead assignments from the code.
- *
- * This operates on basic blocks, tracking assignments and finding if
- * they're used before the variable is completely reassigned.
- *
- * Compare this to ir_dead_code.cpp, which operates globally looking
- * for assignments to variables that are never read.
- */
-
-#include "ir.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-class assignment_entry : public exec_node
-{
-public:
-   assignment_entry(ir_variable *lhs, ir_instruction *ir)
-   {
-      assert(lhs);
-      assert(ir);
-      this->lhs = lhs;
-      this->ir = ir;
-   }
-
-   ir_variable *lhs;
-   ir_instruction *ir;
-};
-
-class kill_for_derefs_visitor : public ir_hierarchical_visitor {
-public:
-   kill_for_derefs_visitor(exec_list *assignments)
-   {
-      this->assignments = assignments;
-   }
-
-   virtual ir_visitor_status visit(ir_dereference_variable *ir)
-   {
-      ir_variable *const var = ir->variable_referenced();
-
-      foreach_iter(exec_list_iterator, iter, *this->assignments) {
-        assignment_entry *entry = (assignment_entry *)iter.get();
-
-        if (entry->lhs == var) {
-           if (debug)
-              printf("kill %s\n", entry->lhs->name);
-           entry->remove();
-        }
-      }
-
-      return visit_continue;
-   }
-
-private:
-   exec_list *assignments;
-};
-
-class array_index_visit : public ir_hierarchical_visitor {
-public:
-   array_index_visit(ir_hierarchical_visitor *v)
-   {
-      this->visitor = v;
-   }
-
-   virtual ir_visitor_status visit_enter(class ir_dereference_array *ir)
-   {
-      ir->array_index->accept(visitor);
-      return visit_continue;
-   }
-
-   static void run(ir_instruction *ir, ir_hierarchical_visitor *v)
-   {
-      array_index_visit top_visit(v);
-      ir->accept(& top_visit);
-   }
-
-   ir_hierarchical_visitor *visitor;
-};
-
-
-/**
- * Adds an entry to the available copy list if it's a plain assignment
- * of a variable to a variable.
- */
-static bool
-process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
-{
-   ir_variable *var = NULL;
-   bool progress = false;
-   kill_for_derefs_visitor v(assignments);
-
-   /* Kill assignment entries for things used to produce this assignment. */
-   ir->rhs->accept(&v);
-   if (ir->condition) {
-      ir->condition->accept(&v);
-   }
-
-   /* Kill assignment enties used as array indices.
-    */
-   array_index_visit::run(ir->lhs, &v);
-   var = ir->lhs->variable_referenced();
-   assert(var);
-
-   bool always_assign = true;
-   if (ir->condition) {
-      ir_constant *condition = ir->condition->as_constant();
-      if (!condition || !condition->value.b[0])
-        always_assign = false;
-   }
-
-   /* Now, check if we did a whole-variable assignment. */
-   if (always_assign && (ir->whole_variable_written() != NULL)) {
-      /* We did a whole-variable assignment.  So, any instruction in
-       * the assignment list with the same LHS is dead.
-       */
-      if (debug)
-        printf("looking for %s to remove\n", var->name);
-      foreach_iter(exec_list_iterator, iter, *assignments) {
-        assignment_entry *entry = (assignment_entry *)iter.get();
-
-        if (entry->lhs == var) {
-           if (debug)
-              printf("removing %s\n", var->name);
-           entry->ir->remove();
-           entry->remove();
-           progress = true;
-        }
-      }
-   }
-
-   /* Add this instruction to the assignment list available to be removed.
-    * But not if the assignment has other side effects.
-    */
-   if (ir_has_call(ir))
-      return progress;
-
-   assignment_entry *entry = new(ctx) assignment_entry(var, ir);
-   assignments->push_tail(entry);
-
-   if (debug) {
-      printf("add %s\n", var->name);
-
-      printf("current entries\n");
-      foreach_iter(exec_list_iterator, iter, *assignments) {
-        assignment_entry *entry = (assignment_entry *)iter.get();
-
-        printf("    %s\n", entry->lhs->name);
-      }
-   }
-
-   return progress;
-}
-
-static void
-dead_code_local_basic_block(ir_instruction *first,
-                            ir_instruction *last,
-                            void *data)
-{
-   ir_instruction *ir, *ir_next;
-   /* List of avaialble_copy */
-   exec_list assignments;
-   bool *out_progress = (bool *)data;
-   bool progress = false;
-
-   void *ctx = talloc_new(NULL);
-   /* Safe looping, since process_assignment */
-   for (ir = first, ir_next = (ir_instruction *)first->next;;
-       ir = ir_next, ir_next = (ir_instruction *)ir->next) {
-      ir_assignment *ir_assign = ir->as_assignment();
-
-      if (debug) {
-        ir->print();
-        printf("\n");
-      }
-
-      if (ir_assign) {
-        progress = process_assignment(ctx, ir_assign, &assignments) || progress;
-      } else {
-        kill_for_derefs_visitor kill(&assignments);
-        ir->accept(&kill);
-      }
-
-      if (ir == last)
-        break;
-   }
-   *out_progress = progress;
-   talloc_free(ctx);
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_dead_code_local(exec_list *instructions)
-{
-   bool progress = false;
-
-   call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress);
-
-   return progress;
-}
diff --git a/src/glsl/ir_dead_functions.cpp b/src/glsl/ir_dead_functions.cpp
deleted file mode 100644 (file)
index 16037a2..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
- /*
-  * Copyright © 2010 Intel Corporation
-  *
-  * Permission is hereby granted, free of charge, to any person obtaining a
-  * copy of this software and associated documentation files (the "Software"),
-  * to deal in the Software without restriction, including without limitation
-  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-  * and/or sell copies of the Software, and to permit persons to whom the
-  * Software is furnished to do so, subject to the following conditions:
-  *
-  * The above copyright notice and this permission notice (including the next
-  * paragraph) shall be included in all copies or substantial portions of the
-  * Software.
-  *
-  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-  * DEALINGS IN THE SOFTWARE.
-  */
-
- /**
-  * \file ir_dead_functions.cpp
-  *
-  * Eliminates unused functions from the linked program.
-  */
-
- #include "ir.h"
- #include "ir_visitor.h"
- #include "ir_expression_flattening.h"
- #include "glsl_types.h"
-
- class signature_entry : public exec_node
- {
- public:
-    signature_entry(ir_function_signature *sig)
-    {
-       this->signature = sig;
-       this->used = false;
-    }
-
-    ir_function_signature *signature;
-    bool used;
- };
-
- class ir_dead_functions_visitor : public ir_hierarchical_visitor {
- public:
-    ir_dead_functions_visitor()
-    {
-       this->mem_ctx = talloc_new(NULL);
-    }
-
-    ~ir_dead_functions_visitor()
-    {
-       talloc_free(this->mem_ctx);
-    }
-
-    virtual ir_visitor_status visit_enter(ir_function_signature *);
-    virtual ir_visitor_status visit_enter(ir_call *);
-
-    signature_entry *get_signature_entry(ir_function_signature *var);
-
-    bool (*predicate)(ir_instruction *ir);
-
-    /* List of signature_entry */
-    exec_list signature_list;
-    void *mem_ctx;
- };
-
-
- signature_entry *
- ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig)
- {
-    foreach_iter(exec_list_iterator, iter, this->signature_list) {
-       signature_entry *entry = (signature_entry *)iter.get();
-       if (entry->signature == sig)
-         return entry;
-    }
-
-    signature_entry *entry = new(mem_ctx) signature_entry(sig);
-    this->signature_list.push_tail(entry);
-    return entry;
- }
-
-
- ir_visitor_status
- ir_dead_functions_visitor::visit_enter(ir_function_signature *ir)
- {
-    signature_entry *entry = this->get_signature_entry(ir);
-
-    if (strcmp(ir->function_name(), "main") == 0) {
-       entry->used = true;
-    }
-
-    return visit_continue;
- }
-
-
- ir_visitor_status
- ir_dead_functions_visitor::visit_enter(ir_call *ir)
- {
-    signature_entry *entry = this->get_signature_entry(ir->get_callee());
-
-    entry->used = true;
-
-   return visit_continue;
-}
-
-bool
-do_dead_functions(exec_list *instructions)
-{
-   ir_dead_functions_visitor v;
-   bool progress = false;
-
-   visit_list_elements(&v, instructions);
-
-   /* Now that we've figured out which function signatures are used, remove
-    * the unused ones, and remove function definitions that have no more
-    * signatures.
-    */
-    foreach_iter(exec_list_iterator, iter, v.signature_list) {
-      signature_entry *entry = (signature_entry *)iter.get();
-
-      if (!entry->used) {
-        entry->signature->remove();
-        delete entry->signature;
-        progress = true;
-      }
-      delete(entry);
-   }
-
-   /* We don't just do this above when we nuked a signature because of
-    * const pointers.
-    */
-   foreach_iter(exec_list_iterator, iter, *instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
-      ir_function *func = ir->as_function();
-
-      if (func && func->signatures.is_empty()) {
-        /* At this point (post-linking), the symbol table is no
-         * longer in use, so not removing the function from the
-         * symbol table should be OK.
-         */
-        func->remove();
-        delete func;
-        progress = true;
-      }
-   }
-
-   return progress;
-}
diff --git a/src/glsl/ir_div_to_mul_rcp.cpp b/src/glsl/ir_div_to_mul_rcp.cpp
deleted file mode 100644 (file)
index 640d5d6..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_div_to_mul_rcp.cpp
- *
- * Breaks an ir_unop_div expression down to op0 * (rcp(op1)).
- *
- * Many GPUs don't have a divide instruction (945 and 965 included),
- * but they do have an RCP instruction to compute an approximate
- * reciprocal.  By breaking the operation down, constant reciprocals
- * can get constant folded.
- */
-
-#include "ir.h"
-#include "glsl_types.h"
-
-class ir_div_to_mul_rcp_visitor : public ir_hierarchical_visitor {
-public:
-   ir_div_to_mul_rcp_visitor()
-   {
-      this->made_progress = false;
-   }
-
-   ir_visitor_status visit_leave(ir_expression *);
-
-   bool made_progress;
-};
-
-bool
-do_div_to_mul_rcp(exec_list *instructions)
-{
-   ir_div_to_mul_rcp_visitor v;
-
-   visit_list_elements(&v, instructions);
-   return v.made_progress;
-}
-
-ir_visitor_status
-ir_div_to_mul_rcp_visitor::visit_leave(ir_expression *ir)
-{
-   if (ir->operation != ir_binop_div)
-      return visit_continue;
-
-   if (ir->operands[1]->type->base_type != GLSL_TYPE_INT &&
-       ir->operands[1]->type->base_type != GLSL_TYPE_UINT) {
-      /* New expression for the 1.0 / op1 */
-      ir_rvalue *expr;
-      expr = new(ir) ir_expression(ir_unop_rcp,
-                                  ir->operands[1]->type,
-                                  ir->operands[1],
-                                  NULL);
-
-      /* op0 / op1 -> op0 * (1.0 / op1) */
-      ir->operation = ir_binop_mul;
-      ir->operands[1] = expr;
-   } else {
-      /* Be careful with integer division -- we need to do it as a
-       * float and re-truncate, since rcp(n > 1) of an integer would
-       * just be 0.
-       */
-      ir_rvalue *op0, *op1;
-      const struct glsl_type *vec_type;
-
-      vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
-                                        ir->operands[1]->type->vector_elements,
-                                        ir->operands[1]->type->matrix_columns);
-
-      if (ir->operands[1]->type->base_type == GLSL_TYPE_INT)
-        op1 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[1], NULL);
-      else
-        op1 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[1], NULL);
-
-      op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL);
-
-      vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
-                                        ir->operands[0]->type->vector_elements,
-                                        ir->operands[0]->type->matrix_columns);
-
-      if (ir->operands[0]->type->base_type == GLSL_TYPE_INT)
-        op0 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[0], NULL);
-      else
-        op0 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[0], NULL);
-
-      op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1);
-
-      ir->operation = ir_unop_f2i;
-      ir->operands[0] = op0;
-      ir->operands[1] = NULL;
-   }
-
-   this->made_progress = true;
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_explog_to_explog2.cpp b/src/glsl/ir_explog_to_explog2.cpp
deleted file mode 100644 (file)
index 78694a2..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_explog_to_explog2.cpp
- *
- * Many GPUs don't have a base e log or exponent instruction, but they
- * do have base 2 versions, so this pass converts exp and log to exp2
- * and log2 operations.
- */
-
-#include "main/core.h" /* for log2f on MSVC */
-#include "ir.h"
-#include "glsl_types.h"
-
-class ir_explog_to_explog2_visitor : public ir_hierarchical_visitor {
-public:
-   ir_explog_to_explog2_visitor()
-   {
-      this->progress = false;
-   }
-
-   ir_visitor_status visit_leave(ir_expression *);
-
-   bool progress;
-};
-
-bool
-do_explog_to_explog2(exec_list *instructions)
-{
-   ir_explog_to_explog2_visitor v;
-
-   visit_list_elements(&v, instructions);
-   return v.progress;
-}
-
-ir_visitor_status
-ir_explog_to_explog2_visitor::visit_leave(ir_expression *ir)
-{
-   if (ir->operation == ir_unop_exp) {
-      void *mem_ctx = talloc_parent(ir);
-      ir_constant *log2_e = new(mem_ctx) ir_constant(log2f(M_E));
-
-      ir->operation = ir_unop_exp2;
-      ir->operands[0] = new(mem_ctx) ir_expression(ir_binop_mul,
-                                                  ir->operands[0]->type,
-                                                  ir->operands[0],
-                                                  log2_e);
-      this->progress = true;
-   }
-
-   if (ir->operation == ir_unop_log) {
-      void *mem_ctx = talloc_parent(ir);
-
-      ir->operation = ir_binop_mul;
-      ir->operands[0] = new(mem_ctx) ir_expression(ir_unop_log2,
-                                                  ir->operands[0]->type,
-                                                  ir->operands[0],
-                                                  NULL);
-      ir->operands[1] = new(mem_ctx) ir_constant(1.0f / log2f(M_E));
-      this->progress = true;
-   }
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_function_inlining.cpp b/src/glsl/ir_function_inlining.cpp
deleted file mode 100644 (file)
index 147c182..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_function_inlining.cpp
- *
- * Replaces calls to functions with the body of the function.
- */
-
-#include <inttypes.h>
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_function_inlining.h"
-#include "ir_expression_flattening.h"
-#include "glsl_types.h"
-#include "program/hash_table.h"
-
-static void
-do_sampler_replacement(exec_list *instructions,
-                      ir_variable *sampler,
-                      ir_dereference *deref);
-
-class ir_function_inlining_visitor : public ir_hierarchical_visitor {
-public:
-   ir_function_inlining_visitor()
-   {
-      progress = false;
-   }
-
-   virtual ~ir_function_inlining_visitor()
-   {
-      /* empty */
-   }
-
-   virtual ir_visitor_status visit_enter(ir_expression *);
-   virtual ir_visitor_status visit_enter(ir_call *);
-   virtual ir_visitor_status visit_enter(ir_assignment *);
-   virtual ir_visitor_status visit_enter(ir_return *);
-   virtual ir_visitor_status visit_enter(ir_texture *);
-   virtual ir_visitor_status visit_enter(ir_swizzle *);
-
-   bool progress;
-};
-
-
-bool
-automatic_inlining_predicate(ir_instruction *ir)
-{
-   ir_call *call = ir->as_call();
-
-   if (call && can_inline(call))
-      return true;
-
-   return false;
-}
-
-bool
-do_function_inlining(exec_list *instructions)
-{
-   ir_function_inlining_visitor v;
-
-   do_expression_flattening(instructions, automatic_inlining_predicate);
-
-   v.run(instructions);
-
-   return v.progress;
-}
-
-static void
-replace_return_with_assignment(ir_instruction *ir, void *data)
-{
-   void *ctx = talloc_parent(ir);
-   ir_variable *retval = (ir_variable *)data;
-   ir_return *ret = ir->as_return();
-
-   if (ret) {
-      if (ret->value) {
-        ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
-        ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
-      } else {
-        /* un-valued return has to be the last return, or we shouldn't
-         * have reached here. (see can_inline()).
-         */
-        assert(ret->next->is_tail_sentinel());
-        ret->remove();
-      }
-   }
-}
-
-ir_rvalue *
-ir_call::generate_inline(ir_instruction *next_ir)
-{
-   void *ctx = talloc_parent(this);
-   ir_variable **parameters;
-   int num_parameters;
-   int i;
-   ir_variable *retval = NULL;
-   struct hash_table *ht;
-
-   ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
-
-   num_parameters = 0;
-   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
-      num_parameters++;
-
-   parameters = new ir_variable *[num_parameters];
-
-   /* Generate storage for the return value. */
-   if (this->callee->return_type) {
-      retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
-                                   ir_var_auto);
-      next_ir->insert_before(retval);
-   }
-
-   /* Generate the declarations for the parameters to our inlined code,
-    * and set up the mapping of real function body variables to ours.
-    */
-   i = 0;
-   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
-   exec_list_iterator param_iter = this->actual_parameters.iterator();
-   for (i = 0; i < num_parameters; i++) {
-      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
-      ir_rvalue *param = (ir_rvalue *) param_iter.get();
-
-      /* Generate a new variable for the parameter. */
-      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
-        /* For samplers, we want the inlined sampler references
-         * referencing the passed in sampler variable, since that
-         * will have the location information, which an assignment of
-         * a sampler wouldn't.  Fix it up below.
-         */
-        parameters[i] = NULL;
-      } else {
-        parameters[i] = sig_param->clone(ctx, ht);
-        parameters[i]->mode = ir_var_auto;
-
-        /* Remove the read-only decoration becuase we're going to write
-         * directly to this variable.  If the cloned variable is left
-         * read-only and the inlined function is inside a loop, the loop
-         * analysis code will get confused.
-         */
-        parameters[i]->read_only = false;
-        next_ir->insert_before(parameters[i]);
-      }
-
-      /* Move the actual param into our param variable if it's an 'in' type. */
-      if (parameters[i] && (sig_param->mode == ir_var_in ||
-                           sig_param->mode == ir_var_inout)) {
-        ir_assignment *assign;
-
-        assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
-                                        param, NULL);
-        next_ir->insert_before(assign);
-      }
-
-      sig_param_iter.next();
-      param_iter.next();
-   }
-
-   exec_list new_instructions;
-
-   /* Generate the inlined body of the function to a new list */
-   foreach_iter(exec_list_iterator, iter, callee->body) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
-      ir_instruction *new_ir = ir->clone(ctx, ht);
-
-      new_instructions.push_tail(new_ir);
-      visit_tree(new_ir, replace_return_with_assignment, retval);
-   }
-
-   /* If any samplers were passed in, replace any deref of the sampler
-    * with a deref of the sampler argument.
-    */
-   param_iter = this->actual_parameters.iterator();
-   sig_param_iter = this->callee->parameters.iterator();
-   for (i = 0; i < num_parameters; i++) {
-      ir_instruction *const param = (ir_instruction *) param_iter.get();
-      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
-
-      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
-        ir_dereference *deref = param->as_dereference();
-
-        assert(deref);
-        do_sampler_replacement(&new_instructions, sig_param, deref);
-      }
-      param_iter.next();
-      sig_param_iter.next();
-   }
-
-   /* Now push those new instructions in. */
-   foreach_iter(exec_list_iterator, iter, new_instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
-      next_ir->insert_before(ir);
-   }
-
-   /* Copy back the value of any 'out' parameters from the function body
-    * variables to our own.
-    */
-   i = 0;
-   param_iter = this->actual_parameters.iterator();
-   sig_param_iter = this->callee->parameters.iterator();
-   for (i = 0; i < num_parameters; i++) {
-      ir_instruction *const param = (ir_instruction *) param_iter.get();
-      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
-
-      /* Move our param variable into the actual param if it's an 'out' type. */
-      if (parameters[i] && (sig_param->mode == ir_var_out ||
-                           sig_param->mode == ir_var_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);
-      }
-
-      param_iter.next();
-      sig_param_iter.next();
-   }
-
-   delete [] parameters;
-
-   hash_table_dtor(ht);
-
-   if (retval)
-      return new(ctx) ir_dereference_variable(retval);
-   else
-      return NULL;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_expression *ir)
-{
-   (void) ir;
-   return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_return *ir)
-{
-   (void) ir;
-   return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_texture *ir)
-{
-   (void) ir;
-   return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
-{
-   (void) ir;
-   return visit_continue_with_parent;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_call *ir)
-{
-   if (can_inline(ir)) {
-      /* If the call was part of some tree, then it should have been
-       * flattened out or we shouldn't have seen it because of a
-       * visit_continue_with_parent in this visitor.
-       */
-      assert(ir == base_ir);
-
-      (void) ir->generate_inline(ir);
-      ir->remove();
-      this->progress = true;
-   }
-
-   return visit_continue;
-}
-
-
-ir_visitor_status
-ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
-{
-   ir_call *call = ir->rhs->as_call();
-   if (!call || !can_inline(call))
-      return visit_continue;
-
-   /* generates the parameter setup, function body, and returns the return
-    * value of the function
-    */
-   ir_rvalue *rhs = call->generate_inline(ir);
-   assert(rhs);
-
-   ir->rhs = rhs;
-   this->progress = true;
-
-   return visit_continue;
-}
-
-/**
- * Replaces references to the "sampler" variable with a clone of "deref."
- *
- * From the spec, samplers can appear in the tree as function
- * (non-out) parameters and as the result of array indexing and
- * structure field selection.  In our builtin implementation, they
- * also appear in the sampler field of an ir_tex instruction.
- */
-
-class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
-public:
-   ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
-   {
-      this->sampler = sampler;
-      this->deref = deref;
-   }
-
-   virtual ~ir_sampler_replacement_visitor()
-   {
-   }
-
-   virtual ir_visitor_status visit_leave(ir_call *);
-   virtual ir_visitor_status visit_leave(ir_dereference_array *);
-   virtual ir_visitor_status visit_leave(ir_dereference_record *);
-   virtual ir_visitor_status visit_leave(ir_texture *);
-
-   void replace_deref(ir_dereference **deref);
-   void replace_rvalue(ir_rvalue **rvalue);
-
-   ir_variable *sampler;
-   ir_dereference *deref;
-};
-
-void
-ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
-{
-   ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
-   if (deref_var && deref_var->var == this->sampler) {
-      *deref = this->deref->clone(talloc_parent(*deref), NULL);
-   }
-}
-
-void
-ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
-{
-   if (!*rvalue)
-      return;
-
-   ir_dereference *deref = (*rvalue)->as_dereference();
-
-   if (!deref)
-      return;
-
-   replace_deref(&deref);
-   *rvalue = deref;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
-{
-   replace_deref(&ir->sampler);
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
-{
-   replace_rvalue(&ir->array);
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
-{
-   replace_rvalue(&ir->record);
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
-{
-   foreach_iter(exec_list_iterator, iter, *ir) {
-      ir_rvalue *param = (ir_rvalue *)iter.get();
-      ir_rvalue *new_param = param;
-      replace_rvalue(&new_param);
-
-      if (new_param != param) {
-        param->replace_with(new_param);
-      }
-   }
-   return visit_continue;
-}
-
-static void
-do_sampler_replacement(exec_list *instructions,
-                      ir_variable *sampler,
-                      ir_dereference *deref)
-{
-   ir_sampler_replacement_visitor v(sampler, deref);
-
-   visit_list_elements(&v, instructions);
-}
diff --git a/src/glsl/ir_if_simplification.cpp b/src/glsl/ir_if_simplification.cpp
deleted file mode 100644 (file)
index 021615e..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_if_simplification.cpp
- *
- * Moves constant branches of if statements out to the surrounding
- * instruction stream.
- */
-
-#include "ir.h"
-
-class ir_if_simplification_visitor : public ir_hierarchical_visitor {
-public:
-   ir_if_simplification_visitor()
-   {
-      this->made_progress = false;
-   }
-
-   ir_visitor_status visit_leave(ir_if *);
-
-   bool made_progress;
-};
-
-bool
-do_if_simplification(exec_list *instructions)
-{
-   ir_if_simplification_visitor v;
-
-   v.run(instructions);
-   return v.made_progress;
-}
-
-
-ir_visitor_status
-ir_if_simplification_visitor::visit_leave(ir_if *ir)
-{
-   /* FINISHME: Ideally there would be a way to note that the condition results
-    * FINISHME: in a constant before processing both of the other subtrees.
-    * FINISHME: This can probably be done with some flags, but it would take
-    * FINISHME: some work to get right.
-    */
-   ir_constant *condition_constant = ir->condition->constant_expression_value();
-   if (condition_constant) {
-      /* Move the contents of the one branch of the conditional
-       * that matters out.
-       */
-      if (condition_constant->value.b[0]) {
-        foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
-           ir_instruction *then_ir = (ir_instruction *)then_iter.get();
-           ir->insert_before(then_ir);
-        }
-      } else {
-        foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
-           ir_instruction *else_ir = (ir_instruction *)else_iter.get();
-           ir->insert_before(else_ir);
-        }
-      }
-      ir->remove();
-      this->made_progress = true;
-   }
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_if_to_cond_assign.cpp b/src/glsl/ir_if_to_cond_assign.cpp
deleted file mode 100644 (file)
index 0b87413..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_if_to_cond_assign.cpp
- *
- * This attempts to flatten all if statements to conditional
- * assignments for GPUs that don't do control flow.
- *
- * It can't handle other control flow being inside of its block, such
- * as calls or loops.  Hopefully loop unrolling and inlining will take
- * care of those.
- */
-
-#include "glsl_types.h"
-#include "ir.h"
-
-class ir_if_to_cond_assign_visitor : public ir_hierarchical_visitor {
-public:
-   ir_if_to_cond_assign_visitor()
-   {
-      this->progress = false;
-   }
-
-   ir_visitor_status visit_leave(ir_if *);
-
-   bool progress;
-};
-
-bool
-do_if_to_cond_assign(exec_list *instructions)
-{
-   ir_if_to_cond_assign_visitor v;
-
-   visit_list_elements(&v, instructions);
-
-   return v.progress;
-}
-
-void
-check_control_flow(ir_instruction *ir, void *data)
-{
-   bool *found_control_flow = (bool *)data;
-   switch (ir->ir_type) {
-   case ir_type_call:
-   case ir_type_discard:
-   case ir_type_loop:
-   case ir_type_loop_jump:
-   case ir_type_return:
-      *found_control_flow = true;
-      break;
-   default:
-      break;
-   }
-}
-
-void
-move_block_to_cond_assign(void *mem_ctx,
-                         ir_if *if_ir, ir_variable *cond_var, bool then)
-{
-   exec_list *instructions;
-
-   if (then) {
-      instructions = &if_ir->then_instructions;
-   } else {
-      instructions = &if_ir->else_instructions;
-   }
-
-   foreach_iter(exec_list_iterator, iter, *instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
-
-      if (ir->ir_type == ir_type_assignment) {
-        ir_assignment *assign = (ir_assignment *)ir;
-        ir_rvalue *cond_expr;
-        ir_dereference *deref = new(mem_ctx) ir_dereference_variable(cond_var);
-
-        if (then) {
-           cond_expr = deref;
-        } else {
-           cond_expr = new(mem_ctx) ir_expression(ir_unop_logic_not,
-                                                  glsl_type::bool_type,
-                                                  deref,
-                                                  NULL);
-        }
-
-        if (!assign->condition) {
-           assign->condition = cond_expr;
-        } else {
-           assign->condition = new(mem_ctx) ir_expression(ir_binop_logic_and,
-                                                          glsl_type::bool_type,
-                                                          cond_expr,
-                                                          assign->condition);
-        }
-      }
-
-      /* Now, move from the if block to the block surrounding it. */
-      ir->remove();
-      if_ir->insert_before(ir);
-   }
-}
-
-ir_visitor_status
-ir_if_to_cond_assign_visitor::visit_leave(ir_if *ir)
-{
-   bool found_control_flow = false;
-   ir_variable *cond_var;
-   ir_assignment *assign;
-   ir_dereference_variable *deref;
-
-   /* Check that both blocks don't contain anything we can't support. */
-   foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
-      ir_instruction *then_ir = (ir_instruction *)then_iter.get();
-      visit_tree(then_ir, check_control_flow, &found_control_flow);
-   }
-   foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
-      ir_instruction *else_ir = (ir_instruction *)else_iter.get();
-      visit_tree(else_ir, check_control_flow, &found_control_flow);
-   }
-   if (found_control_flow)
-      return visit_continue;
-
-   void *mem_ctx = talloc_parent(ir);
-
-   /* Store the condition to a variable so the assignment conditions are
-    * simpler.
-    */
-   cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type,
-                                      "if_to_cond_assign_condition",
-                                      ir_var_temporary);
-   ir->insert_before(cond_var);
-
-   deref = new(mem_ctx) ir_dereference_variable(cond_var);
-   assign = new(mem_ctx) ir_assignment(deref,
-                                      ir->condition, NULL);
-   ir->insert_before(assign);
-
-   /* Now, move all of the instructions out of the if blocks, putting
-    * conditions on assignments.
-    */
-   move_block_to_cond_assign(mem_ctx, ir, cond_var, true);
-   move_block_to_cond_assign(mem_ctx, ir, cond_var, false);
-
-   ir->remove();
-
-   this->progress = true;
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_lower_jumps.cpp b/src/glsl/ir_lower_jumps.cpp
deleted file mode 100644 (file)
index b69cc1e..0000000
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright © 2010 Luca Barbieri
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_lower_jumps.cpp
- */
-
-#include "glsl_types.h"
-#include <string.h>
-#include "ir.h"
-
-enum jump_strength
-{
-   strength_none,
-   strength_always_clears_execute_flag,
-   strength_continue,
-   strength_break,
-   strength_return,
-   strength_discard
-};
-
-struct block_record
-{
-   /* minimum jump strength (of lowered IR, not pre-lowering IR)
-    *
-    * If the block ends with a jump, must be the strength of the jump.
-    * Otherwise, the jump would be dead and have been deleted before)
-    *
-    * If the block doesn't end with a jump, it can be different than strength_none if all paths before it lead to some jump
-    * (e.g. an if with a return in one branch, and a break in the other, while not lowering them)
-    * Note that identical jumps are usually unified though.
-    */
-   jump_strength min_strength;
-
-   /* can anything clear the execute flag? */
-   bool may_clear_execute_flag;
-
-   block_record()
-   {
-      this->min_strength = strength_none;
-      this->may_clear_execute_flag = false;
-   }
-};
-
-struct loop_record
-{
-   ir_function_signature* signature;
-   ir_loop* loop;
-
-   /* used to avoid lowering the break used to represent lowered breaks */
-   unsigned nesting_depth;
-   bool in_if_at_the_end_of_the_loop;
-
-   bool may_set_return_flag;
-
-   ir_variable* break_flag;
-   ir_variable* execute_flag; /* cleared to emulate continue */
-
-   loop_record(ir_function_signature* p_signature = 0, ir_loop* p_loop = 0)
-   {
-      this->signature = p_signature;
-      this->loop = p_loop;
-      this->nesting_depth = 0;
-      this->in_if_at_the_end_of_the_loop = false;
-      this->may_set_return_flag = false;
-      this->break_flag = 0;
-      this->execute_flag = 0;
-   }
-
-   ir_variable* get_execute_flag()
-   {
-      /* also supported for the "function loop" */
-      if(!this->execute_flag) {
-         exec_list& list = this->loop ? this->loop->body_instructions : signature->body;
-         this->execute_flag = new(this->signature) ir_variable(glsl_type::bool_type, "execute_flag", ir_var_temporary);
-         list.push_head(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(execute_flag), new(this->signature) ir_constant(true), 0));
-         list.push_head(this->execute_flag);
-      }
-      return this->execute_flag;
-   }
-
-   ir_variable* get_break_flag()
-   {
-      assert(this->loop);
-      if(!this->break_flag) {
-         this->break_flag = new(this->signature) ir_variable(glsl_type::bool_type, "break_flag", ir_var_temporary);
-         this->loop->insert_before(this->break_flag);
-         this->loop->insert_before(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(break_flag), new(this->signature) ir_constant(false), 0));
-      }
-      return this->break_flag;
-   }
-};
-
-struct function_record
-{
-   ir_function_signature* signature;
-   ir_variable* return_flag; /* used to break out of all loops and then jump to the return instruction */
-   ir_variable* return_value;
-   bool is_main;
-   unsigned nesting_depth;
-
-   function_record(ir_function_signature* p_signature = 0)
-   {
-      this->signature = p_signature;
-      this->return_flag = 0;
-      this->return_value = 0;
-      this->nesting_depth = 0;
-      this->is_main = this->signature && (strcmp(this->signature->function_name(), "main") == 0);
-   }
-
-   ir_variable* get_return_flag()
-   {
-      if(!this->return_flag) {
-         this->return_flag = new(this->signature) ir_variable(glsl_type::bool_type, "return_flag", ir_var_temporary);
-         this->signature->body.push_head(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(return_flag), new(this->signature) ir_constant(false), 0));
-         this->signature->body.push_head(this->return_flag);
-      }
-      return this->return_flag;
-   }
-
-   ir_variable* get_return_value()
-   {
-      if(!this->return_value) {
-         assert(!this->signature->return_type->is_void());
-         return_value = new(this->signature) ir_variable(this->signature->return_type, "return_value", ir_var_temporary);
-         this->signature->body.push_head(this->return_value);
-      }
-      return this->return_value;
-   }
-};
-
-struct ir_lower_jumps_visitor : public ir_control_flow_visitor {
-   bool progress;
-
-   struct function_record function;
-   struct loop_record loop;
-   struct block_record block;
-
-   bool pull_out_jumps;
-   bool lower_continue;
-   bool lower_break;
-   bool lower_sub_return;
-   bool lower_main_return;
-
-   ir_lower_jumps_visitor()
-   {
-      this->progress = false;
-   }
-
-   void truncate_after_instruction(exec_node *ir)
-   {
-      if (!ir)
-         return;
-
-      while (!ir->get_next()->is_tail_sentinel()) {
-         ((ir_instruction *)ir->get_next())->remove();
-         this->progress = true;
-      }
-   }
-
-   void move_outer_block_inside(ir_instruction *ir, exec_list *inner_block)
-   {
-      while (!ir->get_next()->is_tail_sentinel()) {
-         ir_instruction *move_ir = (ir_instruction *)ir->get_next();
-
-         move_ir->remove();
-         inner_block->push_tail(move_ir);
-      }
-   }
-
-   virtual void visit(class ir_loop_jump * ir)
-   {
-      truncate_after_instruction(ir);
-      this->block.min_strength = ir->is_break() ? strength_break : strength_continue;
-   }
-
-   virtual void visit(class ir_return * ir)
-   {
-      truncate_after_instruction(ir);
-      this->block.min_strength = strength_return;
-   }
-
-   virtual void visit(class ir_discard * ir)
-   {
-      truncate_after_instruction(ir);
-      this->block.min_strength = strength_discard;
-   }
-
-   enum jump_strength get_jump_strength(ir_instruction* ir)
-   {
-      if(!ir)
-         return strength_none;
-      else if(ir->ir_type == ir_type_loop_jump) {
-         if(((ir_loop_jump*)ir)->is_break())
-            return strength_break;
-         else
-            return strength_continue;
-      } else if(ir->ir_type == ir_type_return)
-         return strength_return;
-      else if(ir->ir_type == ir_type_discard)
-         return strength_discard;
-      else
-         return strength_none;
-   }
-
-   bool should_lower_jump(ir_jump* ir)
-   {
-      unsigned strength = get_jump_strength(ir);
-      bool lower;
-      switch(strength)
-      {
-      case strength_none:
-         lower = false; /* don't change this, code relies on it */
-         break;
-      case strength_continue:
-         lower = lower_continue;
-         break;
-      case strength_break:
-         assert(this->loop.loop);
-         /* never lower "canonical break" */
-         if(ir->get_next()->is_tail_sentinel() && (this->loop.nesting_depth == 0
-               || (this->loop.nesting_depth == 1 && this->loop.in_if_at_the_end_of_the_loop)))
-            lower = false;
-         else
-            lower = lower_break;
-         break;
-      case strength_return:
-         /* never lower return at the end of a this->function */
-         if(this->function.nesting_depth == 0 && ir->get_next()->is_tail_sentinel())
-            lower = false;
-         else if (this->function.is_main)
-            lower = lower_main_return;
-         else
-            lower = lower_sub_return;
-         break;
-      case strength_discard:
-         lower = false; /* probably nothing needs this lowered */
-         break;
-      }
-      return lower;
-   }
-
-   block_record visit_block(exec_list* list)
-   {
-      block_record saved_block = this->block;
-      this->block = block_record();
-      visit_exec_list(list, this);
-      block_record ret = this->block;
-      this->block = saved_block;
-      return ret;
-   }
-
-   virtual void visit(ir_if *ir)
-   {
-      if(this->loop.nesting_depth == 0 && ir->get_next()->is_tail_sentinel())
-         this->loop.in_if_at_the_end_of_the_loop = true;
-
-      ++this->function.nesting_depth;
-      ++this->loop.nesting_depth;
-
-      block_record block_records[2];
-      ir_jump* jumps[2];
-
-      block_records[0] = visit_block(&ir->then_instructions);
-      block_records[1] = visit_block(&ir->else_instructions);
-
-retry: /* we get here if we put code after the if inside a branch */
-   for(unsigned i = 0; i < 2; ++i) {
-      exec_list& list = i ? ir->else_instructions : ir->then_instructions;
-      jumps[i] = 0;
-      if(!list.is_empty() && get_jump_strength((ir_instruction*)list.get_tail()))
-         jumps[i] = (ir_jump*)list.get_tail();
-   }
-
-      for(;;) {
-         jump_strength jump_strengths[2];
-
-         for(unsigned i = 0; i < 2; ++i) {
-            if(jumps[i]) {
-               jump_strengths[i] = block_records[i].min_strength;
-               assert(jump_strengths[i] == get_jump_strength(jumps[i]));
-            } else
-               jump_strengths[i] = strength_none;
-         }
-
-         /* move both jumps out if possible */
-         if(pull_out_jumps && jump_strengths[0] == jump_strengths[1]) {
-            bool unify = true;
-            if(jump_strengths[0] == strength_continue)
-               ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_continue));
-            else if(jump_strengths[0] == strength_break)
-               ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_break));
-            /* FINISHME: unify returns with identical expressions */
-            else if(jump_strengths[0] == strength_return && this->function.signature->return_type->is_void())
-               ir->insert_after(new(ir) ir_return(NULL));
-            /* FINISHME: unify discards */
-            else
-               unify = false;
-
-            if(unify) {
-               jumps[0]->remove();
-               jumps[1]->remove();
-               this->progress = true;
-
-               jumps[0] = 0;
-               jumps[1] = 0;
-               block_records[0].min_strength = strength_none;
-               block_records[1].min_strength = strength_none;
-               break;
-            }
-         }
-
-         /* lower a jump: if both need to lowered, start with the strongest one, so that
-          * we might later unify the lowered version with the other one
-          */
-         bool should_lower[2];
-         for(unsigned i = 0; i < 2; ++i)
-            should_lower[i] = should_lower_jump(jumps[i]);
-
-         int lower;
-         if(should_lower[1] && should_lower[0])
-            lower = jump_strengths[1] > jump_strengths[0];
-         else if(should_lower[0])
-            lower = 0;
-         else if(should_lower[1])
-            lower = 1;
-         else
-            break;
-
-         if(jump_strengths[lower] == strength_return) {
-            ir_variable* return_flag = this->function.get_return_flag();
-            if(!this->function.signature->return_type->is_void()) {
-               ir_variable* return_value = this->function.get_return_value();
-               jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(return_value), ((ir_return*)jumps[lower])->value, NULL));
-            }
-            jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(return_flag), new (ir) ir_constant(true), NULL));
-            this->loop.may_set_return_flag = true;
-            if(this->loop.loop) {
-               ir_loop_jump* lowered = 0;
-               lowered = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
-               block_records[lower].min_strength = strength_break;
-               jumps[lower]->replace_with(lowered);
-               jumps[lower] = lowered;
-            } else
-               goto lower_continue;
-            this->progress = true;
-         } else if(jump_strengths[lower] == strength_break) {
-            /* We can't lower to an actual continue because that would execute the increment.
-             *
-             * In the lowered code, we instead put the break check between the this->loop body and the increment,
-             * which is impossible with a real continue as defined by the GLSL IR currently.
-             *
-             * Smarter options (such as undoing the increment) are possible but it's not worth implementing them,
-             * because if break is lowered, continue is almost surely lowered too.
-             */
-            jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(this->loop.get_break_flag()), new (ir) ir_constant(true), 0));
-            goto lower_continue;
-         } else if(jump_strengths[lower] == strength_continue) {
-lower_continue:
-            ir_variable* execute_flag = this->loop.get_execute_flag();
-            jumps[lower]->replace_with(new(ir) ir_assignment(new (ir) ir_dereference_variable(execute_flag), new (ir) ir_constant(false), 0));
-            jumps[lower] = 0;
-            block_records[lower].min_strength = strength_always_clears_execute_flag;
-            block_records[lower].may_clear_execute_flag = true;
-            this->progress = true;
-            break;
-         }
-      }
-
-      /* move out a jump out if possible */
-      if(pull_out_jumps) {
-         int move_out = -1;
-         if(jumps[0] && block_records[1].min_strength >= strength_continue)
-            move_out = 0;
-         else if(jumps[1] && block_records[0].min_strength >= strength_continue)
-            move_out = 1;
-
-         if(move_out >= 0)
-         {
-            jumps[move_out]->remove();
-            ir->insert_after(jumps[move_out]);
-            jumps[move_out] = 0;
-            block_records[move_out].min_strength = strength_none;
-            this->progress = true;
-         }
-      }
-
-      if(block_records[0].min_strength < block_records[1].min_strength)
-         this->block.min_strength = block_records[0].min_strength;
-      else
-         this->block.min_strength = block_records[1].min_strength;
-      this->block.may_clear_execute_flag = this->block.may_clear_execute_flag || block_records[0].may_clear_execute_flag || block_records[1].may_clear_execute_flag;
-
-      if(this->block.min_strength)
-         truncate_after_instruction(ir);
-      else if(this->block.may_clear_execute_flag)
-      {
-         int move_into = -1;
-         if(block_records[0].min_strength && !block_records[1].may_clear_execute_flag)
-            move_into = 1;
-         else if(block_records[1].min_strength && !block_records[0].may_clear_execute_flag)
-            move_into = 0;
-
-         if(move_into >= 0) {
-            assert(!block_records[move_into].min_strength && !block_records[move_into].may_clear_execute_flag); /* otherwise, we just truncated */
-
-            exec_list* list = move_into ? &ir->else_instructions : &ir->then_instructions;
-            exec_node* next = ir->get_next();
-            if(!next->is_tail_sentinel()) {
-               move_outer_block_inside(ir, list);
-
-               exec_list list;
-               list.head = next;
-               block_records[move_into] = visit_block(&list);
-
-               this->progress = true;
-               goto retry;
-            }
-         } else {
-            ir_instruction* ir_after;
-            for(ir_after = (ir_instruction*)ir->get_next(); !ir_after->is_tail_sentinel();)
-            {
-               ir_if* ir_if = ir_after->as_if();
-               if(ir_if && ir_if->else_instructions.is_empty()) {
-                  ir_dereference_variable* ir_if_cond_deref = ir_if->condition->as_dereference_variable();
-                  if(ir_if_cond_deref && ir_if_cond_deref->var == this->loop.execute_flag) {
-                     ir_instruction* ir_next = (ir_instruction*)ir_after->get_next();
-                     ir_after->insert_before(&ir_if->then_instructions);
-                     ir_after->remove();
-                     ir_after = ir_next;
-                     continue;
-                  }
-               }
-               ir_after = (ir_instruction*)ir_after->get_next();
-
-               /* only set this if we find any unprotected instruction */
-               this->progress = true;
-            }
-
-            if(!ir->get_next()->is_tail_sentinel()) {
-               assert(this->loop.execute_flag);
-               ir_if* if_execute = new(ir) ir_if(new(ir) ir_dereference_variable(this->loop.execute_flag));
-               move_outer_block_inside(ir, &if_execute->then_instructions);
-               ir->insert_after(if_execute);
-            }
-         }
-      }
-      --this->loop.nesting_depth;
-      --this->function.nesting_depth;
-   }
-
-   virtual void visit(ir_loop *ir)
-   {
-      ++this->function.nesting_depth;
-      loop_record saved_loop = this->loop;
-      this->loop = loop_record(this->function.signature, ir);
-
-      block_record body = visit_block(&ir->body_instructions);
-
-      if(body.min_strength >= strength_break) {
-         /* FINISHME: turn the this->loop into an if, or replace it with its body */
-      }
-
-      if(this->loop.break_flag) {
-         ir_if* break_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->loop.break_flag));
-         break_if->then_instructions.push_tail(new(ir) ir_loop_jump(ir_loop_jump::jump_break));
-         ir->body_instructions.push_tail(break_if);
-      }
-
-      if(this->loop.may_set_return_flag) {
-         assert(this->function.return_flag);
-         ir_if* return_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->function.return_flag));
-         return_if->then_instructions.push_tail(new(ir) ir_loop_jump(saved_loop.loop ? ir_loop_jump::jump_break : ir_loop_jump::jump_continue));
-         ir->insert_after(return_if);
-      }
-
-      this->loop = saved_loop;
-      --this->function.nesting_depth;
-   }
-
-   virtual void visit(ir_function_signature *ir)
-   {
-      /* these are not strictly necessary */
-      assert(!this->function.signature);
-      assert(!this->loop.loop);
-
-      function_record saved_function = this->function;
-      loop_record saved_loop = this->loop;
-      this->function = function_record(ir);
-      this->loop = loop_record(ir);
-
-      assert(!this->loop.loop);
-      visit_block(&ir->body);
-
-      if(this->function.return_value)
-         ir->body.push_tail(new(ir) ir_return(new (ir) ir_dereference_variable(this->function.return_value)));
-
-      this->loop = saved_loop;
-      this->function = saved_function;
-   }
-
-   virtual void visit(class ir_function * ir)
-   {
-      visit_block(&ir->signatures);
-   }
-};
-
-bool
-do_lower_jumps(exec_list *instructions, bool pull_out_jumps, bool lower_sub_return, bool lower_main_return, bool lower_continue, bool lower_break)
-{
-   ir_lower_jumps_visitor v;
-   v.pull_out_jumps = pull_out_jumps;
-   v.lower_continue = lower_continue;
-   v.lower_break = lower_break;
-   v.lower_sub_return = lower_sub_return;
-   v.lower_main_return = lower_main_return;
-
-   do {
-      v.progress = false;
-      visit_exec_list(instructions, &v);
-   } while (v.progress);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_mat_op_to_vec.cpp b/src/glsl/ir_mat_op_to_vec.cpp
deleted file mode 100644 (file)
index 244fe48..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_mat_op_to_vec.cpp
- *
- * Breaks matrix operation expressions down to a series of vector operations.
- *
- * Generally this is how we have to codegen matrix operations for a
- * GPU, so this gives us the chance to constant fold operations on a
- * column or row.
- */
-
-#include "ir.h"
-#include "ir_expression_flattening.h"
-#include "glsl_types.h"
-
-class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
-public:
-   ir_mat_op_to_vec_visitor()
-   {
-      this->made_progress = false;
-      this->mem_ctx = NULL;
-   }
-
-   ir_visitor_status visit_leave(ir_assignment *);
-
-   ir_dereference *get_column(ir_variable *var, int col);
-   ir_rvalue *get_element(ir_variable *var, int col, int row);
-
-   void do_mul_mat_mat(ir_variable *result_var,
-                      ir_variable *a_var, ir_variable *b_var);
-   void do_mul_mat_vec(ir_variable *result_var,
-                      ir_variable *a_var, ir_variable *b_var);
-   void do_mul_vec_mat(ir_variable *result_var,
-                      ir_variable *a_var, ir_variable *b_var);
-   void do_mul_mat_scalar(ir_variable *result_var,
-                         ir_variable *a_var, ir_variable *b_var);
-   void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var,
-                        ir_variable *b_var, bool test_equal);
-
-   void *mem_ctx;
-   bool made_progress;
-};
-
-static bool
-mat_op_to_vec_predicate(ir_instruction *ir)
-{
-   ir_expression *expr = ir->as_expression();
-   unsigned int i;
-
-   if (!expr)
-      return false;
-
-   for (i = 0; i < expr->get_num_operands(); i++) {
-      if (expr->operands[i]->type->is_matrix())
-        return true;
-   }
-
-   return false;
-}
-
-bool
-do_mat_op_to_vec(exec_list *instructions)
-{
-   ir_mat_op_to_vec_visitor v;
-
-   /* Pull out any matrix expression to a separate assignment to a
-    * temp.  This will make our handling of the breakdown to
-    * operations on the matrix's vector components much easier.
-    */
-   do_expression_flattening(instructions, mat_op_to_vec_predicate);
-
-   visit_list_elements(&v, instructions);
-
-   return v.made_progress;
-}
-
-ir_rvalue *
-ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
-{
-   ir_dereference *deref;
-
-   deref = new(mem_ctx) ir_dereference_variable(var);
-
-   if (var->type->is_matrix()) {
-      deref = new(mem_ctx) ir_dereference_array(var,
-                                               new(mem_ctx) ir_constant(col));
-   } else {
-      assert(col == 0);
-   }
-
-   return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1);
-}
-
-ir_dereference *
-ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
-{
-   ir_dereference *deref;
-
-   if (!var->type->is_matrix()) {
-      deref = new(mem_ctx) ir_dereference_variable(var);
-   } else {
-      deref = new(mem_ctx) ir_dereference_variable(var);
-      deref = new(mem_ctx) ir_dereference_array(deref,
-                                               new(mem_ctx) ir_constant(row));
-   }
-
-   return deref;
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
-                                        ir_variable *a_var,
-                                        ir_variable *b_var)
-{
-   int b_col, i;
-   ir_assignment *assign;
-   ir_expression *expr;
-
-   for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
-      ir_rvalue *a = get_column(a_var, 0);
-      ir_rvalue *b = get_element(b_var, b_col, 0);
-
-      /* first column */
-      expr = new(mem_ctx) ir_expression(ir_binop_mul,
-                                       a->type,
-                                       a,
-                                       b);
-
-      /* following columns */
-      for (i = 1; i < a_var->type->matrix_columns; i++) {
-        ir_expression *mul_expr;
-
-        a = get_column(a_var, i);
-        b = get_element(b_var, b_col, i);
-
-        mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
-                                              a->type,
-                                              a,
-                                              b);
-        expr = new(mem_ctx) ir_expression(ir_binop_add,
-                                          a->type,
-                                          expr,
-                                          mul_expr);
-      }
-
-      ir_rvalue *result = get_column(result_var, b_col);
-      assign = new(mem_ctx) ir_assignment(result,
-                                         expr,
-                                         NULL);
-      base_ir->insert_before(assign);
-   }
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
-                                        ir_variable *a_var,
-                                        ir_variable *b_var)
-{
-   int i;
-   ir_rvalue *a = get_column(a_var, 0);
-   ir_rvalue *b = get_element(b_var, 0, 0);
-   ir_assignment *assign;
-   ir_expression *expr;
-
-   /* first column */
-   expr = new(mem_ctx) ir_expression(ir_binop_mul,
-                                    result_var->type,
-                                    a,
-                                    b);
-
-   /* following columns */
-   for (i = 1; i < a_var->type->matrix_columns; i++) {
-      ir_expression *mul_expr;
-
-      a = get_column(a_var, i);
-      b = get_element(b_var, 0, i);
-
-      mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
-                                           result_var->type,
-                                           a,
-                                           b);
-      expr = new(mem_ctx) ir_expression(ir_binop_add,
-                                       result_var->type,
-                                       expr,
-                                       mul_expr);
-   }
-
-   ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var);
-   assign = new(mem_ctx) ir_assignment(result,
-                                      expr,
-                                      NULL);
-   base_ir->insert_before(assign);
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
-                                        ir_variable *a_var,
-                                        ir_variable *b_var)
-{
-   int i;
-
-   for (i = 0; i < b_var->type->matrix_columns; i++) {
-      ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var);
-      ir_rvalue *b = get_column(b_var, i);
-      ir_rvalue *result;
-      ir_expression *column_expr;
-      ir_assignment *column_assign;
-
-      result = new(mem_ctx) ir_dereference_variable(result_var);
-      result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1);
-
-      column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
-                                              result->type,
-                                              a,
-                                              b);
-
-      column_assign = new(mem_ctx) ir_assignment(result,
-                                                column_expr,
-                                                NULL);
-      base_ir->insert_before(column_assign);
-   }
-}
-
-void
-ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
-                                           ir_variable *a_var,
-                                           ir_variable *b_var)
-{
-   int i;
-
-   for (i = 0; i < a_var->type->matrix_columns; i++) {
-      ir_rvalue *a = get_column(a_var, i);
-      ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var);
-      ir_rvalue *result = get_column(result_var, i);
-      ir_expression *column_expr;
-      ir_assignment *column_assign;
-
-      column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
-                                              result->type,
-                                              a,
-                                              b);
-
-      column_assign = new(mem_ctx) ir_assignment(result,
-                                                column_expr,
-                                                NULL);
-      base_ir->insert_before(column_assign);
-   }
-}
-
-void
-ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var,
-                                          ir_variable *a_var,
-                                          ir_variable *b_var,
-                                          bool test_equal)
-{
-   /* This essentially implements the following GLSL:
-    *
-    * bool equal(mat4 a, mat4 b)
-    * {
-    *   return !any(bvec4(a[0] != b[0],
-    *                     a[1] != b[1],
-    *                     a[2] != b[2],
-    *                     a[3] != b[3]);
-    * }
-    *
-    * bool nequal(mat4 a, mat4 b)
-    * {
-    *   return any(bvec4(a[0] != b[0],
-    *                    a[1] != b[1],
-    *                    a[2] != b[2],
-    *                    a[3] != b[3]);
-    * }
-    */
-   const unsigned columns = a_var->type->matrix_columns;
-   const glsl_type *const bvec_type =
-      glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
-
-   ir_variable *const tmp_bvec =
-      new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec",
-                                    ir_var_temporary);
-   this->base_ir->insert_before(tmp_bvec);
-
-   for (unsigned i = 0; i < columns; i++) {
-      ir_dereference *const op0 = get_column(a_var, i);
-      ir_dereference *const op1 = get_column(b_var, i);
-
-      ir_expression *const cmp =
-        new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
-                                         glsl_type::bool_type, op0, op1);
-
-      ir_dereference *const lhs =
-        new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
-
-      ir_assignment *const assign =
-        new(this->mem_ctx) ir_assignment(lhs, cmp, NULL, (1U << i));
-
-      this->base_ir->insert_before(assign);
-   }
-
-   ir_rvalue *const val =
-      new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
-
-   ir_expression *any =
-      new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type,
-                                      val, NULL);
-
-   if (test_equal)
-      any = new(this->mem_ctx) ir_expression(ir_unop_logic_not,
-                                            glsl_type::bool_type,
-                                            any, NULL);
-
-   ir_rvalue *const result =
-      new(this->mem_ctx) ir_dereference_variable(result_var);
-
-   ir_assignment *const assign =
-        new(mem_ctx) ir_assignment(result, any, NULL);
-   base_ir->insert_before(assign);
-}
-
-static bool
-has_matrix_operand(const ir_expression *expr, unsigned &columns)
-{
-   for (unsigned i = 0; i < expr->get_num_operands(); i++) {
-      if (expr->operands[i]->type->is_matrix()) {
-        columns = expr->operands[i]->type->matrix_columns;
-        return true;
-      }
-   }
-
-   return false;
-}
-
-
-ir_visitor_status
-ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign)
-{
-   ir_expression *orig_expr = orig_assign->rhs->as_expression();
-   unsigned int i, matrix_columns = 1;
-   ir_variable *op_var[2];
-
-   if (!orig_expr)
-      return visit_continue;
-
-   if (!has_matrix_operand(orig_expr, matrix_columns))
-      return visit_continue;
-
-   mem_ctx = talloc_parent(orig_assign);
-
-   ir_dereference_variable *lhs_deref =
-      orig_assign->lhs->as_dereference_variable();
-   assert(lhs_deref);
-
-   ir_variable *result_var = lhs_deref->var;
-
-   /* Store the expression operands in temps so we can use them
-    * multiple times.
-    */
-   for (i = 0; i < orig_expr->get_num_operands(); i++) {
-      ir_assignment *assign;
-
-      op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
-                                          "mat_op_to_vec",
-                                          ir_var_temporary);
-      base_ir->insert_before(op_var[i]);
-
-      lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
-      assign = new(mem_ctx) ir_assignment(lhs_deref,
-                                         orig_expr->operands[i],
-                                         NULL);
-      base_ir->insert_before(assign);
-   }
-
-   /* OK, time to break down this matrix operation. */
-   switch (orig_expr->operation) {
-   case ir_unop_neg: {
-      const unsigned mask = (1U << result_var->type->vector_elements) - 1;
-
-      /* Apply the operation to each column.*/
-      for (i = 0; i < matrix_columns; i++) {
-        ir_rvalue *op0 = get_column(op_var[0], i);
-        ir_dereference *result = get_column(result_var, i);
-        ir_expression *column_expr;
-        ir_assignment *column_assign;
-
-        column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
-                                                 result->type,
-                                                 op0,
-                                                 NULL);
-
-        column_assign = new(mem_ctx) ir_assignment(result,
-                                                   column_expr,
-                                                   NULL,
-                                                   mask);
-        assert(column_assign->write_mask != 0);
-        base_ir->insert_before(column_assign);
-      }
-      break;
-   }
-   case ir_binop_add:
-   case ir_binop_sub:
-   case ir_binop_div:
-   case ir_binop_mod: {
-      const unsigned mask = (1U << result_var->type->vector_elements) - 1;
-
-      /* For most operations, the matrix version is just going
-       * column-wise through and applying the operation to each column
-       * if available.
-       */
-      for (i = 0; i < matrix_columns; i++) {
-        ir_rvalue *op0 = get_column(op_var[0], i);
-        ir_rvalue *op1 = get_column(op_var[1], i);
-        ir_dereference *result = get_column(result_var, i);
-        ir_expression *column_expr;
-        ir_assignment *column_assign;
-
-        column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
-                                                 result->type,
-                                                 op0,
-                                                 op1);
-
-        column_assign = new(mem_ctx) ir_assignment(result,
-                                                   column_expr,
-                                                   NULL,
-                                                   mask);
-        assert(column_assign->write_mask != 0);
-        base_ir->insert_before(column_assign);
-      }
-      break;
-   }
-   case ir_binop_mul:
-      if (op_var[0]->type->is_matrix()) {
-        if (op_var[1]->type->is_matrix()) {
-           do_mul_mat_mat(result_var, op_var[0], op_var[1]);
-        } else if (op_var[1]->type->is_vector()) {
-           do_mul_mat_vec(result_var, op_var[0], op_var[1]);
-        } else {
-           assert(op_var[1]->type->is_scalar());
-           do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
-        }
-      } else {
-        assert(op_var[1]->type->is_matrix());
-        if (op_var[0]->type->is_vector()) {
-           do_mul_vec_mat(result_var, op_var[0], op_var[1]);
-        } else {
-           assert(op_var[0]->type->is_scalar());
-           do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
-        }
-      }
-      break;
-
-   case ir_binop_all_equal:
-   case ir_binop_any_nequal:
-      do_equal_mat_mat(result_var, op_var[1], op_var[0],
-                      (orig_expr->operation == ir_binop_all_equal));
-      break;
-
-   default:
-      printf("FINISHME: Handle matrix operation for %s\n",
-            orig_expr->operator_string());
-      abort();
-   }
-   orig_assign->remove();
-   this->made_progress = true;
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_mod_to_fract.cpp b/src/glsl/ir_mod_to_fract.cpp
deleted file mode 100644 (file)
index c82a1f6..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_mod_to_fract.cpp
- *
- * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1))
- *
- * Many GPUs don't have a MOD instruction (945 and 965 included), and
- * if we have to break it down like this anyway, it gives an
- * opportunity to do things like constant fold the (1.0 / op1) easily.
- */
-
-#include "ir.h"
-
-class ir_mod_to_fract_visitor : public ir_hierarchical_visitor {
-public:
-   ir_mod_to_fract_visitor()
-   {
-      this->made_progress = false;
-   }
-
-   ir_visitor_status visit_leave(ir_expression *);
-
-   bool made_progress;
-};
-
-bool
-do_mod_to_fract(exec_list *instructions)
-{
-   ir_mod_to_fract_visitor v;
-
-   visit_list_elements(&v, instructions);
-   return v.made_progress;
-}
-
-ir_visitor_status
-ir_mod_to_fract_visitor::visit_leave(ir_expression *ir)
-{
-   if (ir->operation != ir_binop_mod)
-      return visit_continue;
-
-   ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b",
-                                          ir_var_temporary);
-   this->base_ir->insert_before(temp);
-
-   ir_assignment *assign;
-   ir_rvalue *expr;
-
-   assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(temp),
-                                 ir->operands[1], NULL);
-   this->base_ir->insert_before(assign);
-
-   expr = new(ir) ir_expression(ir_binop_div,
-                               ir->operands[0]->type,
-                               ir->operands[0],
-                               new(ir) ir_dereference_variable(temp));
-
-   expr = new(ir) ir_expression(ir_unop_fract,
-                               ir->operands[0]->type,
-                               expr,
-                               NULL);
-
-   ir->operation = ir_binop_mul;
-   ir->operands[0] = new(ir) ir_dereference_variable(temp);
-   ir->operands[1] = expr;
-   this->made_progress = true;
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_noop_swizzle.cpp b/src/glsl/ir_noop_swizzle.cpp
deleted file mode 100644 (file)
index 0403dfa..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_noop_swizzle.cpp
- *
- * If a swizzle doesn't change the order or count of components, then
- * remove the swizzle so that other optimization passes see the value
- * behind it.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "ir_print_visitor.h"
-#include "glsl_types.h"
-
-class ir_noop_swizzle_visitor : public ir_rvalue_visitor {
-public:
-   ir_noop_swizzle_visitor()
-   {
-      this->progress = false;
-   }
-
-   void handle_rvalue(ir_rvalue **rvalue);
-   bool progress;
-};
-
-void
-ir_noop_swizzle_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
-   if (!*rvalue)
-      return;
-
-   ir_swizzle *swiz = (*rvalue)->as_swizzle();
-   if (!swiz || swiz->type != swiz->val->type)
-      return;
-
-   int elems = swiz->val->type->vector_elements;
-   if (swiz->mask.x != 0)
-      return;
-   if (elems >= 2 && swiz->mask.y != 1)
-      return;
-   if (elems >= 3 && swiz->mask.z != 2)
-      return;
-   if (elems >= 4 && swiz->mask.w != 3)
-      return;
-
-   this->progress = true;
-   *rvalue = swiz->val;
-}
-
-bool
-do_noop_swizzle(exec_list *instructions)
-{
-   ir_noop_swizzle_visitor v;
-   visit_list_elements(&v, instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp
deleted file mode 100644 (file)
index ff3ec93..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_structure_splitting.cpp
- *
- * If a structure is only ever referenced by its components, then
- * split those components out to individual variables so they can be
- * handled normally by other optimization passes.
- *
- * This skips structures like uniforms, which need to be accessible as
- * structures for their access by the GL.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_print_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined
-// function) with the variable_entry class seen in ir_variable_refcount.h
-// Perhaps we can use the one in ir_variable_refcount.h and make this class
-// here go away?
-class variable_entry2 : public exec_node
-{
-public:
-   variable_entry2(ir_variable *var)
-   {
-      this->var = var;
-      this->whole_structure_access = 0;
-      this->declaration = false;
-      this->components = NULL;
-      this->mem_ctx = NULL;
-   }
-
-   ir_variable *var; /* The key: the variable's pointer. */
-
-   /** Number of times the variable is referenced, including assignments. */
-   unsigned whole_structure_access;
-
-   bool declaration; /* If the variable had a decl in the instruction stream */
-
-   ir_variable **components;
-
-   /** talloc_parent(this->var) -- the shader's talloc context. */
-   void *mem_ctx;
-};
-
-
-class ir_structure_reference_visitor : public ir_hierarchical_visitor {
-public:
-   ir_structure_reference_visitor(void)
-   {
-      this->mem_ctx = talloc_new(NULL);
-      this->variable_list.make_empty();
-   }
-
-   ~ir_structure_reference_visitor(void)
-   {
-      talloc_free(mem_ctx);
-   }
-
-   virtual ir_visitor_status visit(ir_variable *);
-   virtual ir_visitor_status visit(ir_dereference_variable *);
-   virtual ir_visitor_status visit_enter(ir_dereference_record *);
-   virtual ir_visitor_status visit_enter(ir_assignment *);
-   virtual ir_visitor_status visit_enter(ir_function_signature *);
-
-   variable_entry2 *get_variable_entry2(ir_variable *var);
-
-   /* List of variable_entry */
-   exec_list variable_list;
-
-   void *mem_ctx;
-};
-
-variable_entry2 *
-ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
-{
-   assert(var);
-
-   if (!var->type->is_record() || var->mode == ir_var_uniform)
-      return NULL;
-
-   foreach_iter(exec_list_iterator, iter, this->variable_list) {
-      variable_entry2 *entry = (variable_entry2 *)iter.get();
-      if (entry->var == var)
-        return entry;
-   }
-
-   variable_entry2 *entry = new(mem_ctx) variable_entry2(var);
-   this->variable_list.push_tail(entry);
-   return entry;
-}
-
-
-ir_visitor_status
-ir_structure_reference_visitor::visit(ir_variable *ir)
-{
-   variable_entry2 *entry = this->get_variable_entry2(ir);
-
-   if (entry)
-      entry->declaration = true;
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
-{
-   ir_variable *const var = ir->variable_referenced();
-   variable_entry2 *entry = this->get_variable_entry2(var);
-
-   if (entry)
-      entry->whole_structure_access++;
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
-{
-   (void) ir;
-   /* Don't descend into the ir_dereference_variable below. */
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
-{
-   if (ir->lhs->as_dereference_variable() &&
-       ir->rhs->as_dereference_variable() &&
-       !ir->condition) {
-      /* We'll split copies of a structure to copies of components, so don't
-       * descend to the ir_dereference_variables.
-       */
-      return visit_continue_with_parent;
-   }
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
-{
-   /* We don't want to descend into the function parameters and
-    * dead-code eliminate them, so just accept the body here.
-    */
-   visit_list_elements(this, &ir->body);
-   return visit_continue_with_parent;
-}
-
-class ir_structure_splitting_visitor : public ir_rvalue_visitor {
-public:
-   ir_structure_splitting_visitor(exec_list *vars)
-   {
-      this->variable_list = vars;
-   }
-
-   virtual ~ir_structure_splitting_visitor()
-   {
-   }
-
-   virtual ir_visitor_status visit_leave(ir_assignment *);
-
-   void split_deref(ir_dereference **deref);
-   void handle_rvalue(ir_rvalue **rvalue);
-   variable_entry2 *get_splitting_entry(ir_variable *var);
-
-   exec_list *variable_list;
-   void *mem_ctx;
-};
-
-variable_entry2 *
-ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
-{
-   assert(var);
-
-   if (!var->type->is_record())
-      return NULL;
-
-   foreach_iter(exec_list_iterator, iter, *this->variable_list) {
-      variable_entry2 *entry = (variable_entry2 *)iter.get();
-      if (entry->var == var) {
-        return entry;
-      }
-   }
-
-   return NULL;
-}
-
-void
-ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
-{
-   if ((*deref)->ir_type != ir_type_dereference_record)
-      return;
-
-   ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
-   ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
-   if (!deref_var)
-      return;
-
-   variable_entry2 *entry = get_splitting_entry(deref_var->var);
-   if (!entry)
-      return;
-
-   unsigned int i;
-   for (i = 0; i < entry->var->type->length; i++) {
-      if (strcmp(deref_record->field,
-                entry->var->type->fields.structure[i].name) == 0)
-        break;
-   }
-   assert(i != entry->var->type->length);
-
-   *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
-}
-
-void
-ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
-   if (!*rvalue)
-      return;
-
-   ir_dereference *deref = (*rvalue)->as_dereference();
-
-   if (!deref)
-      return;
-
-   split_deref(&deref);
-   *rvalue = deref;
-}
-
-ir_visitor_status
-ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
-{
-   ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
-   ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
-   variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
-   variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
-   const glsl_type *type = ir->rhs->type;
-
-   if ((lhs_entry || rhs_entry) && !ir->condition) {
-      for (unsigned int i = 0; i < type->length; i++) {
-        ir_dereference *new_lhs, *new_rhs;
-        void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
-
-        if (lhs_entry) {
-           new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
-        } else {
-           new_lhs = new(mem_ctx)
-              ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
-                                    type->fields.structure[i].name);
-        }
-
-        if (rhs_entry) {
-           new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
-        } else {
-           new_rhs = new(mem_ctx)
-              ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
-                                    type->fields.structure[i].name);
-        }
-
-        ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
-                                                     new_rhs,
-                                                     NULL));
-      }
-      ir->remove();
-   } else {
-      handle_rvalue(&ir->rhs);
-      split_deref(&ir->lhs);
-   }
-
-   handle_rvalue(&ir->condition);
-
-   return visit_continue;
-}
-
-bool
-do_structure_splitting(exec_list *instructions)
-{
-   ir_structure_reference_visitor refs;
-
-   visit_list_elements(&refs, instructions);
-
-   /* Trim out variables we can't split. */
-   foreach_iter(exec_list_iterator, iter, refs.variable_list) {
-      variable_entry2 *entry = (variable_entry2 *)iter.get();
-
-      if (debug) {
-        printf("structure %s@%p: decl %d, whole_access %d\n",
-               entry->var->name, (void *) entry->var, entry->declaration,
-               entry->whole_structure_access);
-      }
-
-      if (!entry->declaration || entry->whole_structure_access) {
-        entry->remove();
-      }
-   }
-
-   if (refs.variable_list.is_empty())
-      return false;
-
-   void *mem_ctx = talloc_new(NULL);
-
-   /* Replace the decls of the structures to be split with their split
-    * components.
-    */
-   foreach_iter(exec_list_iterator, iter, refs.variable_list) {
-      variable_entry2 *entry = (variable_entry2 *)iter.get();
-      const struct glsl_type *type = entry->var->type;
-
-      entry->mem_ctx = talloc_parent(entry->var);
-
-      entry->components = talloc_array(mem_ctx,
-                                      ir_variable *,
-                                      type->length);
-
-      for (unsigned int i = 0; i < entry->var->type->length; i++) {
-        const char *name = talloc_asprintf(mem_ctx, "%s_%s",
-                                           entry->var->name,
-                                           type->fields.structure[i].name);
-
-        entry->components[i] =
-           new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
-                                           name,
-                                           ir_var_temporary);
-        entry->var->insert_before(entry->components[i]);
-      }
-
-      entry->var->remove();
-   }
-
-   ir_structure_splitting_visitor split(&refs.variable_list);
-   visit_list_elements(&split, instructions);
-
-   talloc_free(mem_ctx);
-
-   return true;
-}
diff --git a/src/glsl/ir_sub_to_add_neg.cpp b/src/glsl/ir_sub_to_add_neg.cpp
deleted file mode 100644 (file)
index 7ed8c14..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_sub_to_add_neg.cpp
- *
- * Breaks an ir_binop_sub expression down to add(op0, neg(op1))
- *
- * This simplifies expression reassociation, and for many backends
- * there is no subtract operation separate from adding the negation.
- * For backends with native subtract operations, they will probably
- * want to recognize add(op0, neg(op1)) or the other way around to
- * produce a subtract anyway.
- */
-
-#include "ir.h"
-
-class ir_sub_to_add_neg_visitor : public ir_hierarchical_visitor {
-public:
-   ir_sub_to_add_neg_visitor()
-   {
-      this->progress = false;
-   }
-
-   ir_visitor_status visit_leave(ir_expression *);
-
-   bool progress;
-};
-
-bool
-do_sub_to_add_neg(exec_list *instructions)
-{
-   ir_sub_to_add_neg_visitor v;
-
-   visit_list_elements(&v, instructions);
-   return v.progress;
-}
-
-ir_visitor_status
-ir_sub_to_add_neg_visitor::visit_leave(ir_expression *ir)
-{
-   if (ir->operation != ir_binop_sub)
-      return visit_continue;
-
-   void *mem_ctx = talloc_parent(ir);
-
-   ir->operation = ir_binop_add;
-   ir->operands[1] = new(mem_ctx) ir_expression(ir_unop_neg,
-                                               ir->operands[1]->type,
-                                               ir->operands[1],
-                                               NULL);
-
-   this->progress = true;
-
-   return visit_continue;
-}
diff --git a/src/glsl/ir_swizzle_swizzle.cpp b/src/glsl/ir_swizzle_swizzle.cpp
deleted file mode 100644 (file)
index 0ffb4fa..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_swizzle_swizzle.cpp
- *
- * Eliminates the second swizzle in a swizzle chain.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-class ir_swizzle_swizzle_visitor : public ir_hierarchical_visitor {
-public:
-   ir_swizzle_swizzle_visitor()
-   {
-      progress = false;
-   }
-
-   virtual ir_visitor_status visit_enter(ir_swizzle *);
-
-   bool progress;
-};
-
-ir_visitor_status
-ir_swizzle_swizzle_visitor::visit_enter(ir_swizzle *ir)
-{
-   int mask2[4];
-
-   ir_swizzle *swiz2 = ir->val->as_swizzle();
-   if (!swiz2)
-      return visit_continue;
-
-   memset(&mask2, 0, sizeof(mask2));
-   if (swiz2->mask.num_components >= 1)
-      mask2[0] = swiz2->mask.x;
-   if (swiz2->mask.num_components >= 2)
-      mask2[1] = swiz2->mask.y;
-   if (swiz2->mask.num_components >= 3)
-      mask2[2] = swiz2->mask.z;
-   if (swiz2->mask.num_components >= 4)
-      mask2[3] = swiz2->mask.w;
-
-   if (ir->mask.num_components >= 1)
-      ir->mask.x = mask2[ir->mask.x];
-   if (ir->mask.num_components >= 2)
-      ir->mask.y = mask2[ir->mask.y];
-   if (ir->mask.num_components >= 3)
-      ir->mask.z = mask2[ir->mask.z];
-   if (ir->mask.num_components >= 4)
-      ir->mask.w = mask2[ir->mask.w];
-
-   ir->val = swiz2->val;
-
-   this->progress = true;
-
-   return visit_continue;
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_swizzle_swizzle(exec_list *instructions)
-{
-   ir_swizzle_swizzle_visitor v;
-
-   v.run(instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_tree_grafting.cpp b/src/glsl/ir_tree_grafting.cpp
deleted file mode 100644 (file)
index 9b569b8..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_tree_grafting.cpp
- *
- * Takes assignments to variables that are dereferenced only once and
- * pastes the RHS expression into where the variable is dereferenced.
- *
- * In the process of various operations like function inlining and
- * tertiary op handling, we'll end up with our expression trees having
- * been chopped up into a series of assignments of short expressions
- * to temps.  Other passes like ir_algebraic.cpp would prefer to see
- * the deepest expression trees they can to try to optimize them.
- *
- * This is a lot like copy propagaton.  In comparison, copy
- * propagation only acts on plain copies, not arbitrary expressions on
- * the RHS.  Generally, we wouldn't want to go pasting some
- * complicated expression everywhere it got used, though, so we don't
- * handle expressions in that pass.
- *
- * The hard part is making sure we don't move an expression across
- * some other assignments that would change the value of the
- * expression.  So we split this into two passes: First, find the
- * variables in our scope which are written to once and read once, and
- * then go through basic blocks seeing if we find an opportunity to
- * move those expressions safely.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_variable_refcount.h"
-#include "ir_basic_block.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-class ir_tree_grafting_visitor : public ir_hierarchical_visitor {
-public:
-   ir_tree_grafting_visitor(ir_assignment *graft_assign,
-                           ir_variable *graft_var)
-   {
-      this->progress = false;
-      this->graft_assign = graft_assign;
-      this->graft_var = graft_var;
-   }
-
-   virtual ir_visitor_status visit_leave(class ir_assignment *);
-   virtual ir_visitor_status visit_enter(class ir_call *);
-   virtual ir_visitor_status visit_enter(class ir_expression *);
-   virtual ir_visitor_status visit_enter(class ir_function *);
-   virtual ir_visitor_status visit_enter(class ir_function_signature *);
-   virtual ir_visitor_status visit_enter(class ir_if *);
-   virtual ir_visitor_status visit_enter(class ir_loop *);
-   virtual ir_visitor_status visit_enter(class ir_swizzle *);
-   virtual ir_visitor_status visit_enter(class ir_texture *);
-
-   bool do_graft(ir_rvalue **rvalue);
-
-   bool progress;
-   ir_variable *graft_var;
-   ir_assignment *graft_assign;
-};
-
-struct find_deref_info {
-   ir_variable *var;
-   bool found;
-};
-
-void
-dereferences_variable_callback(ir_instruction *ir, void *data)
-{
-   struct find_deref_info *info = (struct find_deref_info *)data;
-   ir_dereference_variable *deref = ir->as_dereference_variable();
-
-   if (deref && deref->var == info->var)
-      info->found = true;
-}
-
-static bool
-dereferences_variable(ir_instruction *ir, ir_variable *var)
-{
-   struct find_deref_info info;
-
-   info.var = var;
-   info.found = false;
-
-   visit_tree(ir, dereferences_variable_callback, &info);
-
-   return info.found;
-}
-
-bool
-ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue)
-{
-   if (!*rvalue)
-      return false;
-
-   ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
-
-   if (!deref || deref->var != this->graft_var)
-      return false;
-
-   if (debug) {
-      printf("GRAFTING:\n");
-      this->graft_assign->print();
-      printf("\n");
-      printf("TO:\n");
-      (*rvalue)->print();
-      printf("\n");
-   }
-
-   this->graft_assign->remove();
-   *rvalue = this->graft_assign->rhs;
-
-   this->progress = true;
-   return true;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_loop *ir)
-{
-   (void)ir;
-   /* Do not traverse into the body of the loop since that is a
-    * different basic block.
-    */
-   return visit_stop;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_leave(ir_assignment *ir)
-{
-   if (do_graft(&ir->rhs) ||
-       do_graft(&ir->condition))
-      return visit_stop;
-
-   /* If this assignment updates a variable used in the assignment
-    * we're trying to graft, then we're done.
-    */
-   if (dereferences_variable(this->graft_assign->rhs,
-                            ir->lhs->variable_referenced())) {
-      if (debug) {
-        printf("graft killed by: ");
-        ir->print();
-        printf("\n");
-      }
-      return visit_stop;
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_function *ir)
-{
-   (void) ir;
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
-{
-   (void)ir;
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_call *ir)
-{
-   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
-   /* Reminder: iterating ir_call iterates its parameters. */
-   foreach_iter(exec_list_iterator, iter, *ir) {
-      ir_variable *sig_param = (ir_variable *)sig_iter.get();
-      ir_rvalue *ir = (ir_rvalue *)iter.get();
-      ir_rvalue *new_ir = ir;
-
-      if (sig_param->mode != ir_var_in)
-        continue;
-
-      if (do_graft(&new_ir)) {
-        ir->replace_with(new_ir);
-        return visit_stop;
-      }
-      sig_iter.next();
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_expression *ir)
-{
-   for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
-      if (do_graft(&ir->operands[i]))
-        return visit_stop;
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_if *ir)
-{
-   if (do_graft(&ir->condition))
-      return visit_stop;
-
-   /* Do not traverse into the body of the if-statement since that is a
-    * different basic block.
-    */
-   return visit_continue_with_parent;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir)
-{
-   if (do_graft(&ir->val))
-      return visit_stop;
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_tree_grafting_visitor::visit_enter(ir_texture *ir)
-{
-   if (do_graft(&ir->coordinate) ||
-       do_graft(&ir->projector) ||
-       do_graft(&ir->shadow_comparitor))
-        return visit_stop;
-
-   switch (ir->op) {
-   case ir_tex:
-      break;
-   case ir_txb:
-      if (do_graft(&ir->lod_info.bias))
-        return visit_stop;
-      break;
-   case ir_txf:
-   case ir_txl:
-      if (do_graft(&ir->lod_info.lod))
-        return visit_stop;
-      break;
-   case ir_txd:
-      if (do_graft(&ir->lod_info.grad.dPdx) ||
-         do_graft(&ir->lod_info.grad.dPdy))
-        return visit_stop;
-      break;
-   }
-
-   return visit_continue;
-}
-
-struct tree_grafting_info {
-   ir_variable_refcount_visitor *refs;
-   bool progress;
-};
-
-static bool
-try_tree_grafting(ir_assignment *start,
-                 ir_variable *lhs_var,
-                 ir_instruction *bb_last)
-{
-   ir_tree_grafting_visitor v(start, lhs_var);
-
-   if (debug) {
-      printf("trying to graft: ");
-      lhs_var->print();
-      printf("\n");
-   }
-
-   for (ir_instruction *ir = (ir_instruction *)start->next;
-       ir != bb_last->next;
-       ir = (ir_instruction *)ir->next) {
-
-      if (debug) {
-        printf("- ");
-        ir->print();
-        printf("\n");
-      }
-
-      ir_visitor_status s = ir->accept(&v);
-      if (s == visit_stop)
-        return v.progress;
-   }
-
-   return false;
-}
-
-static void
-tree_grafting_basic_block(ir_instruction *bb_first,
-                         ir_instruction *bb_last,
-                         void *data)
-{
-   struct tree_grafting_info *info = (struct tree_grafting_info *)data;
-   ir_instruction *ir, *next;
-
-   for (ir = bb_first, next = (ir_instruction *)ir->next;
-       ir != bb_last->next;
-       ir = next, next = (ir_instruction *)ir->next) {
-      ir_assignment *assign = ir->as_assignment();
-
-      if (!assign)
-        continue;
-
-      ir_variable *lhs_var = assign->whole_variable_written();
-      if (!lhs_var)
-        continue;
-
-      if (lhs_var->mode == ir_var_out ||
-         lhs_var->mode == ir_var_inout)
-        continue;
-
-      variable_entry *entry = info->refs->get_variable_entry(lhs_var);
-
-      if (!entry->declaration ||
-         entry->assigned_count != 1 ||
-         entry->referenced_count != 2)
-        continue;
-
-      assert(assign == entry->assign);
-
-      /* Found a possibly graftable assignment.  Now, walk through the
-       * rest of the BB seeing if the deref is here, and if nothing interfered with
-       * pasting its expression's values in between.
-       */
-      info->progress |= try_tree_grafting(assign, lhs_var, bb_last);
-   }
-}
-
-/**
- * Does a copy propagation pass on the code present in the instruction stream.
- */
-bool
-do_tree_grafting(exec_list *instructions)
-{
-   ir_variable_refcount_visitor refs;
-   struct tree_grafting_info info;
-
-   info.progress = false;
-   info.refs = &refs;
-
-   visit_list_elements(info.refs, instructions);
-
-   call_for_basic_blocks(instructions, tree_grafting_basic_block, &info);
-
-   return info.progress;
-}
diff --git a/src/glsl/ir_vec_index_to_cond_assign.cpp b/src/glsl/ir_vec_index_to_cond_assign.cpp
deleted file mode 100644 (file)
index cd8dedf..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_vec_index_to_cond_assign.cpp
- *
- * Turns indexing into vector types to a series of conditional moves
- * of each channel's swizzle into a temporary.
- *
- * Most GPUs don't have a native way to do this operation, and this
- * works around that.  For drivers using both this pass and
- * ir_vec_index_to_swizzle, there's a risk that this pass will happen
- * before sufficient constant folding to find that the array index is
- * constant.  However, we hope that other optimization passes,
- * particularly constant folding of assignment conditions and copy
- * propagation, will result in the same code in the end.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
-public:
-   ir_vec_index_to_cond_assign_visitor()
-   {
-      progress = false;
-   }
-
-   ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
-
-   virtual ir_visitor_status visit_enter(ir_expression *);
-   virtual ir_visitor_status visit_enter(ir_swizzle *);
-   virtual ir_visitor_status visit_leave(ir_assignment *);
-   virtual ir_visitor_status visit_enter(ir_return *);
-   virtual ir_visitor_status visit_enter(ir_call *);
-   virtual ir_visitor_status visit_enter(ir_if *);
-
-   bool progress;
-};
-
-ir_rvalue *
-ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
-{
-   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;
-
-   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);
-
-   /* 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);
-   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);
-
-   /* Temporary where we store whichever value we swizzle out. */
-   var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
-                                 ir_var_temporary);
-   base_ir->insert_before(var);
-
-   /* 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));
-
-      /* 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);
-
-      deref = new(base_ir) ir_dereference_variable(var);
-      assign = new(base_ir) ir_assignment(deref, swizzle, condition);
-      base_ir->insert_before(assign);
-   }
-
-   this->progress = true;
-   return new(base_ir) ir_dereference_variable(var);
-}
-
-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]);
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
-{
-   /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
-    * 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);
-
-   return visit_continue;
-}
-
-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);
-
-   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);
-   }
-   ir->remove();
-
-   this->progress = true;
-
-   return visit_continue;
-}
-
-ir_visitor_status
-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);
-
-      if (new_param != param) {
-        param->replace_with(new_param);
-      }
-   }
-
-   return visit_continue;
-}
-
-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);
-   }
-
-   return visit_continue;
-}
-
-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);
-
-   return visit_continue;
-}
-
-bool
-do_vec_index_to_cond_assign(exec_list *instructions)
-{
-   ir_vec_index_to_cond_assign_visitor v;
-
-   visit_list_elements(&v, instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/ir_vec_index_to_swizzle.cpp b/src/glsl/ir_vec_index_to_swizzle.cpp
deleted file mode 100644 (file)
index 969dc8f..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file ir_vec_index_to_swizzle.cpp
- *
- * Turns constant indexing into vector types to swizzles.  This will
- * let other swizzle-aware optimization passes catch these constructs,
- * and codegen backends not have to worry about this case.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_optimization.h"
-#include "glsl_types.h"
-
-/**
- * Visitor class for replacing expressions with ir_constant values.
- */
-
-class ir_vec_index_to_swizzle_visitor : public ir_hierarchical_visitor {
-public:
-   ir_vec_index_to_swizzle_visitor()
-   {
-      progress = false;
-   }
-
-   ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val);
-
-   virtual ir_visitor_status visit_enter(ir_expression *);
-   virtual ir_visitor_status visit_enter(ir_swizzle *);
-   virtual ir_visitor_status visit_enter(ir_assignment *);
-   virtual ir_visitor_status visit_enter(ir_return *);
-   virtual ir_visitor_status visit_enter(ir_call *);
-   virtual ir_visitor_status visit_enter(ir_if *);
-
-   bool progress;
-};
-
-ir_rvalue *
-ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
-{
-   ir_dereference_array *deref = ir->as_dereference_array();
-   ir_constant *ir_constant;
-
-   if (!deref)
-      return ir;
-
-   if (deref->array->type->is_matrix() || deref->array->type->is_array())
-      return ir;
-
-   assert(deref->array_index->type->base_type == GLSL_TYPE_INT);
-   ir_constant = deref->array_index->constant_expression_value();
-   if (!ir_constant)
-      return ir;
-
-   void *ctx = talloc_parent(ir);
-   this->progress = true;
-   return new(ctx) ir_swizzle(deref->array,
-                             ir_constant->value.i[0], 0, 0, 0, 1);
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_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_swizzle(ir->operands[i]);
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
-{
-   /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
-    * 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_swizzle(ir->val);
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
-{
-   ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
-   ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_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_swizzle(param);
-
-      if (new_param != param) {
-        param->replace_with(new_param);
-      }
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
-{
-   if (ir->value) {
-      ir->value = convert_vec_index_to_swizzle(ir->value);
-   }
-
-   return visit_continue;
-}
-
-ir_visitor_status
-ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir)
-{
-   ir->condition = convert_vec_index_to_swizzle(ir->condition);
-
-   return visit_continue;
-}
-
-bool
-do_vec_index_to_swizzle(exec_list *instructions)
-{
-   ir_vec_index_to_swizzle_visitor v;
-
-   v.run(instructions);
-
-   return v.progress;
-}
diff --git a/src/glsl/lower_div_to_mul_rcp.cpp b/src/glsl/lower_div_to_mul_rcp.cpp
new file mode 100644 (file)
index 0000000..640d5d6
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_div_to_mul_rcp.cpp
+ *
+ * Breaks an ir_unop_div expression down to op0 * (rcp(op1)).
+ *
+ * Many GPUs don't have a divide instruction (945 and 965 included),
+ * but they do have an RCP instruction to compute an approximate
+ * reciprocal.  By breaking the operation down, constant reciprocals
+ * can get constant folded.
+ */
+
+#include "ir.h"
+#include "glsl_types.h"
+
+class ir_div_to_mul_rcp_visitor : public ir_hierarchical_visitor {
+public:
+   ir_div_to_mul_rcp_visitor()
+   {
+      this->made_progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_expression *);
+
+   bool made_progress;
+};
+
+bool
+do_div_to_mul_rcp(exec_list *instructions)
+{
+   ir_div_to_mul_rcp_visitor v;
+
+   visit_list_elements(&v, instructions);
+   return v.made_progress;
+}
+
+ir_visitor_status
+ir_div_to_mul_rcp_visitor::visit_leave(ir_expression *ir)
+{
+   if (ir->operation != ir_binop_div)
+      return visit_continue;
+
+   if (ir->operands[1]->type->base_type != GLSL_TYPE_INT &&
+       ir->operands[1]->type->base_type != GLSL_TYPE_UINT) {
+      /* New expression for the 1.0 / op1 */
+      ir_rvalue *expr;
+      expr = new(ir) ir_expression(ir_unop_rcp,
+                                  ir->operands[1]->type,
+                                  ir->operands[1],
+                                  NULL);
+
+      /* op0 / op1 -> op0 * (1.0 / op1) */
+      ir->operation = ir_binop_mul;
+      ir->operands[1] = expr;
+   } else {
+      /* Be careful with integer division -- we need to do it as a
+       * float and re-truncate, since rcp(n > 1) of an integer would
+       * just be 0.
+       */
+      ir_rvalue *op0, *op1;
+      const struct glsl_type *vec_type;
+
+      vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+                                        ir->operands[1]->type->vector_elements,
+                                        ir->operands[1]->type->matrix_columns);
+
+      if (ir->operands[1]->type->base_type == GLSL_TYPE_INT)
+        op1 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[1], NULL);
+      else
+        op1 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[1], NULL);
+
+      op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL);
+
+      vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+                                        ir->operands[0]->type->vector_elements,
+                                        ir->operands[0]->type->matrix_columns);
+
+      if (ir->operands[0]->type->base_type == GLSL_TYPE_INT)
+        op0 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[0], NULL);
+      else
+        op0 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[0], NULL);
+
+      op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1);
+
+      ir->operation = ir_unop_f2i;
+      ir->operands[0] = op0;
+      ir->operands[1] = NULL;
+   }
+
+   this->made_progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/lower_explog_to_explog2.cpp b/src/glsl/lower_explog_to_explog2.cpp
new file mode 100644 (file)
index 0000000..78694a2
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_explog_to_explog2.cpp
+ *
+ * Many GPUs don't have a base e log or exponent instruction, but they
+ * do have base 2 versions, so this pass converts exp and log to exp2
+ * and log2 operations.
+ */
+
+#include "main/core.h" /* for log2f on MSVC */
+#include "ir.h"
+#include "glsl_types.h"
+
+class ir_explog_to_explog2_visitor : public ir_hierarchical_visitor {
+public:
+   ir_explog_to_explog2_visitor()
+   {
+      this->progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_expression *);
+
+   bool progress;
+};
+
+bool
+do_explog_to_explog2(exec_list *instructions)
+{
+   ir_explog_to_explog2_visitor v;
+
+   visit_list_elements(&v, instructions);
+   return v.progress;
+}
+
+ir_visitor_status
+ir_explog_to_explog2_visitor::visit_leave(ir_expression *ir)
+{
+   if (ir->operation == ir_unop_exp) {
+      void *mem_ctx = talloc_parent(ir);
+      ir_constant *log2_e = new(mem_ctx) ir_constant(log2f(M_E));
+
+      ir->operation = ir_unop_exp2;
+      ir->operands[0] = new(mem_ctx) ir_expression(ir_binop_mul,
+                                                  ir->operands[0]->type,
+                                                  ir->operands[0],
+                                                  log2_e);
+      this->progress = true;
+   }
+
+   if (ir->operation == ir_unop_log) {
+      void *mem_ctx = talloc_parent(ir);
+
+      ir->operation = ir_binop_mul;
+      ir->operands[0] = new(mem_ctx) ir_expression(ir_unop_log2,
+                                                  ir->operands[0]->type,
+                                                  ir->operands[0],
+                                                  NULL);
+      ir->operands[1] = new(mem_ctx) ir_constant(1.0f / log2f(M_E));
+      this->progress = true;
+   }
+
+   return visit_continue;
+}
diff --git a/src/glsl/lower_if_to_cond_assign.cpp b/src/glsl/lower_if_to_cond_assign.cpp
new file mode 100644 (file)
index 0000000..0b87413
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_if_to_cond_assign.cpp
+ *
+ * This attempts to flatten all if statements to conditional
+ * assignments for GPUs that don't do control flow.
+ *
+ * It can't handle other control flow being inside of its block, such
+ * as calls or loops.  Hopefully loop unrolling and inlining will take
+ * care of those.
+ */
+
+#include "glsl_types.h"
+#include "ir.h"
+
+class ir_if_to_cond_assign_visitor : public ir_hierarchical_visitor {
+public:
+   ir_if_to_cond_assign_visitor()
+   {
+      this->progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_if *);
+
+   bool progress;
+};
+
+bool
+do_if_to_cond_assign(exec_list *instructions)
+{
+   ir_if_to_cond_assign_visitor v;
+
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
+
+void
+check_control_flow(ir_instruction *ir, void *data)
+{
+   bool *found_control_flow = (bool *)data;
+   switch (ir->ir_type) {
+   case ir_type_call:
+   case ir_type_discard:
+   case ir_type_loop:
+   case ir_type_loop_jump:
+   case ir_type_return:
+      *found_control_flow = true;
+      break;
+   default:
+      break;
+   }
+}
+
+void
+move_block_to_cond_assign(void *mem_ctx,
+                         ir_if *if_ir, ir_variable *cond_var, bool then)
+{
+   exec_list *instructions;
+
+   if (then) {
+      instructions = &if_ir->then_instructions;
+   } else {
+      instructions = &if_ir->else_instructions;
+   }
+
+   foreach_iter(exec_list_iterator, iter, *instructions) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+
+      if (ir->ir_type == ir_type_assignment) {
+        ir_assignment *assign = (ir_assignment *)ir;
+        ir_rvalue *cond_expr;
+        ir_dereference *deref = new(mem_ctx) ir_dereference_variable(cond_var);
+
+        if (then) {
+           cond_expr = deref;
+        } else {
+           cond_expr = new(mem_ctx) ir_expression(ir_unop_logic_not,
+                                                  glsl_type::bool_type,
+                                                  deref,
+                                                  NULL);
+        }
+
+        if (!assign->condition) {
+           assign->condition = cond_expr;
+        } else {
+           assign->condition = new(mem_ctx) ir_expression(ir_binop_logic_and,
+                                                          glsl_type::bool_type,
+                                                          cond_expr,
+                                                          assign->condition);
+        }
+      }
+
+      /* Now, move from the if block to the block surrounding it. */
+      ir->remove();
+      if_ir->insert_before(ir);
+   }
+}
+
+ir_visitor_status
+ir_if_to_cond_assign_visitor::visit_leave(ir_if *ir)
+{
+   bool found_control_flow = false;
+   ir_variable *cond_var;
+   ir_assignment *assign;
+   ir_dereference_variable *deref;
+
+   /* Check that both blocks don't contain anything we can't support. */
+   foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
+      ir_instruction *then_ir = (ir_instruction *)then_iter.get();
+      visit_tree(then_ir, check_control_flow, &found_control_flow);
+   }
+   foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
+      ir_instruction *else_ir = (ir_instruction *)else_iter.get();
+      visit_tree(else_ir, check_control_flow, &found_control_flow);
+   }
+   if (found_control_flow)
+      return visit_continue;
+
+   void *mem_ctx = talloc_parent(ir);
+
+   /* Store the condition to a variable so the assignment conditions are
+    * simpler.
+    */
+   cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type,
+                                      "if_to_cond_assign_condition",
+                                      ir_var_temporary);
+   ir->insert_before(cond_var);
+
+   deref = new(mem_ctx) ir_dereference_variable(cond_var);
+   assign = new(mem_ctx) ir_assignment(deref,
+                                      ir->condition, NULL);
+   ir->insert_before(assign);
+
+   /* Now, move all of the instructions out of the if blocks, putting
+    * conditions on assignments.
+    */
+   move_block_to_cond_assign(mem_ctx, ir, cond_var, true);
+   move_block_to_cond_assign(mem_ctx, ir, cond_var, false);
+
+   ir->remove();
+
+   this->progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/lower_jumps.cpp b/src/glsl/lower_jumps.cpp
new file mode 100644 (file)
index 0000000..b69cc1e
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * Copyright © 2010 Luca Barbieri
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_lower_jumps.cpp
+ */
+
+#include "glsl_types.h"
+#include <string.h>
+#include "ir.h"
+
+enum jump_strength
+{
+   strength_none,
+   strength_always_clears_execute_flag,
+   strength_continue,
+   strength_break,
+   strength_return,
+   strength_discard
+};
+
+struct block_record
+{
+   /* minimum jump strength (of lowered IR, not pre-lowering IR)
+    *
+    * If the block ends with a jump, must be the strength of the jump.
+    * Otherwise, the jump would be dead and have been deleted before)
+    *
+    * If the block doesn't end with a jump, it can be different than strength_none if all paths before it lead to some jump
+    * (e.g. an if with a return in one branch, and a break in the other, while not lowering them)
+    * Note that identical jumps are usually unified though.
+    */
+   jump_strength min_strength;
+
+   /* can anything clear the execute flag? */
+   bool may_clear_execute_flag;
+
+   block_record()
+   {
+      this->min_strength = strength_none;
+      this->may_clear_execute_flag = false;
+   }
+};
+
+struct loop_record
+{
+   ir_function_signature* signature;
+   ir_loop* loop;
+
+   /* used to avoid lowering the break used to represent lowered breaks */
+   unsigned nesting_depth;
+   bool in_if_at_the_end_of_the_loop;
+
+   bool may_set_return_flag;
+
+   ir_variable* break_flag;
+   ir_variable* execute_flag; /* cleared to emulate continue */
+
+   loop_record(ir_function_signature* p_signature = 0, ir_loop* p_loop = 0)
+   {
+      this->signature = p_signature;
+      this->loop = p_loop;
+      this->nesting_depth = 0;
+      this->in_if_at_the_end_of_the_loop = false;
+      this->may_set_return_flag = false;
+      this->break_flag = 0;
+      this->execute_flag = 0;
+   }
+
+   ir_variable* get_execute_flag()
+   {
+      /* also supported for the "function loop" */
+      if(!this->execute_flag) {
+         exec_list& list = this->loop ? this->loop->body_instructions : signature->body;
+         this->execute_flag = new(this->signature) ir_variable(glsl_type::bool_type, "execute_flag", ir_var_temporary);
+         list.push_head(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(execute_flag), new(this->signature) ir_constant(true), 0));
+         list.push_head(this->execute_flag);
+      }
+      return this->execute_flag;
+   }
+
+   ir_variable* get_break_flag()
+   {
+      assert(this->loop);
+      if(!this->break_flag) {
+         this->break_flag = new(this->signature) ir_variable(glsl_type::bool_type, "break_flag", ir_var_temporary);
+         this->loop->insert_before(this->break_flag);
+         this->loop->insert_before(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(break_flag), new(this->signature) ir_constant(false), 0));
+      }
+      return this->break_flag;
+   }
+};
+
+struct function_record
+{
+   ir_function_signature* signature;
+   ir_variable* return_flag; /* used to break out of all loops and then jump to the return instruction */
+   ir_variable* return_value;
+   bool is_main;
+   unsigned nesting_depth;
+
+   function_record(ir_function_signature* p_signature = 0)
+   {
+      this->signature = p_signature;
+      this->return_flag = 0;
+      this->return_value = 0;
+      this->nesting_depth = 0;
+      this->is_main = this->signature && (strcmp(this->signature->function_name(), "main") == 0);
+   }
+
+   ir_variable* get_return_flag()
+   {
+      if(!this->return_flag) {
+         this->return_flag = new(this->signature) ir_variable(glsl_type::bool_type, "return_flag", ir_var_temporary);
+         this->signature->body.push_head(new(this->signature) ir_assignment(new(this->signature) ir_dereference_variable(return_flag), new(this->signature) ir_constant(false), 0));
+         this->signature->body.push_head(this->return_flag);
+      }
+      return this->return_flag;
+   }
+
+   ir_variable* get_return_value()
+   {
+      if(!this->return_value) {
+         assert(!this->signature->return_type->is_void());
+         return_value = new(this->signature) ir_variable(this->signature->return_type, "return_value", ir_var_temporary);
+         this->signature->body.push_head(this->return_value);
+      }
+      return this->return_value;
+   }
+};
+
+struct ir_lower_jumps_visitor : public ir_control_flow_visitor {
+   bool progress;
+
+   struct function_record function;
+   struct loop_record loop;
+   struct block_record block;
+
+   bool pull_out_jumps;
+   bool lower_continue;
+   bool lower_break;
+   bool lower_sub_return;
+   bool lower_main_return;
+
+   ir_lower_jumps_visitor()
+   {
+      this->progress = false;
+   }
+
+   void truncate_after_instruction(exec_node *ir)
+   {
+      if (!ir)
+         return;
+
+      while (!ir->get_next()->is_tail_sentinel()) {
+         ((ir_instruction *)ir->get_next())->remove();
+         this->progress = true;
+      }
+   }
+
+   void move_outer_block_inside(ir_instruction *ir, exec_list *inner_block)
+   {
+      while (!ir->get_next()->is_tail_sentinel()) {
+         ir_instruction *move_ir = (ir_instruction *)ir->get_next();
+
+         move_ir->remove();
+         inner_block->push_tail(move_ir);
+      }
+   }
+
+   virtual void visit(class ir_loop_jump * ir)
+   {
+      truncate_after_instruction(ir);
+      this->block.min_strength = ir->is_break() ? strength_break : strength_continue;
+   }
+
+   virtual void visit(class ir_return * ir)
+   {
+      truncate_after_instruction(ir);
+      this->block.min_strength = strength_return;
+   }
+
+   virtual void visit(class ir_discard * ir)
+   {
+      truncate_after_instruction(ir);
+      this->block.min_strength = strength_discard;
+   }
+
+   enum jump_strength get_jump_strength(ir_instruction* ir)
+   {
+      if(!ir)
+         return strength_none;
+      else if(ir->ir_type == ir_type_loop_jump) {
+         if(((ir_loop_jump*)ir)->is_break())
+            return strength_break;
+         else
+            return strength_continue;
+      } else if(ir->ir_type == ir_type_return)
+         return strength_return;
+      else if(ir->ir_type == ir_type_discard)
+         return strength_discard;
+      else
+         return strength_none;
+   }
+
+   bool should_lower_jump(ir_jump* ir)
+   {
+      unsigned strength = get_jump_strength(ir);
+      bool lower;
+      switch(strength)
+      {
+      case strength_none:
+         lower = false; /* don't change this, code relies on it */
+         break;
+      case strength_continue:
+         lower = lower_continue;
+         break;
+      case strength_break:
+         assert(this->loop.loop);
+         /* never lower "canonical break" */
+         if(ir->get_next()->is_tail_sentinel() && (this->loop.nesting_depth == 0
+               || (this->loop.nesting_depth == 1 && this->loop.in_if_at_the_end_of_the_loop)))
+            lower = false;
+         else
+            lower = lower_break;
+         break;
+      case strength_return:
+         /* never lower return at the end of a this->function */
+         if(this->function.nesting_depth == 0 && ir->get_next()->is_tail_sentinel())
+            lower = false;
+         else if (this->function.is_main)
+            lower = lower_main_return;
+         else
+            lower = lower_sub_return;
+         break;
+      case strength_discard:
+         lower = false; /* probably nothing needs this lowered */
+         break;
+      }
+      return lower;
+   }
+
+   block_record visit_block(exec_list* list)
+   {
+      block_record saved_block = this->block;
+      this->block = block_record();
+      visit_exec_list(list, this);
+      block_record ret = this->block;
+      this->block = saved_block;
+      return ret;
+   }
+
+   virtual void visit(ir_if *ir)
+   {
+      if(this->loop.nesting_depth == 0 && ir->get_next()->is_tail_sentinel())
+         this->loop.in_if_at_the_end_of_the_loop = true;
+
+      ++this->function.nesting_depth;
+      ++this->loop.nesting_depth;
+
+      block_record block_records[2];
+      ir_jump* jumps[2];
+
+      block_records[0] = visit_block(&ir->then_instructions);
+      block_records[1] = visit_block(&ir->else_instructions);
+
+retry: /* we get here if we put code after the if inside a branch */
+   for(unsigned i = 0; i < 2; ++i) {
+      exec_list& list = i ? ir->else_instructions : ir->then_instructions;
+      jumps[i] = 0;
+      if(!list.is_empty() && get_jump_strength((ir_instruction*)list.get_tail()))
+         jumps[i] = (ir_jump*)list.get_tail();
+   }
+
+      for(;;) {
+         jump_strength jump_strengths[2];
+
+         for(unsigned i = 0; i < 2; ++i) {
+            if(jumps[i]) {
+               jump_strengths[i] = block_records[i].min_strength;
+               assert(jump_strengths[i] == get_jump_strength(jumps[i]));
+            } else
+               jump_strengths[i] = strength_none;
+         }
+
+         /* move both jumps out if possible */
+         if(pull_out_jumps && jump_strengths[0] == jump_strengths[1]) {
+            bool unify = true;
+            if(jump_strengths[0] == strength_continue)
+               ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_continue));
+            else if(jump_strengths[0] == strength_break)
+               ir->insert_after(new(ir) ir_loop_jump(ir_loop_jump::jump_break));
+            /* FINISHME: unify returns with identical expressions */
+            else if(jump_strengths[0] == strength_return && this->function.signature->return_type->is_void())
+               ir->insert_after(new(ir) ir_return(NULL));
+            /* FINISHME: unify discards */
+            else
+               unify = false;
+
+            if(unify) {
+               jumps[0]->remove();
+               jumps[1]->remove();
+               this->progress = true;
+
+               jumps[0] = 0;
+               jumps[1] = 0;
+               block_records[0].min_strength = strength_none;
+               block_records[1].min_strength = strength_none;
+               break;
+            }
+         }
+
+         /* lower a jump: if both need to lowered, start with the strongest one, so that
+          * we might later unify the lowered version with the other one
+          */
+         bool should_lower[2];
+         for(unsigned i = 0; i < 2; ++i)
+            should_lower[i] = should_lower_jump(jumps[i]);
+
+         int lower;
+         if(should_lower[1] && should_lower[0])
+            lower = jump_strengths[1] > jump_strengths[0];
+         else if(should_lower[0])
+            lower = 0;
+         else if(should_lower[1])
+            lower = 1;
+         else
+            break;
+
+         if(jump_strengths[lower] == strength_return) {
+            ir_variable* return_flag = this->function.get_return_flag();
+            if(!this->function.signature->return_type->is_void()) {
+               ir_variable* return_value = this->function.get_return_value();
+               jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(return_value), ((ir_return*)jumps[lower])->value, NULL));
+            }
+            jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(return_flag), new (ir) ir_constant(true), NULL));
+            this->loop.may_set_return_flag = true;
+            if(this->loop.loop) {
+               ir_loop_jump* lowered = 0;
+               lowered = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
+               block_records[lower].min_strength = strength_break;
+               jumps[lower]->replace_with(lowered);
+               jumps[lower] = lowered;
+            } else
+               goto lower_continue;
+            this->progress = true;
+         } else if(jump_strengths[lower] == strength_break) {
+            /* We can't lower to an actual continue because that would execute the increment.
+             *
+             * In the lowered code, we instead put the break check between the this->loop body and the increment,
+             * which is impossible with a real continue as defined by the GLSL IR currently.
+             *
+             * Smarter options (such as undoing the increment) are possible but it's not worth implementing them,
+             * because if break is lowered, continue is almost surely lowered too.
+             */
+            jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(this->loop.get_break_flag()), new (ir) ir_constant(true), 0));
+            goto lower_continue;
+         } else if(jump_strengths[lower] == strength_continue) {
+lower_continue:
+            ir_variable* execute_flag = this->loop.get_execute_flag();
+            jumps[lower]->replace_with(new(ir) ir_assignment(new (ir) ir_dereference_variable(execute_flag), new (ir) ir_constant(false), 0));
+            jumps[lower] = 0;
+            block_records[lower].min_strength = strength_always_clears_execute_flag;
+            block_records[lower].may_clear_execute_flag = true;
+            this->progress = true;
+            break;
+         }
+      }
+
+      /* move out a jump out if possible */
+      if(pull_out_jumps) {
+         int move_out = -1;
+         if(jumps[0] && block_records[1].min_strength >= strength_continue)
+            move_out = 0;
+         else if(jumps[1] && block_records[0].min_strength >= strength_continue)
+            move_out = 1;
+
+         if(move_out >= 0)
+         {
+            jumps[move_out]->remove();
+            ir->insert_after(jumps[move_out]);
+            jumps[move_out] = 0;
+            block_records[move_out].min_strength = strength_none;
+            this->progress = true;
+         }
+      }
+
+      if(block_records[0].min_strength < block_records[1].min_strength)
+         this->block.min_strength = block_records[0].min_strength;
+      else
+         this->block.min_strength = block_records[1].min_strength;
+      this->block.may_clear_execute_flag = this->block.may_clear_execute_flag || block_records[0].may_clear_execute_flag || block_records[1].may_clear_execute_flag;
+
+      if(this->block.min_strength)
+         truncate_after_instruction(ir);
+      else if(this->block.may_clear_execute_flag)
+      {
+         int move_into = -1;
+         if(block_records[0].min_strength && !block_records[1].may_clear_execute_flag)
+            move_into = 1;
+         else if(block_records[1].min_strength && !block_records[0].may_clear_execute_flag)
+            move_into = 0;
+
+         if(move_into >= 0) {
+            assert(!block_records[move_into].min_strength && !block_records[move_into].may_clear_execute_flag); /* otherwise, we just truncated */
+
+            exec_list* list = move_into ? &ir->else_instructions : &ir->then_instructions;
+            exec_node* next = ir->get_next();
+            if(!next->is_tail_sentinel()) {
+               move_outer_block_inside(ir, list);
+
+               exec_list list;
+               list.head = next;
+               block_records[move_into] = visit_block(&list);
+
+               this->progress = true;
+               goto retry;
+            }
+         } else {
+            ir_instruction* ir_after;
+            for(ir_after = (ir_instruction*)ir->get_next(); !ir_after->is_tail_sentinel();)
+            {
+               ir_if* ir_if = ir_after->as_if();
+               if(ir_if && ir_if->else_instructions.is_empty()) {
+                  ir_dereference_variable* ir_if_cond_deref = ir_if->condition->as_dereference_variable();
+                  if(ir_if_cond_deref && ir_if_cond_deref->var == this->loop.execute_flag) {
+                     ir_instruction* ir_next = (ir_instruction*)ir_after->get_next();
+                     ir_after->insert_before(&ir_if->then_instructions);
+                     ir_after->remove();
+                     ir_after = ir_next;
+                     continue;
+                  }
+               }
+               ir_after = (ir_instruction*)ir_after->get_next();
+
+               /* only set this if we find any unprotected instruction */
+               this->progress = true;
+            }
+
+            if(!ir->get_next()->is_tail_sentinel()) {
+               assert(this->loop.execute_flag);
+               ir_if* if_execute = new(ir) ir_if(new(ir) ir_dereference_variable(this->loop.execute_flag));
+               move_outer_block_inside(ir, &if_execute->then_instructions);
+               ir->insert_after(if_execute);
+            }
+         }
+      }
+      --this->loop.nesting_depth;
+      --this->function.nesting_depth;
+   }
+
+   virtual void visit(ir_loop *ir)
+   {
+      ++this->function.nesting_depth;
+      loop_record saved_loop = this->loop;
+      this->loop = loop_record(this->function.signature, ir);
+
+      block_record body = visit_block(&ir->body_instructions);
+
+      if(body.min_strength >= strength_break) {
+         /* FINISHME: turn the this->loop into an if, or replace it with its body */
+      }
+
+      if(this->loop.break_flag) {
+         ir_if* break_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->loop.break_flag));
+         break_if->then_instructions.push_tail(new(ir) ir_loop_jump(ir_loop_jump::jump_break));
+         ir->body_instructions.push_tail(break_if);
+      }
+
+      if(this->loop.may_set_return_flag) {
+         assert(this->function.return_flag);
+         ir_if* return_if = new(ir) ir_if(new(ir) ir_dereference_variable(this->function.return_flag));
+         return_if->then_instructions.push_tail(new(ir) ir_loop_jump(saved_loop.loop ? ir_loop_jump::jump_break : ir_loop_jump::jump_continue));
+         ir->insert_after(return_if);
+      }
+
+      this->loop = saved_loop;
+      --this->function.nesting_depth;
+   }
+
+   virtual void visit(ir_function_signature *ir)
+   {
+      /* these are not strictly necessary */
+      assert(!this->function.signature);
+      assert(!this->loop.loop);
+
+      function_record saved_function = this->function;
+      loop_record saved_loop = this->loop;
+      this->function = function_record(ir);
+      this->loop = loop_record(ir);
+
+      assert(!this->loop.loop);
+      visit_block(&ir->body);
+
+      if(this->function.return_value)
+         ir->body.push_tail(new(ir) ir_return(new (ir) ir_dereference_variable(this->function.return_value)));
+
+      this->loop = saved_loop;
+      this->function = saved_function;
+   }
+
+   virtual void visit(class ir_function * ir)
+   {
+      visit_block(&ir->signatures);
+   }
+};
+
+bool
+do_lower_jumps(exec_list *instructions, bool pull_out_jumps, bool lower_sub_return, bool lower_main_return, bool lower_continue, bool lower_break)
+{
+   ir_lower_jumps_visitor v;
+   v.pull_out_jumps = pull_out_jumps;
+   v.lower_continue = lower_continue;
+   v.lower_break = lower_break;
+   v.lower_sub_return = lower_sub_return;
+   v.lower_main_return = lower_main_return;
+
+   do {
+      v.progress = false;
+      visit_exec_list(instructions, &v);
+   } while (v.progress);
+
+   return v.progress;
+}
diff --git a/src/glsl/lower_mat_op_to_vec.cpp b/src/glsl/lower_mat_op_to_vec.cpp
new file mode 100644 (file)
index 0000000..244fe48
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_mat_op_to_vec.cpp
+ *
+ * Breaks matrix operation expressions down to a series of vector operations.
+ *
+ * Generally this is how we have to codegen matrix operations for a
+ * GPU, so this gives us the chance to constant fold operations on a
+ * column or row.
+ */
+
+#include "ir.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+
+class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
+public:
+   ir_mat_op_to_vec_visitor()
+   {
+      this->made_progress = false;
+      this->mem_ctx = NULL;
+   }
+
+   ir_visitor_status visit_leave(ir_assignment *);
+
+   ir_dereference *get_column(ir_variable *var, int col);
+   ir_rvalue *get_element(ir_variable *var, int col, int row);
+
+   void do_mul_mat_mat(ir_variable *result_var,
+                      ir_variable *a_var, ir_variable *b_var);
+   void do_mul_mat_vec(ir_variable *result_var,
+                      ir_variable *a_var, ir_variable *b_var);
+   void do_mul_vec_mat(ir_variable *result_var,
+                      ir_variable *a_var, ir_variable *b_var);
+   void do_mul_mat_scalar(ir_variable *result_var,
+                         ir_variable *a_var, ir_variable *b_var);
+   void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var,
+                        ir_variable *b_var, bool test_equal);
+
+   void *mem_ctx;
+   bool made_progress;
+};
+
+static bool
+mat_op_to_vec_predicate(ir_instruction *ir)
+{
+   ir_expression *expr = ir->as_expression();
+   unsigned int i;
+
+   if (!expr)
+      return false;
+
+   for (i = 0; i < expr->get_num_operands(); i++) {
+      if (expr->operands[i]->type->is_matrix())
+        return true;
+   }
+
+   return false;
+}
+
+bool
+do_mat_op_to_vec(exec_list *instructions)
+{
+   ir_mat_op_to_vec_visitor v;
+
+   /* Pull out any matrix expression to a separate assignment to a
+    * temp.  This will make our handling of the breakdown to
+    * operations on the matrix's vector components much easier.
+    */
+   do_expression_flattening(instructions, mat_op_to_vec_predicate);
+
+   visit_list_elements(&v, instructions);
+
+   return v.made_progress;
+}
+
+ir_rvalue *
+ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
+{
+   ir_dereference *deref;
+
+   deref = new(mem_ctx) ir_dereference_variable(var);
+
+   if (var->type->is_matrix()) {
+      deref = new(mem_ctx) ir_dereference_array(var,
+                                               new(mem_ctx) ir_constant(col));
+   } else {
+      assert(col == 0);
+   }
+
+   return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1);
+}
+
+ir_dereference *
+ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
+{
+   ir_dereference *deref;
+
+   if (!var->type->is_matrix()) {
+      deref = new(mem_ctx) ir_dereference_variable(var);
+   } else {
+      deref = new(mem_ctx) ir_dereference_variable(var);
+      deref = new(mem_ctx) ir_dereference_array(deref,
+                                               new(mem_ctx) ir_constant(row));
+   }
+
+   return deref;
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
+                                        ir_variable *a_var,
+                                        ir_variable *b_var)
+{
+   int b_col, i;
+   ir_assignment *assign;
+   ir_expression *expr;
+
+   for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
+      ir_rvalue *a = get_column(a_var, 0);
+      ir_rvalue *b = get_element(b_var, b_col, 0);
+
+      /* first column */
+      expr = new(mem_ctx) ir_expression(ir_binop_mul,
+                                       a->type,
+                                       a,
+                                       b);
+
+      /* following columns */
+      for (i = 1; i < a_var->type->matrix_columns; i++) {
+        ir_expression *mul_expr;
+
+        a = get_column(a_var, i);
+        b = get_element(b_var, b_col, i);
+
+        mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
+                                              a->type,
+                                              a,
+                                              b);
+        expr = new(mem_ctx) ir_expression(ir_binop_add,
+                                          a->type,
+                                          expr,
+                                          mul_expr);
+      }
+
+      ir_rvalue *result = get_column(result_var, b_col);
+      assign = new(mem_ctx) ir_assignment(result,
+                                         expr,
+                                         NULL);
+      base_ir->insert_before(assign);
+   }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
+                                        ir_variable *a_var,
+                                        ir_variable *b_var)
+{
+   int i;
+   ir_rvalue *a = get_column(a_var, 0);
+   ir_rvalue *b = get_element(b_var, 0, 0);
+   ir_assignment *assign;
+   ir_expression *expr;
+
+   /* first column */
+   expr = new(mem_ctx) ir_expression(ir_binop_mul,
+                                    result_var->type,
+                                    a,
+                                    b);
+
+   /* following columns */
+   for (i = 1; i < a_var->type->matrix_columns; i++) {
+      ir_expression *mul_expr;
+
+      a = get_column(a_var, i);
+      b = get_element(b_var, 0, i);
+
+      mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
+                                           result_var->type,
+                                           a,
+                                           b);
+      expr = new(mem_ctx) ir_expression(ir_binop_add,
+                                       result_var->type,
+                                       expr,
+                                       mul_expr);
+   }
+
+   ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var);
+   assign = new(mem_ctx) ir_assignment(result,
+                                      expr,
+                                      NULL);
+   base_ir->insert_before(assign);
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
+                                        ir_variable *a_var,
+                                        ir_variable *b_var)
+{
+   int i;
+
+   for (i = 0; i < b_var->type->matrix_columns; i++) {
+      ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var);
+      ir_rvalue *b = get_column(b_var, i);
+      ir_rvalue *result;
+      ir_expression *column_expr;
+      ir_assignment *column_assign;
+
+      result = new(mem_ctx) ir_dereference_variable(result_var);
+      result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1);
+
+      column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
+                                              result->type,
+                                              a,
+                                              b);
+
+      column_assign = new(mem_ctx) ir_assignment(result,
+                                                column_expr,
+                                                NULL);
+      base_ir->insert_before(column_assign);
+   }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
+                                           ir_variable *a_var,
+                                           ir_variable *b_var)
+{
+   int i;
+
+   for (i = 0; i < a_var->type->matrix_columns; i++) {
+      ir_rvalue *a = get_column(a_var, i);
+      ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var);
+      ir_rvalue *result = get_column(result_var, i);
+      ir_expression *column_expr;
+      ir_assignment *column_assign;
+
+      column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
+                                              result->type,
+                                              a,
+                                              b);
+
+      column_assign = new(mem_ctx) ir_assignment(result,
+                                                column_expr,
+                                                NULL);
+      base_ir->insert_before(column_assign);
+   }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var,
+                                          ir_variable *a_var,
+                                          ir_variable *b_var,
+                                          bool test_equal)
+{
+   /* This essentially implements the following GLSL:
+    *
+    * bool equal(mat4 a, mat4 b)
+    * {
+    *   return !any(bvec4(a[0] != b[0],
+    *                     a[1] != b[1],
+    *                     a[2] != b[2],
+    *                     a[3] != b[3]);
+    * }
+    *
+    * bool nequal(mat4 a, mat4 b)
+    * {
+    *   return any(bvec4(a[0] != b[0],
+    *                    a[1] != b[1],
+    *                    a[2] != b[2],
+    *                    a[3] != b[3]);
+    * }
+    */
+   const unsigned columns = a_var->type->matrix_columns;
+   const glsl_type *const bvec_type =
+      glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
+
+   ir_variable *const tmp_bvec =
+      new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec",
+                                    ir_var_temporary);
+   this->base_ir->insert_before(tmp_bvec);
+
+   for (unsigned i = 0; i < columns; i++) {
+      ir_dereference *const op0 = get_column(a_var, i);
+      ir_dereference *const op1 = get_column(b_var, i);
+
+      ir_expression *const cmp =
+        new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
+                                         glsl_type::bool_type, op0, op1);
+
+      ir_dereference *const lhs =
+        new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
+
+      ir_assignment *const assign =
+        new(this->mem_ctx) ir_assignment(lhs, cmp, NULL, (1U << i));
+
+      this->base_ir->insert_before(assign);
+   }
+
+   ir_rvalue *const val =
+      new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
+
+   ir_expression *any =
+      new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type,
+                                      val, NULL);
+
+   if (test_equal)
+      any = new(this->mem_ctx) ir_expression(ir_unop_logic_not,
+                                            glsl_type::bool_type,
+                                            any, NULL);
+
+   ir_rvalue *const result =
+      new(this->mem_ctx) ir_dereference_variable(result_var);
+
+   ir_assignment *const assign =
+        new(mem_ctx) ir_assignment(result, any, NULL);
+   base_ir->insert_before(assign);
+}
+
+static bool
+has_matrix_operand(const ir_expression *expr, unsigned &columns)
+{
+   for (unsigned i = 0; i < expr->get_num_operands(); i++) {
+      if (expr->operands[i]->type->is_matrix()) {
+        columns = expr->operands[i]->type->matrix_columns;
+        return true;
+      }
+   }
+
+   return false;
+}
+
+
+ir_visitor_status
+ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign)
+{
+   ir_expression *orig_expr = orig_assign->rhs->as_expression();
+   unsigned int i, matrix_columns = 1;
+   ir_variable *op_var[2];
+
+   if (!orig_expr)
+      return visit_continue;
+
+   if (!has_matrix_operand(orig_expr, matrix_columns))
+      return visit_continue;
+
+   mem_ctx = talloc_parent(orig_assign);
+
+   ir_dereference_variable *lhs_deref =
+      orig_assign->lhs->as_dereference_variable();
+   assert(lhs_deref);
+
+   ir_variable *result_var = lhs_deref->var;
+
+   /* Store the expression operands in temps so we can use them
+    * multiple times.
+    */
+   for (i = 0; i < orig_expr->get_num_operands(); i++) {
+      ir_assignment *assign;
+
+      op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
+                                          "mat_op_to_vec",
+                                          ir_var_temporary);
+      base_ir->insert_before(op_var[i]);
+
+      lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
+      assign = new(mem_ctx) ir_assignment(lhs_deref,
+                                         orig_expr->operands[i],
+                                         NULL);
+      base_ir->insert_before(assign);
+   }
+
+   /* OK, time to break down this matrix operation. */
+   switch (orig_expr->operation) {
+   case ir_unop_neg: {
+      const unsigned mask = (1U << result_var->type->vector_elements) - 1;
+
+      /* Apply the operation to each column.*/
+      for (i = 0; i < matrix_columns; i++) {
+        ir_rvalue *op0 = get_column(op_var[0], i);
+        ir_dereference *result = get_column(result_var, i);
+        ir_expression *column_expr;
+        ir_assignment *column_assign;
+
+        column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
+                                                 result->type,
+                                                 op0,
+                                                 NULL);
+
+        column_assign = new(mem_ctx) ir_assignment(result,
+                                                   column_expr,
+                                                   NULL,
+                                                   mask);
+        assert(column_assign->write_mask != 0);
+        base_ir->insert_before(column_assign);
+      }
+      break;
+   }
+   case ir_binop_add:
+   case ir_binop_sub:
+   case ir_binop_div:
+   case ir_binop_mod: {
+      const unsigned mask = (1U << result_var->type->vector_elements) - 1;
+
+      /* For most operations, the matrix version is just going
+       * column-wise through and applying the operation to each column
+       * if available.
+       */
+      for (i = 0; i < matrix_columns; i++) {
+        ir_rvalue *op0 = get_column(op_var[0], i);
+        ir_rvalue *op1 = get_column(op_var[1], i);
+        ir_dereference *result = get_column(result_var, i);
+        ir_expression *column_expr;
+        ir_assignment *column_assign;
+
+        column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
+                                                 result->type,
+                                                 op0,
+                                                 op1);
+
+        column_assign = new(mem_ctx) ir_assignment(result,
+                                                   column_expr,
+                                                   NULL,
+                                                   mask);
+        assert(column_assign->write_mask != 0);
+        base_ir->insert_before(column_assign);
+      }
+      break;
+   }
+   case ir_binop_mul:
+      if (op_var[0]->type->is_matrix()) {
+        if (op_var[1]->type->is_matrix()) {
+           do_mul_mat_mat(result_var, op_var[0], op_var[1]);
+        } else if (op_var[1]->type->is_vector()) {
+           do_mul_mat_vec(result_var, op_var[0], op_var[1]);
+        } else {
+           assert(op_var[1]->type->is_scalar());
+           do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
+        }
+      } else {
+        assert(op_var[1]->type->is_matrix());
+        if (op_var[0]->type->is_vector()) {
+           do_mul_vec_mat(result_var, op_var[0], op_var[1]);
+        } else {
+           assert(op_var[0]->type->is_scalar());
+           do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
+        }
+      }
+      break;
+
+   case ir_binop_all_equal:
+   case ir_binop_any_nequal:
+      do_equal_mat_mat(result_var, op_var[1], op_var[0],
+                      (orig_expr->operation == ir_binop_all_equal));
+      break;
+
+   default:
+      printf("FINISHME: Handle matrix operation for %s\n",
+            orig_expr->operator_string());
+      abort();
+   }
+   orig_assign->remove();
+   this->made_progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/lower_mod_to_fract.cpp b/src/glsl/lower_mod_to_fract.cpp
new file mode 100644 (file)
index 0000000..c82a1f6
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_mod_to_fract.cpp
+ *
+ * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1))
+ *
+ * Many GPUs don't have a MOD instruction (945 and 965 included), and
+ * if we have to break it down like this anyway, it gives an
+ * opportunity to do things like constant fold the (1.0 / op1) easily.
+ */
+
+#include "ir.h"
+
+class ir_mod_to_fract_visitor : public ir_hierarchical_visitor {
+public:
+   ir_mod_to_fract_visitor()
+   {
+      this->made_progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_expression *);
+
+   bool made_progress;
+};
+
+bool
+do_mod_to_fract(exec_list *instructions)
+{
+   ir_mod_to_fract_visitor v;
+
+   visit_list_elements(&v, instructions);
+   return v.made_progress;
+}
+
+ir_visitor_status
+ir_mod_to_fract_visitor::visit_leave(ir_expression *ir)
+{
+   if (ir->operation != ir_binop_mod)
+      return visit_continue;
+
+   ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b",
+                                          ir_var_temporary);
+   this->base_ir->insert_before(temp);
+
+   ir_assignment *assign;
+   ir_rvalue *expr;
+
+   assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(temp),
+                                 ir->operands[1], NULL);
+   this->base_ir->insert_before(assign);
+
+   expr = new(ir) ir_expression(ir_binop_div,
+                               ir->operands[0]->type,
+                               ir->operands[0],
+                               new(ir) ir_dereference_variable(temp));
+
+   expr = new(ir) ir_expression(ir_unop_fract,
+                               ir->operands[0]->type,
+                               expr,
+                               NULL);
+
+   ir->operation = ir_binop_mul;
+   ir->operands[0] = new(ir) ir_dereference_variable(temp);
+   ir->operands[1] = expr;
+   this->made_progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/lower_sub_to_add_neg.cpp b/src/glsl/lower_sub_to_add_neg.cpp
new file mode 100644 (file)
index 0000000..7ed8c14
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_sub_to_add_neg.cpp
+ *
+ * Breaks an ir_binop_sub expression down to add(op0, neg(op1))
+ *
+ * This simplifies expression reassociation, and for many backends
+ * there is no subtract operation separate from adding the negation.
+ * For backends with native subtract operations, they will probably
+ * want to recognize add(op0, neg(op1)) or the other way around to
+ * produce a subtract anyway.
+ */
+
+#include "ir.h"
+
+class ir_sub_to_add_neg_visitor : public ir_hierarchical_visitor {
+public:
+   ir_sub_to_add_neg_visitor()
+   {
+      this->progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_expression *);
+
+   bool progress;
+};
+
+bool
+do_sub_to_add_neg(exec_list *instructions)
+{
+   ir_sub_to_add_neg_visitor v;
+
+   visit_list_elements(&v, instructions);
+   return v.progress;
+}
+
+ir_visitor_status
+ir_sub_to_add_neg_visitor::visit_leave(ir_expression *ir)
+{
+   if (ir->operation != ir_binop_sub)
+      return visit_continue;
+
+   void *mem_ctx = talloc_parent(ir);
+
+   ir->operation = ir_binop_add;
+   ir->operands[1] = new(mem_ctx) ir_expression(ir_unop_neg,
+                                               ir->operands[1]->type,
+                                               ir->operands[1],
+                                               NULL);
+
+   this->progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/lower_vec_index_to_cond_assign.cpp b/src/glsl/lower_vec_index_to_cond_assign.cpp
new file mode 100644 (file)
index 0000000..cd8dedf
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_vec_index_to_cond_assign.cpp
+ *
+ * Turns indexing into vector types to a series of conditional moves
+ * of each channel's swizzle into a temporary.
+ *
+ * Most GPUs don't have a native way to do this operation, and this
+ * works around that.  For drivers using both this pass and
+ * ir_vec_index_to_swizzle, there's a risk that this pass will happen
+ * before sufficient constant folding to find that the array index is
+ * constant.  However, we hope that other optimization passes,
+ * particularly constant folding of assignment conditions and copy
+ * propagation, will result in the same code in the end.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
+public:
+   ir_vec_index_to_cond_assign_visitor()
+   {
+      progress = false;
+   }
+
+   ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
+
+   virtual ir_visitor_status visit_enter(ir_expression *);
+   virtual ir_visitor_status visit_enter(ir_swizzle *);
+   virtual ir_visitor_status visit_leave(ir_assignment *);
+   virtual ir_visitor_status visit_enter(ir_return *);
+   virtual ir_visitor_status visit_enter(ir_call *);
+   virtual ir_visitor_status visit_enter(ir_if *);
+
+   bool progress;
+};
+
+ir_rvalue *
+ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
+{
+   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;
+
+   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);
+
+   /* 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);
+   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);
+
+   /* Temporary where we store whichever value we swizzle out. */
+   var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
+                                 ir_var_temporary);
+   base_ir->insert_before(var);
+
+   /* 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));
+
+      /* 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);
+
+      deref = new(base_ir) ir_dereference_variable(var);
+      assign = new(base_ir) ir_assignment(deref, swizzle, condition);
+      base_ir->insert_before(assign);
+   }
+
+   this->progress = true;
+   return new(base_ir) ir_dereference_variable(var);
+}
+
+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]);
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
+{
+   /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
+    * 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);
+
+   return visit_continue;
+}
+
+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);
+
+   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);
+   }
+   ir->remove();
+
+   this->progress = true;
+
+   return visit_continue;
+}
+
+ir_visitor_status
+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);
+
+      if (new_param != param) {
+        param->replace_with(new_param);
+      }
+   }
+
+   return visit_continue;
+}
+
+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);
+   }
+
+   return visit_continue;
+}
+
+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);
+
+   return visit_continue;
+}
+
+bool
+do_vec_index_to_cond_assign(exec_list *instructions)
+{
+   ir_vec_index_to_cond_assign_visitor v;
+
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/lower_vec_index_to_swizzle.cpp b/src/glsl/lower_vec_index_to_swizzle.cpp
new file mode 100644 (file)
index 0000000..969dc8f
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_vec_index_to_swizzle.cpp
+ *
+ * Turns constant indexing into vector types to swizzles.  This will
+ * let other swizzle-aware optimization passes catch these constructs,
+ * and codegen backends not have to worry about this case.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_vec_index_to_swizzle_visitor : public ir_hierarchical_visitor {
+public:
+   ir_vec_index_to_swizzle_visitor()
+   {
+      progress = false;
+   }
+
+   ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val);
+
+   virtual ir_visitor_status visit_enter(ir_expression *);
+   virtual ir_visitor_status visit_enter(ir_swizzle *);
+   virtual ir_visitor_status visit_enter(ir_assignment *);
+   virtual ir_visitor_status visit_enter(ir_return *);
+   virtual ir_visitor_status visit_enter(ir_call *);
+   virtual ir_visitor_status visit_enter(ir_if *);
+
+   bool progress;
+};
+
+ir_rvalue *
+ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
+{
+   ir_dereference_array *deref = ir->as_dereference_array();
+   ir_constant *ir_constant;
+
+   if (!deref)
+      return ir;
+
+   if (deref->array->type->is_matrix() || deref->array->type->is_array())
+      return ir;
+
+   assert(deref->array_index->type->base_type == GLSL_TYPE_INT);
+   ir_constant = deref->array_index->constant_expression_value();
+   if (!ir_constant)
+      return ir;
+
+   void *ctx = talloc_parent(ir);
+   this->progress = true;
+   return new(ctx) ir_swizzle(deref->array,
+                             ir_constant->value.i[0], 0, 0, 0, 1);
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_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_swizzle(ir->operands[i]);
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
+{
+   /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
+    * 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_swizzle(ir->val);
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
+{
+   ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
+   ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_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_swizzle(param);
+
+      if (new_param != param) {
+        param->replace_with(new_param);
+      }
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
+{
+   if (ir->value) {
+      ir->value = convert_vec_index_to_swizzle(ir->value);
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir)
+{
+   ir->condition = convert_vec_index_to_swizzle(ir->condition);
+
+   return visit_continue;
+}
+
+bool
+do_vec_index_to_swizzle(exec_list *instructions)
+{
+   ir_vec_index_to_swizzle_visitor v;
+
+   v.run(instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp
new file mode 100644 (file)
index 0000000..2ed66db
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_algebraic.cpp
+ *
+ * Takes advantage of association, commutivity, and other algebraic
+ * properties to simplify expressions.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_algebraic_visitor : public ir_rvalue_visitor {
+public:
+   ir_algebraic_visitor()
+   {
+      this->progress = false;
+      this->mem_ctx = NULL;
+   }
+
+   virtual ~ir_algebraic_visitor()
+   {
+   }
+
+   ir_rvalue *handle_expression(ir_expression *ir);
+   void handle_rvalue(ir_rvalue **rvalue);
+   bool reassociate_constant(ir_expression *ir1,
+                            int const_index,
+                            ir_constant *constant,
+                            ir_expression *ir2);
+   void reassociate_operands(ir_expression *ir1,
+                            int op1,
+                            ir_expression *ir2,
+                            int op2);
+   ir_rvalue *swizzle_if_required(ir_expression *expr,
+                                 ir_rvalue *operand);
+
+   void *mem_ctx;
+
+   bool progress;
+};
+
+static bool
+is_vec_zero(ir_constant *ir)
+{
+   int c;
+
+   if (!ir)
+      return false;
+   if (!ir->type->is_scalar() &&
+       !ir->type->is_vector())
+      return false;
+
+   for (c = 0; c < ir->type->vector_elements; c++) {
+      switch (ir->type->base_type) {
+      case GLSL_TYPE_FLOAT:
+        if (ir->value.f[c] != 0.0)
+           return false;
+        break;
+      case GLSL_TYPE_INT:
+        if (ir->value.i[c] != 0)
+           return false;
+        break;
+      case GLSL_TYPE_UINT:
+        if (ir->value.u[c] != 0)
+           return false;
+        break;
+      case GLSL_TYPE_BOOL:
+        if (ir->value.b[c] != false)
+           return false;
+        break;
+      default:
+        assert(!"bad base type");
+        return false;
+      }
+   }
+
+   return true;
+}
+
+static bool
+is_vec_one(ir_constant *ir)
+{
+   int c;
+
+   if (!ir)
+      return false;
+   if (!ir->type->is_scalar() &&
+       !ir->type->is_vector())
+      return false;
+
+   for (c = 0; c < ir->type->vector_elements; c++) {
+      switch (ir->type->base_type) {
+      case GLSL_TYPE_FLOAT:
+        if (ir->value.f[c] != 1.0)
+           return false;
+        break;
+      case GLSL_TYPE_INT:
+        if (ir->value.i[c] != 1)
+           return false;
+        break;
+      case GLSL_TYPE_UINT:
+        if (ir->value.u[c] != 1)
+           return false;
+        break;
+      case GLSL_TYPE_BOOL:
+        if (ir->value.b[c] != true)
+           return false;
+        break;
+      default:
+        assert(!"bad base type");
+        return false;
+      }
+   }
+
+   return true;
+}
+
+static void
+update_type(ir_expression *ir)
+{
+   if (ir->operands[0]->type->is_vector())
+      ir->type = ir->operands[0]->type;
+   else
+      ir->type = ir->operands[1]->type;
+}
+
+void
+ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
+                                          int op1,
+                                          ir_expression *ir2,
+                                          int op2)
+{
+   ir_rvalue *temp = ir2->operands[op2];
+   ir2->operands[op2] = ir1->operands[op1];
+   ir1->operands[op1] = temp;
+
+   /* Update the type of ir2.  The type of ir1 won't have changed --
+    * base types matched, and at least one of the operands of the 2
+    * binops is still a vector if any of them were.
+    */
+   update_type(ir2);
+
+   this->progress = true;
+}
+
+/**
+ * Reassociates a constant down a tree of adds or multiplies.
+ *
+ * Consider (2 * (a * (b * 0.5))).  We want to send up with a * b.
+ */
+bool
+ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
+                                          ir_constant *constant,
+                                          ir_expression *ir2)
+{
+   if (!ir2 || ir1->operation != ir2->operation)
+      return false;
+
+   /* Don't want to even think about matrices. */
+   if (ir1->operands[0]->type->is_matrix() ||
+       ir1->operands[0]->type->is_matrix() ||
+       ir2->operands[1]->type->is_matrix() ||
+       ir2->operands[1]->type->is_matrix())
+      return false;
+
+   ir_constant *ir2_const[2];
+   ir2_const[0] = ir2->operands[0]->constant_expression_value();
+   ir2_const[1] = ir2->operands[1]->constant_expression_value();
+
+   if (ir2_const[0] && ir2_const[1])
+      return false;
+
+   if (ir2_const[0]) {
+      reassociate_operands(ir1, const_index, ir2, 1);
+      return true;
+   } else if (ir2_const[1]) {
+      reassociate_operands(ir1, const_index, ir2, 0);
+      return true;
+   }
+
+   if (reassociate_constant(ir1, const_index, constant,
+                           ir2->operands[0]->as_expression())) {
+      update_type(ir2);
+      return true;
+   }
+
+   if (reassociate_constant(ir1, const_index, constant,
+                           ir2->operands[1]->as_expression())) {
+      update_type(ir2);
+      return true;
+   }
+
+   return false;
+}
+
+/* When eliminating an expression and just returning one of its operands,
+ * we may need to swizzle that operand out to a vector if the expression was
+ * vector type.
+ */
+ir_rvalue *
+ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
+                                         ir_rvalue *operand)
+{
+   if (expr->type->is_vector() && operand->type->is_scalar()) {
+      return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0,
+                                    expr->type->vector_elements);
+   } else
+      return operand;
+}
+
+ir_rvalue *
+ir_algebraic_visitor::handle_expression(ir_expression *ir)
+{
+   ir_constant *op_const[2] = {NULL, NULL};
+   ir_expression *op_expr[2] = {NULL, NULL};
+   ir_expression *temp;
+   unsigned int i;
+
+   for (i = 0; i < ir->get_num_operands(); i++) {
+      if (ir->operands[i]->type->is_matrix())
+        return ir;
+
+      op_const[i] = ir->operands[i]->constant_expression_value();
+      op_expr[i] = ir->operands[i]->as_expression();
+   }
+
+   if (this->mem_ctx == NULL)
+      this->mem_ctx = talloc_parent(ir);
+
+   switch (ir->operation) {
+   case ir_unop_logic_not: {
+      enum ir_expression_operation new_op = ir_unop_logic_not;
+
+      if (op_expr[0] == NULL)
+        break;
+
+      switch (op_expr[0]->operation) {
+      case ir_binop_less:    new_op = ir_binop_gequal;  break;
+      case ir_binop_greater: new_op = ir_binop_lequal;  break;
+      case ir_binop_lequal:  new_op = ir_binop_greater; break;
+      case ir_binop_gequal:  new_op = ir_binop_less;    break;
+      case ir_binop_equal:   new_op = ir_binop_nequal;  break;
+      case ir_binop_nequal:  new_op = ir_binop_equal;   break;
+      case ir_binop_all_equal:   new_op = ir_binop_any_nequal;  break;
+      case ir_binop_any_nequal:  new_op = ir_binop_all_equal;   break;
+
+      default:
+        /* The default case handler is here to silence a warning from GCC.
+         */
+        break;
+      }
+
+      if (new_op != ir_unop_logic_not) {
+        this->progress = true;
+        return new(mem_ctx) ir_expression(new_op,
+                                          ir->type,
+                                          op_expr[0]->operands[0],
+                                          op_expr[0]->operands[1]);
+      }
+
+      break;
+   }
+
+   case ir_binop_add:
+      if (is_vec_zero(op_const[0])) {
+        this->progress = true;
+        return swizzle_if_required(ir, ir->operands[1]);
+      }
+      if (is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return swizzle_if_required(ir, ir->operands[0]);
+      }
+
+      /* Reassociate addition of constants so that we can do constant
+       * folding.
+       */
+      if (op_const[0] && !op_const[1])
+        reassociate_constant(ir, 0, op_const[0],
+                             ir->operands[1]->as_expression());
+      if (op_const[1] && !op_const[0])
+        reassociate_constant(ir, 1, op_const[1],
+                             ir->operands[0]->as_expression());
+      break;
+
+   case ir_binop_sub:
+      if (is_vec_zero(op_const[0])) {
+        this->progress = true;
+        temp = new(mem_ctx) ir_expression(ir_unop_neg,
+                                          ir->operands[1]->type,
+                                          ir->operands[1],
+                                          NULL);
+        return swizzle_if_required(ir, temp);
+      }
+      if (is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return swizzle_if_required(ir, ir->operands[0]);
+      }
+      break;
+
+   case ir_binop_mul:
+      if (is_vec_one(op_const[0])) {
+        this->progress = true;
+        return swizzle_if_required(ir, ir->operands[1]);
+      }
+      if (is_vec_one(op_const[1])) {
+        this->progress = true;
+        return swizzle_if_required(ir, ir->operands[0]);
+      }
+
+      if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return ir_constant::zero(ir, ir->type);
+      }
+
+      /* Reassociate multiplication of constants so that we can do
+       * constant folding.
+       */
+      if (op_const[0] && !op_const[1])
+        reassociate_constant(ir, 0, op_const[0],
+                             ir->operands[1]->as_expression());
+      if (op_const[1] && !op_const[0])
+        reassociate_constant(ir, 1, op_const[1],
+                             ir->operands[0]->as_expression());
+
+      break;
+
+   case ir_binop_div:
+      if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
+        this->progress = true;
+        temp = new(mem_ctx) ir_expression(ir_unop_rcp,
+                                          ir->operands[1]->type,
+                                          ir->operands[1],
+                                          NULL);
+        return swizzle_if_required(ir, temp);
+      }
+      if (is_vec_one(op_const[1])) {
+        this->progress = true;
+        return swizzle_if_required(ir, ir->operands[0]);
+      }
+      break;
+
+   case ir_binop_logic_and:
+      /* FINISHME: Also simplify (a && a) to (a). */
+      if (is_vec_one(op_const[0])) {
+        this->progress = true;
+        return ir->operands[1];
+      } else if (is_vec_one(op_const[1])) {
+        this->progress = true;
+        return ir->operands[0];
+      } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return ir_constant::zero(mem_ctx, ir->type);
+      }
+      break;
+
+   case ir_binop_logic_xor:
+      /* FINISHME: Also simplify (a ^^ a) to (false). */
+      if (is_vec_zero(op_const[0])) {
+        this->progress = true;
+        return ir->operands[1];
+      } else if (is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return ir->operands[0];
+      } else if (is_vec_one(op_const[0])) {
+        this->progress = true;
+        return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
+                                          ir->operands[1], NULL);
+      } else if (is_vec_one(op_const[1])) {
+        this->progress = true;
+        return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
+                                          ir->operands[0], NULL);
+      }
+      break;
+
+   case ir_binop_logic_or:
+      /* FINISHME: Also simplify (a || a) to (a). */
+      if (is_vec_zero(op_const[0])) {
+        this->progress = true;
+        return ir->operands[1];
+      } else if (is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return ir->operands[0];
+      } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) {
+        ir_constant_data data;
+
+        for (unsigned i = 0; i < 16; i++)
+           data.b[i] = true;
+
+        this->progress = true;
+        return new(mem_ctx) ir_constant(ir->type, &data);
+      }
+      break;
+
+   case ir_unop_rcp:
+      if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) {
+        this->progress = true;
+        return op_expr[0]->operands[0];
+      }
+
+      /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
+       * backends, except that some backends will have done sqrt ->
+       * rcp(rsq(x)) and we don't want to undo it for them.
+       */
+
+      /* As far as we know, all backends are OK with rsq. */
+      if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) {
+        this->progress = true;
+        temp = new(mem_ctx) ir_expression(ir_unop_rsq,
+                                          op_expr[0]->operands[0]->type,
+                                          op_expr[0]->operands[0],
+                                          NULL);
+        return swizzle_if_required(ir, temp);
+      }
+
+      break;
+
+   default:
+      break;
+   }
+
+   return ir;
+}
+
+void
+ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+   if (!*rvalue)
+      return;
+
+   ir_expression *expr = (*rvalue)->as_expression();
+   if (!expr)
+      return;
+
+   *rvalue = handle_expression(expr);
+}
+
+bool
+do_algebraic(exec_list *instructions)
+{
+   ir_algebraic_visitor v;
+
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/opt_constant_folding.cpp b/src/glsl/opt_constant_folding.cpp
new file mode 100644 (file)
index 0000000..554c54f
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_constant_folding.cpp
+ * Replace constant-valued expressions with references to constant values.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+/**
+ * Visitor class for replacing expressions with ir_constant values.
+ */
+
+class ir_constant_folding_visitor : public ir_rvalue_visitor {
+public:
+   ir_constant_folding_visitor()
+   {
+      this->progress = false;
+   }
+
+   virtual ~ir_constant_folding_visitor()
+   {
+      /* empty */
+   }
+
+   virtual ir_visitor_status visit_enter(ir_assignment *ir);
+   virtual ir_visitor_status visit_enter(ir_call *ir);
+
+   virtual void handle_rvalue(ir_rvalue **rvalue);
+
+   bool progress;
+};
+
+void
+ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+   if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant)
+      return;
+
+   /* Note that we do rvalue visitoring on leaving.  So if an
+    * expression has a non-constant operand, no need to go looking
+    * down it to find if it's constant.  This cuts the time of this
+    * pass down drastically.
+    */
+   ir_expression *expr = (*rvalue)->as_expression();
+   if (expr) {
+      for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
+        if (!expr->operands[i]->as_constant())
+           return;
+      }
+   }
+
+   ir_constant *constant = (*rvalue)->constant_expression_value();
+   if (constant) {
+      *rvalue = constant;
+      this->progress = true;
+   } else {
+      (*rvalue)->accept(this);
+   }
+}
+
+ir_visitor_status
+ir_constant_folding_visitor::visit_enter(ir_assignment *ir)
+{
+   ir->rhs->accept(this);
+   handle_rvalue(&ir->rhs);
+
+   if (ir->condition) {
+      ir->condition->accept(this);
+      handle_rvalue(&ir->condition);
+
+      ir_constant *const_val = ir->condition->as_constant();
+      /* If the condition is constant, either remove the condition or
+       * remove the never-executed assignment.
+       */
+      if (const_val) {
+        if (const_val->value.b[0])
+           ir->condition = NULL;
+        else
+           ir->remove();
+        this->progress = true;
+      }
+   }
+
+   /* Don't descend into the LHS because we want it to stay as a
+    * variable dereference.  FINISHME: We probably should to get array
+    * indices though.
+    */
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_folding_visitor::visit_enter(ir_call *ir)
+{
+   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+   foreach_iter(exec_list_iterator, iter, *ir) {
+      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+      ir_variable *sig_param = (ir_variable *)sig_iter.get();
+
+      if (sig_param->mode == ir_var_in) {
+        ir_rvalue *new_param = param_rval;
+
+        handle_rvalue(&new_param);
+        if (new_param != param_rval) {
+           param_rval->replace_with(new_param);
+        }
+      }
+      sig_iter.next();
+   }
+
+   return visit_continue_with_parent;
+}
+
+bool
+do_constant_folding(exec_list *instructions)
+{
+   ir_constant_folding_visitor constant_folding;
+
+   visit_list_elements(&constant_folding, instructions);
+
+   return constant_folding.progress;
+}
diff --git a/src/glsl/opt_constant_propagation.cpp b/src/glsl/opt_constant_propagation.cpp
new file mode 100644 (file)
index 0000000..5d875b7
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * constant of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, constant, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above constantright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR CONSTANTRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_constant_propagation.cpp
+ *
+ * Tracks assignments of constants to channels of variables, and
+ * usage of those constant channels with direct usage of the constants.
+ *
+ * This can lead to constant folding and algebraic optimizations in
+ * those later expressions, while causing no increase in instruction
+ * count (due to constants being generally free to load from a
+ * constant push buffer or as instruction immediate values) and
+ * possibly reducing register pressure.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+class acp_entry : public exec_node
+{
+public:
+   acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
+   {
+      assert(var);
+      assert(constant);
+      this->var = var;
+      this->write_mask = write_mask;
+      this->constant = constant;
+   }
+
+   ir_variable *var;
+   ir_constant *constant;
+   unsigned write_mask;
+};
+
+
+class kill_entry : public exec_node
+{
+public:
+   kill_entry(ir_variable *var, unsigned write_mask)
+   {
+      assert(var);
+      this->var = var;
+      this->write_mask = write_mask;
+   }
+
+   ir_variable *var;
+   unsigned write_mask;
+};
+
+class ir_constant_propagation_visitor : public ir_rvalue_visitor {
+public:
+   ir_constant_propagation_visitor()
+   {
+      progress = false;
+      mem_ctx = talloc_new(0);
+      this->acp = new(mem_ctx) exec_list;
+      this->kills = new(mem_ctx) exec_list;
+   }
+   ~ir_constant_propagation_visitor()
+   {
+      talloc_free(mem_ctx);
+   }
+
+   virtual ir_visitor_status visit_enter(class ir_loop *);
+   virtual ir_visitor_status visit_enter(class ir_function_signature *);
+   virtual ir_visitor_status visit_enter(class ir_function *);
+   virtual ir_visitor_status visit_leave(class ir_assignment *);
+   virtual ir_visitor_status visit_enter(class ir_call *);
+   virtual ir_visitor_status visit_enter(class ir_if *);
+
+   void add_constant(ir_assignment *ir);
+   void kill(ir_variable *ir, unsigned write_mask);
+   void handle_if_block(exec_list *instructions);
+   void handle_rvalue(ir_rvalue **rvalue);
+
+   /** List of acp_entry: The available constants to propagate */
+   exec_list *acp;
+
+   /**
+    * List of kill_entry: The masks of variables whose values were
+    * killed in this block.
+    */
+   exec_list *kills;
+
+   bool progress;
+
+   bool killed_all;
+
+   void *mem_ctx;
+};
+
+
+void
+ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+   if (this->in_assignee || !*rvalue)
+      return;
+
+   const glsl_type *type = (*rvalue)->type;
+   if (!type->is_scalar() && !type->is_vector())
+      return;
+
+   ir_swizzle *swiz = NULL;
+   ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
+   if (!deref) {
+      swiz = (*rvalue)->as_swizzle();
+      if (!swiz)
+        return;
+
+      deref = swiz->val->as_dereference_variable();
+      if (!deref)
+        return;
+   }
+
+   ir_constant_data data;
+   memset(&data, 0, sizeof(data));
+
+   for (unsigned int i = 0; i < type->components(); i++) {
+      int channel;
+      acp_entry *found = NULL;
+
+      if (swiz) {
+        switch (i) {
+        case 0: channel = swiz->mask.x; break;
+        case 1: channel = swiz->mask.y; break;
+        case 2: channel = swiz->mask.z; break;
+        case 3: channel = swiz->mask.w; break;
+        default: assert(!"shouldn't be reached"); channel = 0; break;
+        }
+      } else {
+        channel = i;
+      }
+
+      foreach_iter(exec_list_iterator, iter, *this->acp) {
+        acp_entry *entry = (acp_entry *)iter.get();
+        if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
+           found = entry;
+           break;
+        }
+      }
+
+      if (!found)
+        return;
+
+      int rhs_channel = 0;
+      for (int j = 0; j < 4; j++) {
+        if (j == channel)
+           break;
+        if (found->write_mask & (1 << j))
+           rhs_channel++;
+      }
+
+      switch (type->base_type) {
+      case GLSL_TYPE_FLOAT:
+        data.f[i] = found->constant->value.f[rhs_channel];
+        break;
+      case GLSL_TYPE_INT:
+        data.i[i] = found->constant->value.i[rhs_channel];
+        break;
+      case GLSL_TYPE_UINT:
+        data.u[i] = found->constant->value.u[rhs_channel];
+        break;
+      case GLSL_TYPE_BOOL:
+        data.b[i] = found->constant->value.b[rhs_channel];
+        break;
+      default:
+        assert(!"not reached");
+        break;
+      }
+   }
+
+   *rvalue = new(talloc_parent(deref)) ir_constant(type, &data);
+   this->progress = true;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
+{
+   /* Treat entry into a function signature as a completely separate
+    * block.  Any instructions at global scope will be shuffled into
+    * main() at link time, so they're irrelevant to us.
+    */
+   exec_list *orig_acp = this->acp;
+   exec_list *orig_kills = this->kills;
+   bool orig_killed_all = this->killed_all;
+
+   this->acp = new(mem_ctx) exec_list;
+   this->kills = new(mem_ctx) exec_list;
+   this->killed_all = false;
+
+   visit_list_elements(this, &ir->body);
+
+   this->kills = orig_kills;
+   this->acp = orig_acp;
+   this->killed_all = orig_killed_all;
+
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
+{
+   if (this->in_assignee)
+      return visit_continue;
+
+   kill(ir->lhs->variable_referenced(), ir->write_mask);
+
+   add_constant(ir);
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_function *ir)
+{
+   (void) ir;
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_call *ir)
+{
+   /* Do constant propagation on call parameters, but skip any out params */
+   exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+   foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
+      ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
+      ir_rvalue *param = (ir_rvalue *)iter.get();
+      if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
+        ir_rvalue *new_param = param;
+        handle_rvalue(&new_param);
+         if (new_param != param)
+           param->replace_with(new_param);
+        else
+           param->accept(this);
+      }
+      sig_param_iter.next();
+   }
+
+   /* Since we're unlinked, we don't (necssarily) know the side effects of
+    * this call.  So kill all copies.
+    */
+   acp->make_empty();
+   this->killed_all = true;
+
+   return visit_continue_with_parent;
+}
+
+void
+ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
+{
+   exec_list *orig_acp = this->acp;
+   exec_list *orig_kills = this->kills;
+   bool orig_killed_all = this->killed_all;
+
+   this->acp = new(mem_ctx) exec_list;
+   this->kills = new(mem_ctx) exec_list;
+   this->killed_all = false;
+
+   /* Populate the initial acp with a constant of the original */
+   foreach_iter(exec_list_iterator, iter, *orig_acp) {
+      acp_entry *a = (acp_entry *)iter.get();
+      this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask,
+                                                       a->constant));
+   }
+
+   visit_list_elements(this, instructions);
+
+   if (this->killed_all) {
+      orig_acp->make_empty();
+   }
+
+   exec_list *new_kills = this->kills;
+   this->kills = orig_kills;
+   this->acp = orig_acp;
+   this->killed_all = this->killed_all || orig_killed_all;
+
+   foreach_iter(exec_list_iterator, iter, *new_kills) {
+      kill_entry *k = (kill_entry *)iter.get();
+      kill(k->var, k->write_mask);
+   }
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_if *ir)
+{
+   ir->condition->accept(this);
+   handle_rvalue(&ir->condition);
+
+   handle_if_block(&ir->then_instructions);
+   handle_if_block(&ir->else_instructions);
+
+   /* handle_if_block() already descended into the children. */
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
+{
+   exec_list *orig_acp = this->acp;
+   exec_list *orig_kills = this->kills;
+   bool orig_killed_all = this->killed_all;
+
+   /* FINISHME: For now, the initial acp for loops is totally empty.
+    * We could go through once, then go through again with the acp
+    * cloned minus the killed entries after the first run through.
+    */
+   this->acp = new(mem_ctx) exec_list;
+   this->kills = new(mem_ctx) exec_list;
+   this->killed_all = false;
+
+   visit_list_elements(this, &ir->body_instructions);
+
+   if (this->killed_all) {
+      orig_acp->make_empty();
+   }
+
+   exec_list *new_kills = this->kills;
+   this->kills = orig_kills;
+   this->acp = orig_acp;
+   this->killed_all = this->killed_all || orig_killed_all;
+
+   foreach_iter(exec_list_iterator, iter, *new_kills) {
+      kill_entry *k = (kill_entry *)iter.get();
+      kill(k->var, k->write_mask);
+   }
+
+   /* already descended into the children. */
+   return visit_continue_with_parent;
+}
+
+void
+ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
+{
+   assert(var != NULL);
+
+   /* We don't track non-vectors. */
+   if (!var->type->is_vector() && !var->type->is_scalar())
+      return;
+
+   /* Remove any entries currently in the ACP for this kill. */
+   foreach_iter(exec_list_iterator, iter, *this->acp) {
+      acp_entry *entry = (acp_entry *)iter.get();
+
+      if (entry->var == var) {
+        entry->write_mask &= ~write_mask;
+        if (entry->write_mask == 0)
+           entry->remove();
+      }
+   }
+
+   /* Add this writemask of the variable to the list of killed
+    * variables in this block.
+    */
+   foreach_iter(exec_list_iterator, iter, *this->kills) {
+      kill_entry *entry = (kill_entry *)iter.get();
+
+      if (entry->var == var) {
+        entry->write_mask |= write_mask;
+        return;
+      }
+   }
+   /* Not already in the list.  Make new entry. */
+   this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
+}
+
+/**
+ * Adds an entry to the available constant list if it's a plain assignment
+ * of a variable to a variable.
+ */
+void
+ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
+{
+   acp_entry *entry;
+
+   if (ir->condition) {
+      ir_constant *condition = ir->condition->as_constant();
+      if (!condition || !condition->value.b[0])
+        return;
+   }
+
+   if (!ir->write_mask)
+      return;
+
+   ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
+   ir_constant *constant = ir->rhs->as_constant();
+
+   if (!deref || !constant)
+      return;
+
+   /* Only do constant propagation on vectors.  Constant matrices,
+    * arrays, or structures would require more work elsewhere.
+    */
+   if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
+      return;
+
+   entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
+   this->acp->push_tail(entry);
+}
+
+/**
+ * Does a constant propagation pass on the code present in the instruction stream.
+ */
+bool
+do_constant_propagation(exec_list *instructions)
+{
+   ir_constant_propagation_visitor v;
+
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/opt_constant_variable.cpp b/src/glsl/opt_constant_variable.cpp
new file mode 100644 (file)
index 0000000..1fb73e7
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_constant_variable.cpp
+ *
+ * Marks variables assigned a single constant value over the course
+ * of the program as constant.
+ *
+ * The goal here is to trigger further constant folding and then dead
+ * code elimination.  This is common with vector/matrix constructors
+ * and calls to builtin functions.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+struct assignment_entry {
+   exec_node link;
+   int assignment_count;
+   ir_variable *var;
+   ir_constant *constval;
+   bool our_scope;
+};
+
+class ir_constant_variable_visitor : public ir_hierarchical_visitor {
+public:
+   virtual ir_visitor_status visit_enter(ir_dereference_variable *);
+   virtual ir_visitor_status visit(ir_variable *);
+   virtual ir_visitor_status visit_enter(ir_assignment *);
+   virtual ir_visitor_status visit_enter(ir_call *);
+
+   exec_list list;
+};
+
+static struct assignment_entry *
+get_assignment_entry(ir_variable *var, exec_list *list)
+{
+   struct assignment_entry *entry;
+
+   foreach_list_typed(struct assignment_entry, entry, link, list) {
+      if (entry->var == var)
+        return entry;
+   }
+
+   entry = (struct assignment_entry *)calloc(1, sizeof(*entry));
+   entry->var = var;
+   list->push_head(&entry->link);
+   return entry;
+}
+
+ir_visitor_status
+ir_constant_variable_visitor::visit(ir_variable *ir)
+{
+   struct assignment_entry *entry = get_assignment_entry(ir, &this->list);
+   entry->our_scope = true;
+   return visit_continue;
+}
+
+/* Skip derefs of variables so that we can detect declarations. */
+ir_visitor_status
+ir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir)
+{
+   (void)ir;
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
+{
+   ir_constant *constval;
+   struct assignment_entry *entry;
+
+   entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list);
+   assert(entry);
+   entry->assignment_count++;
+
+   /* If it's already constant, don't do the work. */
+   if (entry->var->constant_value)
+      return visit_continue;
+
+   /* OK, now find if we actually have all the right conditions for
+    * this to be a constant value assigned to the var.
+    */
+   if (ir->condition) {
+      constval = ir->condition->constant_expression_value();
+      if (!constval || !constval->value.b[0])
+        return visit_continue;
+   }
+
+   ir_variable *var = ir->whole_variable_written();
+   if (!var)
+      return visit_continue;
+
+   constval = ir->rhs->constant_expression_value();
+   if (!constval)
+      return visit_continue;
+
+   /* Mark this entry as having a constant assignment (if the
+    * assignment count doesn't go >1).  do_constant_variable will fix
+    * up the variable with the constant value later.
+    */
+   entry->constval = constval;
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_constant_variable_visitor::visit_enter(ir_call *ir)
+{
+   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+   foreach_iter(exec_list_iterator, iter, *ir) {
+      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+      ir_variable *param = (ir_variable *)sig_iter.get();
+
+      if (param->mode == ir_var_out ||
+         param->mode == ir_var_inout) {
+        ir_variable *var = param_rval->variable_referenced();
+        struct assignment_entry *entry;
+
+        assert(var);
+        entry = get_assignment_entry(var, &this->list);
+        entry->assignment_count++;
+      }
+      sig_iter.next();
+   }
+   return visit_continue;
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_constant_variable(exec_list *instructions)
+{
+   bool progress = false;
+   ir_constant_variable_visitor v;
+
+   v.run(instructions);
+
+   while (!v.list.is_empty()) {
+
+      struct assignment_entry *entry;
+      entry = exec_node_data(struct assignment_entry, v.list.head, link);
+
+      if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
+        entry->var->constant_value = entry->constval;
+        progress = true;
+      }
+      entry->link.remove();
+      free(entry);
+   }
+
+   return progress;
+}
+
+bool
+do_constant_variable_unlinked(exec_list *instructions)
+{
+   bool progress = false;
+
+   foreach_iter(exec_list_iterator, iter, *instructions) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+      ir_function *f = ir->as_function();
+      if (f) {
+        foreach_iter(exec_list_iterator, sigiter, *f) {
+           ir_function_signature *sig =
+              (ir_function_signature *) sigiter.get();
+           if (do_constant_variable(&sig->body))
+              progress = true;
+        }
+      }
+   }
+
+   return progress;
+}
diff --git a/src/glsl/opt_copy_propagation.cpp b/src/glsl/opt_copy_propagation.cpp
new file mode 100644 (file)
index 0000000..0fe8fa6
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_copy_propagation.cpp
+ *
+ * Moves usage of recently-copied variables to the previous copy of
+ * the variable.
+ *
+ * This should reduce the number of MOV instructions in the generated
+ * programs unless copy propagation is also done on the LIR, and may
+ * help anyway by triggering other optimizations that live in the HIR.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+class acp_entry : public exec_node
+{
+public:
+   acp_entry(ir_variable *lhs, ir_variable *rhs)
+   {
+      assert(lhs);
+      assert(rhs);
+      this->lhs = lhs;
+      this->rhs = rhs;
+   }
+
+   ir_variable *lhs;
+   ir_variable *rhs;
+};
+
+
+class kill_entry : public exec_node
+{
+public:
+   kill_entry(ir_variable *var)
+   {
+      assert(var);
+      this->var = var;
+   }
+
+   ir_variable *var;
+};
+
+class ir_copy_propagation_visitor : public ir_hierarchical_visitor {
+public:
+   ir_copy_propagation_visitor()
+   {
+      progress = false;
+      mem_ctx = talloc_new(0);
+      this->acp = new(mem_ctx) exec_list;
+      this->kills = new(mem_ctx) exec_list;
+   }
+   ~ir_copy_propagation_visitor()
+   {
+      talloc_free(mem_ctx);
+   }
+
+   virtual ir_visitor_status visit(class ir_dereference_variable *);
+   virtual ir_visitor_status visit_enter(class ir_loop *);
+   virtual ir_visitor_status visit_enter(class ir_function_signature *);
+   virtual ir_visitor_status visit_enter(class ir_function *);
+   virtual ir_visitor_status visit_leave(class ir_assignment *);
+   virtual ir_visitor_status visit_enter(class ir_call *);
+   virtual ir_visitor_status visit_enter(class ir_if *);
+
+   void add_copy(ir_assignment *ir);
+   void kill(ir_variable *ir);
+   void handle_if_block(exec_list *instructions);
+
+   /** List of acp_entry: The available copies to propagate */
+   exec_list *acp;
+   /**
+    * List of kill_entry: The variables whose values were killed in this
+    * block.
+    */
+   exec_list *kills;
+
+   bool progress;
+
+   bool killed_all;
+
+   void *mem_ctx;
+};
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir)
+{
+   /* Treat entry into a function signature as a completely separate
+    * block.  Any instructions at global scope will be shuffled into
+    * main() at link time, so they're irrelevant to us.
+    */
+   exec_list *orig_acp = this->acp;
+   exec_list *orig_kills = this->kills;
+   bool orig_killed_all = this->killed_all;
+
+   this->acp = new(mem_ctx) exec_list;
+   this->kills = new(mem_ctx) exec_list;
+   this->killed_all = false;
+
+   visit_list_elements(this, &ir->body);
+
+   this->kills = orig_kills;
+   this->acp = orig_acp;
+   this->killed_all = orig_killed_all;
+
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_leave(ir_assignment *ir)
+{
+   kill(ir->lhs->variable_referenced());
+
+   add_copy(ir);
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_function *ir)
+{
+   (void) ir;
+   return visit_continue;
+}
+
+/**
+ * Replaces dereferences of ACP RHS variables with ACP LHS variables.
+ *
+ * This is where the actual copy propagation occurs.  Note that the
+ * rewriting of ir_dereference means that the ir_dereference instance
+ * must not be shared by multiple IR operations!
+ */
+ir_visitor_status
+ir_copy_propagation_visitor::visit(ir_dereference_variable *ir)
+{
+   if (this->in_assignee)
+      return visit_continue;
+
+   ir_variable *var = ir->var;
+
+   foreach_iter(exec_list_iterator, iter, *this->acp) {
+      acp_entry *entry = (acp_entry *)iter.get();
+
+      if (var == entry->lhs) {
+        ir->var = entry->rhs;
+        this->progress = true;
+        break;
+      }
+   }
+
+   return visit_continue;
+}
+
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_call *ir)
+{
+   /* Do copy propagation on call parameters, but skip any out params */
+   exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
+   foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
+      ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
+      ir_instruction *ir = (ir_instruction *)iter.get();
+      if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
+         ir->accept(this);
+      }
+      sig_param_iter.next();
+   }
+
+   /* Since we're unlinked, we don't (necssarily) know the side effects of
+    * this call.  So kill all copies.
+    */
+   acp->make_empty();
+   this->killed_all = true;
+
+   return visit_continue_with_parent;
+}
+
+void
+ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
+{
+   exec_list *orig_acp = this->acp;
+   exec_list *orig_kills = this->kills;
+   bool orig_killed_all = this->killed_all;
+
+   this->acp = new(mem_ctx) exec_list;
+   this->kills = new(mem_ctx) exec_list;
+   this->killed_all = false;
+
+   /* Populate the initial acp with a copy of the original */
+   foreach_iter(exec_list_iterator, iter, *orig_acp) {
+      acp_entry *a = (acp_entry *)iter.get();
+      this->acp->push_tail(new(this->mem_ctx) acp_entry(a->lhs, a->rhs));
+   }
+
+   visit_list_elements(this, instructions);
+
+   if (this->killed_all) {
+      orig_acp->make_empty();
+   }
+
+   exec_list *new_kills = this->kills;
+   this->kills = orig_kills;
+   this->acp = orig_acp;
+   this->killed_all = this->killed_all || orig_killed_all;
+
+   foreach_iter(exec_list_iterator, iter, *new_kills) {
+      kill_entry *k = (kill_entry *)iter.get();
+      kill(k->var);
+   }
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_if *ir)
+{
+   ir->condition->accept(this);
+
+   handle_if_block(&ir->then_instructions);
+   handle_if_block(&ir->else_instructions);
+
+   /* handle_if_block() already descended into the children. */
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_copy_propagation_visitor::visit_enter(ir_loop *ir)
+{
+   exec_list *orig_acp = this->acp;
+   exec_list *orig_kills = this->kills;
+   bool orig_killed_all = this->killed_all;
+
+   /* FINISHME: For now, the initial acp for loops is totally empty.
+    * We could go through once, then go through again with the acp
+    * cloned minus the killed entries after the first run through.
+    */
+   this->acp = new(mem_ctx) exec_list;
+   this->kills = new(mem_ctx) exec_list;
+   this->killed_all = false;
+
+   visit_list_elements(this, &ir->body_instructions);
+
+   if (this->killed_all) {
+      orig_acp->make_empty();
+   }
+
+   exec_list *new_kills = this->kills;
+   this->kills = orig_kills;
+   this->acp = orig_acp;
+   this->killed_all = this->killed_all || orig_killed_all;
+
+   foreach_iter(exec_list_iterator, iter, *new_kills) {
+      kill_entry *k = (kill_entry *)iter.get();
+      kill(k->var);
+   }
+
+   /* already descended into the children. */
+   return visit_continue_with_parent;
+}
+
+void
+ir_copy_propagation_visitor::kill(ir_variable *var)
+{
+   assert(var != NULL);
+
+   /* Remove any entries currently in the ACP for this kill. */
+   foreach_iter(exec_list_iterator, iter, *acp) {
+      acp_entry *entry = (acp_entry *)iter.get();
+
+      if (entry->lhs == var || entry->rhs == var) {
+        entry->remove();
+      }
+   }
+
+   /* Add the LHS variable to the list of killed variables in this block.
+    */
+   this->kills->push_tail(new(this->mem_ctx) kill_entry(var));
+}
+
+/**
+ * Adds an entry to the available copy list if it's a plain assignment
+ * of a variable to a variable.
+ */
+void
+ir_copy_propagation_visitor::add_copy(ir_assignment *ir)
+{
+   acp_entry *entry;
+
+   if (ir->condition) {
+      ir_constant *condition = ir->condition->as_constant();
+      if (!condition || !condition->value.b[0])
+        return;
+   }
+
+   ir_variable *lhs_var = ir->whole_variable_written();
+   ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
+
+   if ((lhs_var != NULL) && (rhs_var != NULL)) {
+      if (lhs_var == rhs_var) {
+        /* This is a dumb assignment, but we've conveniently noticed
+         * it here.  Removing it now would mess up the loop iteration
+         * calling us.  Just flag it to not execute, and someone else
+         * will clean up the mess.
+         */
+        ir->condition = new(talloc_parent(ir)) ir_constant(false);
+        this->progress = true;
+      } else {
+        entry = new(this->mem_ctx) acp_entry(lhs_var, rhs_var);
+        this->acp->push_tail(entry);
+      }
+   }
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_copy_propagation(exec_list *instructions)
+{
+   ir_copy_propagation_visitor v;
+
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/opt_dead_code.cpp b/src/glsl/opt_dead_code.cpp
new file mode 100644 (file)
index 0000000..5cf5e99
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_dead_code.cpp
+ *
+ * Eliminates dead assignments and variable declarations from the code.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_variable_refcount.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+/**
+ * Do a dead code pass over instructions and everything that instructions
+ * references.
+ *
+ * Note that this will remove assignments to globals, so it is not suitable
+ * for usage on an unlinked instruction stream.
+ */
+bool
+do_dead_code(exec_list *instructions)
+{
+   ir_variable_refcount_visitor v;
+   bool progress = false;
+
+   v.run(instructions);
+
+   foreach_iter(exec_list_iterator, iter, v.variable_list) {
+      variable_entry *entry = (variable_entry *)iter.get();
+
+      /* Since each assignment is a reference, the refereneced count must be
+       * greater than or equal to the assignment count.  If they are equal,
+       * then all of the references are assignments, and the variable is
+       * dead.
+       *
+       * Note that if the variable is neither assigned nor referenced, both
+       * counts will be zero and will be caught by the equality test.
+       */
+      assert(entry->referenced_count >= entry->assigned_count);
+
+      if (debug) {
+        printf("%s@%p: %d refs, %d assigns, %sdeclared in our scope\n",
+               entry->var->name, (void *) entry->var,
+               entry->referenced_count, entry->assigned_count,
+               entry->declaration ? "" : "not ");
+      }
+
+      if ((entry->referenced_count > entry->assigned_count)
+         || !entry->declaration)
+        continue;
+
+      if (entry->assign) {
+        /* Remove a single dead assignment to the variable we found.
+         * Don't do so if it's a shader output, though.
+         */
+        if (entry->var->mode != ir_var_out &&
+            entry->var->mode != ir_var_inout &&
+            !ir_has_call(entry->assign)) {
+           entry->assign->remove();
+           progress = true;
+
+           if (debug) {
+              printf("Removed assignment to %s@%p\n",
+                     entry->var->name, (void *) entry->var);
+           }
+        }
+      } else {
+        /* If there are no assignments or references to the variable left,
+         * then we can remove its declaration.
+         */
+
+        /* uniform initializers are precious, and could get used by another
+         * stage.
+         */
+        if (entry->var->mode == ir_var_uniform &&
+            entry->var->constant_value)
+           continue;
+
+        entry->var->remove();
+        progress = true;
+
+        if (debug) {
+           printf("Removed declaration of %s@%p\n",
+                  entry->var->name, (void *) entry->var);
+        }
+      }
+   }
+
+   return progress;
+}
+
+/**
+ * Does a dead code pass on the functions present in the instruction stream.
+ *
+ * This is suitable for use while the program is not linked, as it will
+ * ignore variable declarations (and the assignments to them) for variables
+ * with global scope.
+ */
+bool
+do_dead_code_unlinked(exec_list *instructions)
+{
+   bool progress = false;
+
+   foreach_iter(exec_list_iterator, iter, *instructions) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+      ir_function *f = ir->as_function();
+      if (f) {
+        foreach_iter(exec_list_iterator, sigiter, *f) {
+           ir_function_signature *sig =
+              (ir_function_signature *) sigiter.get();
+           if (do_dead_code(&sig->body))
+              progress = true;
+        }
+      }
+   }
+
+   return progress;
+}
diff --git a/src/glsl/opt_dead_code_local.cpp b/src/glsl/opt_dead_code_local.cpp
new file mode 100644 (file)
index 0000000..4bbedf0
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_dead_code_local.cpp
+ *
+ * Eliminates local dead assignments from the code.
+ *
+ * This operates on basic blocks, tracking assignments and finding if
+ * they're used before the variable is completely reassigned.
+ *
+ * Compare this to ir_dead_code.cpp, which operates globally looking
+ * for assignments to variables that are never read.
+ */
+
+#include "ir.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+class assignment_entry : public exec_node
+{
+public:
+   assignment_entry(ir_variable *lhs, ir_instruction *ir)
+   {
+      assert(lhs);
+      assert(ir);
+      this->lhs = lhs;
+      this->ir = ir;
+   }
+
+   ir_variable *lhs;
+   ir_instruction *ir;
+};
+
+class kill_for_derefs_visitor : public ir_hierarchical_visitor {
+public:
+   kill_for_derefs_visitor(exec_list *assignments)
+   {
+      this->assignments = assignments;
+   }
+
+   virtual ir_visitor_status visit(ir_dereference_variable *ir)
+   {
+      ir_variable *const var = ir->variable_referenced();
+
+      foreach_iter(exec_list_iterator, iter, *this->assignments) {
+        assignment_entry *entry = (assignment_entry *)iter.get();
+
+        if (entry->lhs == var) {
+           if (debug)
+              printf("kill %s\n", entry->lhs->name);
+           entry->remove();
+        }
+      }
+
+      return visit_continue;
+   }
+
+private:
+   exec_list *assignments;
+};
+
+class array_index_visit : public ir_hierarchical_visitor {
+public:
+   array_index_visit(ir_hierarchical_visitor *v)
+   {
+      this->visitor = v;
+   }
+
+   virtual ir_visitor_status visit_enter(class ir_dereference_array *ir)
+   {
+      ir->array_index->accept(visitor);
+      return visit_continue;
+   }
+
+   static void run(ir_instruction *ir, ir_hierarchical_visitor *v)
+   {
+      array_index_visit top_visit(v);
+      ir->accept(& top_visit);
+   }
+
+   ir_hierarchical_visitor *visitor;
+};
+
+
+/**
+ * Adds an entry to the available copy list if it's a plain assignment
+ * of a variable to a variable.
+ */
+static bool
+process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
+{
+   ir_variable *var = NULL;
+   bool progress = false;
+   kill_for_derefs_visitor v(assignments);
+
+   /* Kill assignment entries for things used to produce this assignment. */
+   ir->rhs->accept(&v);
+   if (ir->condition) {
+      ir->condition->accept(&v);
+   }
+
+   /* Kill assignment enties used as array indices.
+    */
+   array_index_visit::run(ir->lhs, &v);
+   var = ir->lhs->variable_referenced();
+   assert(var);
+
+   bool always_assign = true;
+   if (ir->condition) {
+      ir_constant *condition = ir->condition->as_constant();
+      if (!condition || !condition->value.b[0])
+        always_assign = false;
+   }
+
+   /* Now, check if we did a whole-variable assignment. */
+   if (always_assign && (ir->whole_variable_written() != NULL)) {
+      /* We did a whole-variable assignment.  So, any instruction in
+       * the assignment list with the same LHS is dead.
+       */
+      if (debug)
+        printf("looking for %s to remove\n", var->name);
+      foreach_iter(exec_list_iterator, iter, *assignments) {
+        assignment_entry *entry = (assignment_entry *)iter.get();
+
+        if (entry->lhs == var) {
+           if (debug)
+              printf("removing %s\n", var->name);
+           entry->ir->remove();
+           entry->remove();
+           progress = true;
+        }
+      }
+   }
+
+   /* Add this instruction to the assignment list available to be removed.
+    * But not if the assignment has other side effects.
+    */
+   if (ir_has_call(ir))
+      return progress;
+
+   assignment_entry *entry = new(ctx) assignment_entry(var, ir);
+   assignments->push_tail(entry);
+
+   if (debug) {
+      printf("add %s\n", var->name);
+
+      printf("current entries\n");
+      foreach_iter(exec_list_iterator, iter, *assignments) {
+        assignment_entry *entry = (assignment_entry *)iter.get();
+
+        printf("    %s\n", entry->lhs->name);
+      }
+   }
+
+   return progress;
+}
+
+static void
+dead_code_local_basic_block(ir_instruction *first,
+                            ir_instruction *last,
+                            void *data)
+{
+   ir_instruction *ir, *ir_next;
+   /* List of avaialble_copy */
+   exec_list assignments;
+   bool *out_progress = (bool *)data;
+   bool progress = false;
+
+   void *ctx = talloc_new(NULL);
+   /* Safe looping, since process_assignment */
+   for (ir = first, ir_next = (ir_instruction *)first->next;;
+       ir = ir_next, ir_next = (ir_instruction *)ir->next) {
+      ir_assignment *ir_assign = ir->as_assignment();
+
+      if (debug) {
+        ir->print();
+        printf("\n");
+      }
+
+      if (ir_assign) {
+        progress = process_assignment(ctx, ir_assign, &assignments) || progress;
+      } else {
+        kill_for_derefs_visitor kill(&assignments);
+        ir->accept(&kill);
+      }
+
+      if (ir == last)
+        break;
+   }
+   *out_progress = progress;
+   talloc_free(ctx);
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_dead_code_local(exec_list *instructions)
+{
+   bool progress = false;
+
+   call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress);
+
+   return progress;
+}
diff --git a/src/glsl/opt_dead_functions.cpp b/src/glsl/opt_dead_functions.cpp
new file mode 100644 (file)
index 0000000..16037a2
--- /dev/null
@@ -0,0 +1,153 @@
+ /*
+  * Copyright © 2010 Intel Corporation
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the "Software"),
+  * to deal in the Software without restriction, including without limitation
+  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  * and/or sell copies of the Software, and to permit persons to whom the
+  * Software is furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice (including the next
+  * paragraph) shall be included in all copies or substantial portions of the
+  * Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  * DEALINGS IN THE SOFTWARE.
+  */
+
+ /**
+  * \file ir_dead_functions.cpp
+  *
+  * Eliminates unused functions from the linked program.
+  */
+
+ #include "ir.h"
+ #include "ir_visitor.h"
+ #include "ir_expression_flattening.h"
+ #include "glsl_types.h"
+
+ class signature_entry : public exec_node
+ {
+ public:
+    signature_entry(ir_function_signature *sig)
+    {
+       this->signature = sig;
+       this->used = false;
+    }
+
+    ir_function_signature *signature;
+    bool used;
+ };
+
+ class ir_dead_functions_visitor : public ir_hierarchical_visitor {
+ public:
+    ir_dead_functions_visitor()
+    {
+       this->mem_ctx = talloc_new(NULL);
+    }
+
+    ~ir_dead_functions_visitor()
+    {
+       talloc_free(this->mem_ctx);
+    }
+
+    virtual ir_visitor_status visit_enter(ir_function_signature *);
+    virtual ir_visitor_status visit_enter(ir_call *);
+
+    signature_entry *get_signature_entry(ir_function_signature *var);
+
+    bool (*predicate)(ir_instruction *ir);
+
+    /* List of signature_entry */
+    exec_list signature_list;
+    void *mem_ctx;
+ };
+
+
+ signature_entry *
+ ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig)
+ {
+    foreach_iter(exec_list_iterator, iter, this->signature_list) {
+       signature_entry *entry = (signature_entry *)iter.get();
+       if (entry->signature == sig)
+         return entry;
+    }
+
+    signature_entry *entry = new(mem_ctx) signature_entry(sig);
+    this->signature_list.push_tail(entry);
+    return entry;
+ }
+
+
+ ir_visitor_status
+ ir_dead_functions_visitor::visit_enter(ir_function_signature *ir)
+ {
+    signature_entry *entry = this->get_signature_entry(ir);
+
+    if (strcmp(ir->function_name(), "main") == 0) {
+       entry->used = true;
+    }
+
+    return visit_continue;
+ }
+
+
+ ir_visitor_status
+ ir_dead_functions_visitor::visit_enter(ir_call *ir)
+ {
+    signature_entry *entry = this->get_signature_entry(ir->get_callee());
+
+    entry->used = true;
+
+   return visit_continue;
+}
+
+bool
+do_dead_functions(exec_list *instructions)
+{
+   ir_dead_functions_visitor v;
+   bool progress = false;
+
+   visit_list_elements(&v, instructions);
+
+   /* Now that we've figured out which function signatures are used, remove
+    * the unused ones, and remove function definitions that have no more
+    * signatures.
+    */
+    foreach_iter(exec_list_iterator, iter, v.signature_list) {
+      signature_entry *entry = (signature_entry *)iter.get();
+
+      if (!entry->used) {
+        entry->signature->remove();
+        delete entry->signature;
+        progress = true;
+      }
+      delete(entry);
+   }
+
+   /* We don't just do this above when we nuked a signature because of
+    * const pointers.
+    */
+   foreach_iter(exec_list_iterator, iter, *instructions) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+      ir_function *func = ir->as_function();
+
+      if (func && func->signatures.is_empty()) {
+        /* At this point (post-linking), the symbol table is no
+         * longer in use, so not removing the function from the
+         * symbol table should be OK.
+         */
+        func->remove();
+        delete func;
+        progress = true;
+      }
+   }
+
+   return progress;
+}
diff --git a/src/glsl/opt_function_inlining.cpp b/src/glsl/opt_function_inlining.cpp
new file mode 100644 (file)
index 0000000..147c182
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_function_inlining.cpp
+ *
+ * Replaces calls to functions with the body of the function.
+ */
+
+#include <inttypes.h>
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_function_inlining.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+#include "program/hash_table.h"
+
+static void
+do_sampler_replacement(exec_list *instructions,
+                      ir_variable *sampler,
+                      ir_dereference *deref);
+
+class ir_function_inlining_visitor : public ir_hierarchical_visitor {
+public:
+   ir_function_inlining_visitor()
+   {
+      progress = false;
+   }
+
+   virtual ~ir_function_inlining_visitor()
+   {
+      /* empty */
+   }
+
+   virtual ir_visitor_status visit_enter(ir_expression *);
+   virtual ir_visitor_status visit_enter(ir_call *);
+   virtual ir_visitor_status visit_enter(ir_assignment *);
+   virtual ir_visitor_status visit_enter(ir_return *);
+   virtual ir_visitor_status visit_enter(ir_texture *);
+   virtual ir_visitor_status visit_enter(ir_swizzle *);
+
+   bool progress;
+};
+
+
+bool
+automatic_inlining_predicate(ir_instruction *ir)
+{
+   ir_call *call = ir->as_call();
+
+   if (call && can_inline(call))
+      return true;
+
+   return false;
+}
+
+bool
+do_function_inlining(exec_list *instructions)
+{
+   ir_function_inlining_visitor v;
+
+   do_expression_flattening(instructions, automatic_inlining_predicate);
+
+   v.run(instructions);
+
+   return v.progress;
+}
+
+static void
+replace_return_with_assignment(ir_instruction *ir, void *data)
+{
+   void *ctx = talloc_parent(ir);
+   ir_variable *retval = (ir_variable *)data;
+   ir_return *ret = ir->as_return();
+
+   if (ret) {
+      if (ret->value) {
+        ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval);
+        ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL));
+      } else {
+        /* un-valued return has to be the last return, or we shouldn't
+         * have reached here. (see can_inline()).
+         */
+        assert(ret->next->is_tail_sentinel());
+        ret->remove();
+      }
+   }
+}
+
+ir_rvalue *
+ir_call::generate_inline(ir_instruction *next_ir)
+{
+   void *ctx = talloc_parent(this);
+   ir_variable **parameters;
+   int num_parameters;
+   int i;
+   ir_variable *retval = NULL;
+   struct hash_table *ht;
+
+   ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare);
+
+   num_parameters = 0;
+   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
+      num_parameters++;
+
+   parameters = new ir_variable *[num_parameters];
+
+   /* Generate storage for the return value. */
+   if (this->callee->return_type) {
+      retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val",
+                                   ir_var_auto);
+      next_ir->insert_before(retval);
+   }
+
+   /* Generate the declarations for the parameters to our inlined code,
+    * and set up the mapping of real function body variables to ours.
+    */
+   i = 0;
+   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
+   exec_list_iterator param_iter = this->actual_parameters.iterator();
+   for (i = 0; i < num_parameters; i++) {
+      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
+      ir_rvalue *param = (ir_rvalue *) param_iter.get();
+
+      /* Generate a new variable for the parameter. */
+      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
+        /* For samplers, we want the inlined sampler references
+         * referencing the passed in sampler variable, since that
+         * will have the location information, which an assignment of
+         * a sampler wouldn't.  Fix it up below.
+         */
+        parameters[i] = NULL;
+      } else {
+        parameters[i] = sig_param->clone(ctx, ht);
+        parameters[i]->mode = ir_var_auto;
+
+        /* Remove the read-only decoration becuase we're going to write
+         * directly to this variable.  If the cloned variable is left
+         * read-only and the inlined function is inside a loop, the loop
+         * analysis code will get confused.
+         */
+        parameters[i]->read_only = false;
+        next_ir->insert_before(parameters[i]);
+      }
+
+      /* Move the actual param into our param variable if it's an 'in' type. */
+      if (parameters[i] && (sig_param->mode == ir_var_in ||
+                           sig_param->mode == ir_var_inout)) {
+        ir_assignment *assign;
+
+        assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]),
+                                        param, NULL);
+        next_ir->insert_before(assign);
+      }
+
+      sig_param_iter.next();
+      param_iter.next();
+   }
+
+   exec_list new_instructions;
+
+   /* Generate the inlined body of the function to a new list */
+   foreach_iter(exec_list_iterator, iter, callee->body) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+      ir_instruction *new_ir = ir->clone(ctx, ht);
+
+      new_instructions.push_tail(new_ir);
+      visit_tree(new_ir, replace_return_with_assignment, retval);
+   }
+
+   /* If any samplers were passed in, replace any deref of the sampler
+    * with a deref of the sampler argument.
+    */
+   param_iter = this->actual_parameters.iterator();
+   sig_param_iter = this->callee->parameters.iterator();
+   for (i = 0; i < num_parameters; i++) {
+      ir_instruction *const param = (ir_instruction *) param_iter.get();
+      ir_variable *sig_param = (ir_variable *) sig_param_iter.get();
+
+      if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) {
+        ir_dereference *deref = param->as_dereference();
+
+        assert(deref);
+        do_sampler_replacement(&new_instructions, sig_param, deref);
+      }
+      param_iter.next();
+      sig_param_iter.next();
+   }
+
+   /* Now push those new instructions in. */
+   foreach_iter(exec_list_iterator, iter, new_instructions) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+      next_ir->insert_before(ir);
+   }
+
+   /* Copy back the value of any 'out' parameters from the function body
+    * variables to our own.
+    */
+   i = 0;
+   param_iter = this->actual_parameters.iterator();
+   sig_param_iter = this->callee->parameters.iterator();
+   for (i = 0; i < num_parameters; i++) {
+      ir_instruction *const param = (ir_instruction *) param_iter.get();
+      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
+
+      /* Move our param variable into the actual param if it's an 'out' type. */
+      if (parameters[i] && (sig_param->mode == ir_var_out ||
+                           sig_param->mode == ir_var_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);
+      }
+
+      param_iter.next();
+      sig_param_iter.next();
+   }
+
+   delete [] parameters;
+
+   hash_table_dtor(ht);
+
+   if (retval)
+      return new(ctx) ir_dereference_variable(retval);
+   else
+      return NULL;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_expression *ir)
+{
+   (void) ir;
+   return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_return *ir)
+{
+   (void) ir;
+   return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_texture *ir)
+{
+   (void) ir;
+   return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_swizzle *ir)
+{
+   (void) ir;
+   return visit_continue_with_parent;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_call *ir)
+{
+   if (can_inline(ir)) {
+      /* If the call was part of some tree, then it should have been
+       * flattened out or we shouldn't have seen it because of a
+       * visit_continue_with_parent in this visitor.
+       */
+      assert(ir == base_ir);
+
+      (void) ir->generate_inline(ir);
+      ir->remove();
+      this->progress = true;
+   }
+
+   return visit_continue;
+}
+
+
+ir_visitor_status
+ir_function_inlining_visitor::visit_enter(ir_assignment *ir)
+{
+   ir_call *call = ir->rhs->as_call();
+   if (!call || !can_inline(call))
+      return visit_continue;
+
+   /* generates the parameter setup, function body, and returns the return
+    * value of the function
+    */
+   ir_rvalue *rhs = call->generate_inline(ir);
+   assert(rhs);
+
+   ir->rhs = rhs;
+   this->progress = true;
+
+   return visit_continue;
+}
+
+/**
+ * Replaces references to the "sampler" variable with a clone of "deref."
+ *
+ * From the spec, samplers can appear in the tree as function
+ * (non-out) parameters and as the result of array indexing and
+ * structure field selection.  In our builtin implementation, they
+ * also appear in the sampler field of an ir_tex instruction.
+ */
+
+class ir_sampler_replacement_visitor : public ir_hierarchical_visitor {
+public:
+   ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref)
+   {
+      this->sampler = sampler;
+      this->deref = deref;
+   }
+
+   virtual ~ir_sampler_replacement_visitor()
+   {
+   }
+
+   virtual ir_visitor_status visit_leave(ir_call *);
+   virtual ir_visitor_status visit_leave(ir_dereference_array *);
+   virtual ir_visitor_status visit_leave(ir_dereference_record *);
+   virtual ir_visitor_status visit_leave(ir_texture *);
+
+   void replace_deref(ir_dereference **deref);
+   void replace_rvalue(ir_rvalue **rvalue);
+
+   ir_variable *sampler;
+   ir_dereference *deref;
+};
+
+void
+ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref)
+{
+   ir_dereference_variable *deref_var = (*deref)->as_dereference_variable();
+   if (deref_var && deref_var->var == this->sampler) {
+      *deref = this->deref->clone(talloc_parent(*deref), NULL);
+   }
+}
+
+void
+ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue)
+{
+   if (!*rvalue)
+      return;
+
+   ir_dereference *deref = (*rvalue)->as_dereference();
+
+   if (!deref)
+      return;
+
+   replace_deref(&deref);
+   *rvalue = deref;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_texture *ir)
+{
+   replace_deref(&ir->sampler);
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir)
+{
+   replace_rvalue(&ir->array);
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir)
+{
+   replace_rvalue(&ir->record);
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_sampler_replacement_visitor::visit_leave(ir_call *ir)
+{
+   foreach_iter(exec_list_iterator, iter, *ir) {
+      ir_rvalue *param = (ir_rvalue *)iter.get();
+      ir_rvalue *new_param = param;
+      replace_rvalue(&new_param);
+
+      if (new_param != param) {
+        param->replace_with(new_param);
+      }
+   }
+   return visit_continue;
+}
+
+static void
+do_sampler_replacement(exec_list *instructions,
+                      ir_variable *sampler,
+                      ir_dereference *deref)
+{
+   ir_sampler_replacement_visitor v(sampler, deref);
+
+   visit_list_elements(&v, instructions);
+}
diff --git a/src/glsl/opt_if_simplification.cpp b/src/glsl/opt_if_simplification.cpp
new file mode 100644 (file)
index 0000000..021615e
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_if_simplification.cpp
+ *
+ * Moves constant branches of if statements out to the surrounding
+ * instruction stream.
+ */
+
+#include "ir.h"
+
+class ir_if_simplification_visitor : public ir_hierarchical_visitor {
+public:
+   ir_if_simplification_visitor()
+   {
+      this->made_progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_if *);
+
+   bool made_progress;
+};
+
+bool
+do_if_simplification(exec_list *instructions)
+{
+   ir_if_simplification_visitor v;
+
+   v.run(instructions);
+   return v.made_progress;
+}
+
+
+ir_visitor_status
+ir_if_simplification_visitor::visit_leave(ir_if *ir)
+{
+   /* FINISHME: Ideally there would be a way to note that the condition results
+    * FINISHME: in a constant before processing both of the other subtrees.
+    * FINISHME: This can probably be done with some flags, but it would take
+    * FINISHME: some work to get right.
+    */
+   ir_constant *condition_constant = ir->condition->constant_expression_value();
+   if (condition_constant) {
+      /* Move the contents of the one branch of the conditional
+       * that matters out.
+       */
+      if (condition_constant->value.b[0]) {
+        foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
+           ir_instruction *then_ir = (ir_instruction *)then_iter.get();
+           ir->insert_before(then_ir);
+        }
+      } else {
+        foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
+           ir_instruction *else_ir = (ir_instruction *)else_iter.get();
+           ir->insert_before(else_ir);
+        }
+      }
+      ir->remove();
+      this->made_progress = true;
+   }
+
+   return visit_continue;
+}
diff --git a/src/glsl/opt_noop_swizzle.cpp b/src/glsl/opt_noop_swizzle.cpp
new file mode 100644 (file)
index 0000000..0403dfa
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_noop_swizzle.cpp
+ *
+ * If a swizzle doesn't change the order or count of components, then
+ * remove the swizzle so that other optimization passes see the value
+ * behind it.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "ir_print_visitor.h"
+#include "glsl_types.h"
+
+class ir_noop_swizzle_visitor : public ir_rvalue_visitor {
+public:
+   ir_noop_swizzle_visitor()
+   {
+      this->progress = false;
+   }
+
+   void handle_rvalue(ir_rvalue **rvalue);
+   bool progress;
+};
+
+void
+ir_noop_swizzle_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+   if (!*rvalue)
+      return;
+
+   ir_swizzle *swiz = (*rvalue)->as_swizzle();
+   if (!swiz || swiz->type != swiz->val->type)
+      return;
+
+   int elems = swiz->val->type->vector_elements;
+   if (swiz->mask.x != 0)
+      return;
+   if (elems >= 2 && swiz->mask.y != 1)
+      return;
+   if (elems >= 3 && swiz->mask.z != 2)
+      return;
+   if (elems >= 4 && swiz->mask.w != 3)
+      return;
+
+   this->progress = true;
+   *rvalue = swiz->val;
+}
+
+bool
+do_noop_swizzle(exec_list *instructions)
+{
+   ir_noop_swizzle_visitor v;
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/opt_structure_splitting.cpp b/src/glsl/opt_structure_splitting.cpp
new file mode 100644 (file)
index 0000000..ff3ec93
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_structure_splitting.cpp
+ *
+ * If a structure is only ever referenced by its components, then
+ * split those components out to individual variables so they can be
+ * handled normally by other optimization passes.
+ *
+ * This skips structures like uniforms, which need to be accessible as
+ * structures for their access by the GL.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_print_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined
+// function) with the variable_entry class seen in ir_variable_refcount.h
+// Perhaps we can use the one in ir_variable_refcount.h and make this class
+// here go away?
+class variable_entry2 : public exec_node
+{
+public:
+   variable_entry2(ir_variable *var)
+   {
+      this->var = var;
+      this->whole_structure_access = 0;
+      this->declaration = false;
+      this->components = NULL;
+      this->mem_ctx = NULL;
+   }
+
+   ir_variable *var; /* The key: the variable's pointer. */
+
+   /** Number of times the variable is referenced, including assignments. */
+   unsigned whole_structure_access;
+
+   bool declaration; /* If the variable had a decl in the instruction stream */
+
+   ir_variable **components;
+
+   /** talloc_parent(this->var) -- the shader's talloc context. */
+   void *mem_ctx;
+};
+
+
+class ir_structure_reference_visitor : public ir_hierarchical_visitor {
+public:
+   ir_structure_reference_visitor(void)
+   {
+      this->mem_ctx = talloc_new(NULL);
+      this->variable_list.make_empty();
+   }
+
+   ~ir_structure_reference_visitor(void)
+   {
+      talloc_free(mem_ctx);
+   }
+
+   virtual ir_visitor_status visit(ir_variable *);
+   virtual ir_visitor_status visit(ir_dereference_variable *);
+   virtual ir_visitor_status visit_enter(ir_dereference_record *);
+   virtual ir_visitor_status visit_enter(ir_assignment *);
+   virtual ir_visitor_status visit_enter(ir_function_signature *);
+
+   variable_entry2 *get_variable_entry2(ir_variable *var);
+
+   /* List of variable_entry */
+   exec_list variable_list;
+
+   void *mem_ctx;
+};
+
+variable_entry2 *
+ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
+{
+   assert(var);
+
+   if (!var->type->is_record() || var->mode == ir_var_uniform)
+      return NULL;
+
+   foreach_iter(exec_list_iterator, iter, this->variable_list) {
+      variable_entry2 *entry = (variable_entry2 *)iter.get();
+      if (entry->var == var)
+        return entry;
+   }
+
+   variable_entry2 *entry = new(mem_ctx) variable_entry2(var);
+   this->variable_list.push_tail(entry);
+   return entry;
+}
+
+
+ir_visitor_status
+ir_structure_reference_visitor::visit(ir_variable *ir)
+{
+   variable_entry2 *entry = this->get_variable_entry2(ir);
+
+   if (entry)
+      entry->declaration = true;
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
+{
+   ir_variable *const var = ir->variable_referenced();
+   variable_entry2 *entry = this->get_variable_entry2(var);
+
+   if (entry)
+      entry->whole_structure_access++;
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
+{
+   (void) ir;
+   /* Don't descend into the ir_dereference_variable below. */
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
+{
+   if (ir->lhs->as_dereference_variable() &&
+       ir->rhs->as_dereference_variable() &&
+       !ir->condition) {
+      /* We'll split copies of a structure to copies of components, so don't
+       * descend to the ir_dereference_variables.
+       */
+      return visit_continue_with_parent;
+   }
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
+{
+   /* We don't want to descend into the function parameters and
+    * dead-code eliminate them, so just accept the body here.
+    */
+   visit_list_elements(this, &ir->body);
+   return visit_continue_with_parent;
+}
+
+class ir_structure_splitting_visitor : public ir_rvalue_visitor {
+public:
+   ir_structure_splitting_visitor(exec_list *vars)
+   {
+      this->variable_list = vars;
+   }
+
+   virtual ~ir_structure_splitting_visitor()
+   {
+   }
+
+   virtual ir_visitor_status visit_leave(ir_assignment *);
+
+   void split_deref(ir_dereference **deref);
+   void handle_rvalue(ir_rvalue **rvalue);
+   variable_entry2 *get_splitting_entry(ir_variable *var);
+
+   exec_list *variable_list;
+   void *mem_ctx;
+};
+
+variable_entry2 *
+ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
+{
+   assert(var);
+
+   if (!var->type->is_record())
+      return NULL;
+
+   foreach_iter(exec_list_iterator, iter, *this->variable_list) {
+      variable_entry2 *entry = (variable_entry2 *)iter.get();
+      if (entry->var == var) {
+        return entry;
+      }
+   }
+
+   return NULL;
+}
+
+void
+ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
+{
+   if ((*deref)->ir_type != ir_type_dereference_record)
+      return;
+
+   ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
+   ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
+   if (!deref_var)
+      return;
+
+   variable_entry2 *entry = get_splitting_entry(deref_var->var);
+   if (!entry)
+      return;
+
+   unsigned int i;
+   for (i = 0; i < entry->var->type->length; i++) {
+      if (strcmp(deref_record->field,
+                entry->var->type->fields.structure[i].name) == 0)
+        break;
+   }
+   assert(i != entry->var->type->length);
+
+   *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+}
+
+void
+ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+   if (!*rvalue)
+      return;
+
+   ir_dereference *deref = (*rvalue)->as_dereference();
+
+   if (!deref)
+      return;
+
+   split_deref(&deref);
+   *rvalue = deref;
+}
+
+ir_visitor_status
+ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
+{
+   ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
+   ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
+   variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
+   variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
+   const glsl_type *type = ir->rhs->type;
+
+   if ((lhs_entry || rhs_entry) && !ir->condition) {
+      for (unsigned int i = 0; i < type->length; i++) {
+        ir_dereference *new_lhs, *new_rhs;
+        void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
+
+        if (lhs_entry) {
+           new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
+        } else {
+           new_lhs = new(mem_ctx)
+              ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
+                                    type->fields.structure[i].name);
+        }
+
+        if (rhs_entry) {
+           new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
+        } else {
+           new_rhs = new(mem_ctx)
+              ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
+                                    type->fields.structure[i].name);
+        }
+
+        ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
+                                                     new_rhs,
+                                                     NULL));
+      }
+      ir->remove();
+   } else {
+      handle_rvalue(&ir->rhs);
+      split_deref(&ir->lhs);
+   }
+
+   handle_rvalue(&ir->condition);
+
+   return visit_continue;
+}
+
+bool
+do_structure_splitting(exec_list *instructions)
+{
+   ir_structure_reference_visitor refs;
+
+   visit_list_elements(&refs, instructions);
+
+   /* Trim out variables we can't split. */
+   foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+      variable_entry2 *entry = (variable_entry2 *)iter.get();
+
+      if (debug) {
+        printf("structure %s@%p: decl %d, whole_access %d\n",
+               entry->var->name, (void *) entry->var, entry->declaration,
+               entry->whole_structure_access);
+      }
+
+      if (!entry->declaration || entry->whole_structure_access) {
+        entry->remove();
+      }
+   }
+
+   if (refs.variable_list.is_empty())
+      return false;
+
+   void *mem_ctx = talloc_new(NULL);
+
+   /* Replace the decls of the structures to be split with their split
+    * components.
+    */
+   foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+      variable_entry2 *entry = (variable_entry2 *)iter.get();
+      const struct glsl_type *type = entry->var->type;
+
+      entry->mem_ctx = talloc_parent(entry->var);
+
+      entry->components = talloc_array(mem_ctx,
+                                      ir_variable *,
+                                      type->length);
+
+      for (unsigned int i = 0; i < entry->var->type->length; i++) {
+        const char *name = talloc_asprintf(mem_ctx, "%s_%s",
+                                           entry->var->name,
+                                           type->fields.structure[i].name);
+
+        entry->components[i] =
+           new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
+                                           name,
+                                           ir_var_temporary);
+        entry->var->insert_before(entry->components[i]);
+      }
+
+      entry->var->remove();
+   }
+
+   ir_structure_splitting_visitor split(&refs.variable_list);
+   visit_list_elements(&split, instructions);
+
+   talloc_free(mem_ctx);
+
+   return true;
+}
diff --git a/src/glsl/opt_swizzle_swizzle.cpp b/src/glsl/opt_swizzle_swizzle.cpp
new file mode 100644 (file)
index 0000000..0ffb4fa
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_swizzle_swizzle.cpp
+ *
+ * Eliminates the second swizzle in a swizzle chain.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+class ir_swizzle_swizzle_visitor : public ir_hierarchical_visitor {
+public:
+   ir_swizzle_swizzle_visitor()
+   {
+      progress = false;
+   }
+
+   virtual ir_visitor_status visit_enter(ir_swizzle *);
+
+   bool progress;
+};
+
+ir_visitor_status
+ir_swizzle_swizzle_visitor::visit_enter(ir_swizzle *ir)
+{
+   int mask2[4];
+
+   ir_swizzle *swiz2 = ir->val->as_swizzle();
+   if (!swiz2)
+      return visit_continue;
+
+   memset(&mask2, 0, sizeof(mask2));
+   if (swiz2->mask.num_components >= 1)
+      mask2[0] = swiz2->mask.x;
+   if (swiz2->mask.num_components >= 2)
+      mask2[1] = swiz2->mask.y;
+   if (swiz2->mask.num_components >= 3)
+      mask2[2] = swiz2->mask.z;
+   if (swiz2->mask.num_components >= 4)
+      mask2[3] = swiz2->mask.w;
+
+   if (ir->mask.num_components >= 1)
+      ir->mask.x = mask2[ir->mask.x];
+   if (ir->mask.num_components >= 2)
+      ir->mask.y = mask2[ir->mask.y];
+   if (ir->mask.num_components >= 3)
+      ir->mask.z = mask2[ir->mask.z];
+   if (ir->mask.num_components >= 4)
+      ir->mask.w = mask2[ir->mask.w];
+
+   ir->val = swiz2->val;
+
+   this->progress = true;
+
+   return visit_continue;
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_swizzle_swizzle(exec_list *instructions)
+{
+   ir_swizzle_swizzle_visitor v;
+
+   v.run(instructions);
+
+   return v.progress;
+}
diff --git a/src/glsl/opt_tree_grafting.cpp b/src/glsl/opt_tree_grafting.cpp
new file mode 100644 (file)
index 0000000..9b569b8
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_tree_grafting.cpp
+ *
+ * Takes assignments to variables that are dereferenced only once and
+ * pastes the RHS expression into where the variable is dereferenced.
+ *
+ * In the process of various operations like function inlining and
+ * tertiary op handling, we'll end up with our expression trees having
+ * been chopped up into a series of assignments of short expressions
+ * to temps.  Other passes like ir_algebraic.cpp would prefer to see
+ * the deepest expression trees they can to try to optimize them.
+ *
+ * This is a lot like copy propagaton.  In comparison, copy
+ * propagation only acts on plain copies, not arbitrary expressions on
+ * the RHS.  Generally, we wouldn't want to go pasting some
+ * complicated expression everywhere it got used, though, so we don't
+ * handle expressions in that pass.
+ *
+ * The hard part is making sure we don't move an expression across
+ * some other assignments that would change the value of the
+ * expression.  So we split this into two passes: First, find the
+ * variables in our scope which are written to once and read once, and
+ * then go through basic blocks seeing if we find an opportunity to
+ * move those expressions safely.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_variable_refcount.h"
+#include "ir_basic_block.h"
+#include "ir_optimization.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+class ir_tree_grafting_visitor : public ir_hierarchical_visitor {
+public:
+   ir_tree_grafting_visitor(ir_assignment *graft_assign,
+                           ir_variable *graft_var)
+   {
+      this->progress = false;
+      this->graft_assign = graft_assign;
+      this->graft_var = graft_var;
+   }
+
+   virtual ir_visitor_status visit_leave(class ir_assignment *);
+   virtual ir_visitor_status visit_enter(class ir_call *);
+   virtual ir_visitor_status visit_enter(class ir_expression *);
+   virtual ir_visitor_status visit_enter(class ir_function *);
+   virtual ir_visitor_status visit_enter(class ir_function_signature *);
+   virtual ir_visitor_status visit_enter(class ir_if *);
+   virtual ir_visitor_status visit_enter(class ir_loop *);
+   virtual ir_visitor_status visit_enter(class ir_swizzle *);
+   virtual ir_visitor_status visit_enter(class ir_texture *);
+
+   bool do_graft(ir_rvalue **rvalue);
+
+   bool progress;
+   ir_variable *graft_var;
+   ir_assignment *graft_assign;
+};
+
+struct find_deref_info {
+   ir_variable *var;
+   bool found;
+};
+
+void
+dereferences_variable_callback(ir_instruction *ir, void *data)
+{
+   struct find_deref_info *info = (struct find_deref_info *)data;
+   ir_dereference_variable *deref = ir->as_dereference_variable();
+
+   if (deref && deref->var == info->var)
+      info->found = true;
+}
+
+static bool
+dereferences_variable(ir_instruction *ir, ir_variable *var)
+{
+   struct find_deref_info info;
+
+   info.var = var;
+   info.found = false;
+
+   visit_tree(ir, dereferences_variable_callback, &info);
+
+   return info.found;
+}
+
+bool
+ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue)
+{
+   if (!*rvalue)
+      return false;
+
+   ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
+
+   if (!deref || deref->var != this->graft_var)
+      return false;
+
+   if (debug) {
+      printf("GRAFTING:\n");
+      this->graft_assign->print();
+      printf("\n");
+      printf("TO:\n");
+      (*rvalue)->print();
+      printf("\n");
+   }
+
+   this->graft_assign->remove();
+   *rvalue = this->graft_assign->rhs;
+
+   this->progress = true;
+   return true;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_loop *ir)
+{
+   (void)ir;
+   /* Do not traverse into the body of the loop since that is a
+    * different basic block.
+    */
+   return visit_stop;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_leave(ir_assignment *ir)
+{
+   if (do_graft(&ir->rhs) ||
+       do_graft(&ir->condition))
+      return visit_stop;
+
+   /* If this assignment updates a variable used in the assignment
+    * we're trying to graft, then we're done.
+    */
+   if (dereferences_variable(this->graft_assign->rhs,
+                            ir->lhs->variable_referenced())) {
+      if (debug) {
+        printf("graft killed by: ");
+        ir->print();
+        printf("\n");
+      }
+      return visit_stop;
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_function *ir)
+{
+   (void) ir;
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
+{
+   (void)ir;
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_call *ir)
+{
+   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
+   /* Reminder: iterating ir_call iterates its parameters. */
+   foreach_iter(exec_list_iterator, iter, *ir) {
+      ir_variable *sig_param = (ir_variable *)sig_iter.get();
+      ir_rvalue *ir = (ir_rvalue *)iter.get();
+      ir_rvalue *new_ir = ir;
+
+      if (sig_param->mode != ir_var_in)
+        continue;
+
+      if (do_graft(&new_ir)) {
+        ir->replace_with(new_ir);
+        return visit_stop;
+      }
+      sig_iter.next();
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_expression *ir)
+{
+   for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
+      if (do_graft(&ir->operands[i]))
+        return visit_stop;
+   }
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_if *ir)
+{
+   if (do_graft(&ir->condition))
+      return visit_stop;
+
+   /* Do not traverse into the body of the if-statement since that is a
+    * different basic block.
+    */
+   return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir)
+{
+   if (do_graft(&ir->val))
+      return visit_stop;
+
+   return visit_continue;
+}
+
+ir_visitor_status
+ir_tree_grafting_visitor::visit_enter(ir_texture *ir)
+{
+   if (do_graft(&ir->coordinate) ||
+       do_graft(&ir->projector) ||
+       do_graft(&ir->shadow_comparitor))
+        return visit_stop;
+
+   switch (ir->op) {
+   case ir_tex:
+      break;
+   case ir_txb:
+      if (do_graft(&ir->lod_info.bias))
+        return visit_stop;
+      break;
+   case ir_txf:
+   case ir_txl:
+      if (do_graft(&ir->lod_info.lod))
+        return visit_stop;
+      break;
+   case ir_txd:
+      if (do_graft(&ir->lod_info.grad.dPdx) ||
+         do_graft(&ir->lod_info.grad.dPdy))
+        return visit_stop;
+      break;
+   }
+
+   return visit_continue;
+}
+
+struct tree_grafting_info {
+   ir_variable_refcount_visitor *refs;
+   bool progress;
+};
+
+static bool
+try_tree_grafting(ir_assignment *start,
+                 ir_variable *lhs_var,
+                 ir_instruction *bb_last)
+{
+   ir_tree_grafting_visitor v(start, lhs_var);
+
+   if (debug) {
+      printf("trying to graft: ");
+      lhs_var->print();
+      printf("\n");
+   }
+
+   for (ir_instruction *ir = (ir_instruction *)start->next;
+       ir != bb_last->next;
+       ir = (ir_instruction *)ir->next) {
+
+      if (debug) {
+        printf("- ");
+        ir->print();
+        printf("\n");
+      }
+
+      ir_visitor_status s = ir->accept(&v);
+      if (s == visit_stop)
+        return v.progress;
+   }
+
+   return false;
+}
+
+static void
+tree_grafting_basic_block(ir_instruction *bb_first,
+                         ir_instruction *bb_last,
+                         void *data)
+{
+   struct tree_grafting_info *info = (struct tree_grafting_info *)data;
+   ir_instruction *ir, *next;
+
+   for (ir = bb_first, next = (ir_instruction *)ir->next;
+       ir != bb_last->next;
+       ir = next, next = (ir_instruction *)ir->next) {
+      ir_assignment *assign = ir->as_assignment();
+
+      if (!assign)
+        continue;
+
+      ir_variable *lhs_var = assign->whole_variable_written();
+      if (!lhs_var)
+        continue;
+
+      if (lhs_var->mode == ir_var_out ||
+         lhs_var->mode == ir_var_inout)
+        continue;
+
+      variable_entry *entry = info->refs->get_variable_entry(lhs_var);
+
+      if (!entry->declaration ||
+         entry->assigned_count != 1 ||
+         entry->referenced_count != 2)
+        continue;
+
+      assert(assign == entry->assign);
+
+      /* Found a possibly graftable assignment.  Now, walk through the
+       * rest of the BB seeing if the deref is here, and if nothing interfered with
+       * pasting its expression's values in between.
+       */
+      info->progress |= try_tree_grafting(assign, lhs_var, bb_last);
+   }
+}
+
+/**
+ * Does a copy propagation pass on the code present in the instruction stream.
+ */
+bool
+do_tree_grafting(exec_list *instructions)
+{
+   ir_variable_refcount_visitor refs;
+   struct tree_grafting_info info;
+
+   info.progress = false;
+   info.refs = &refs;
+
+   visit_list_elements(info.refs, instructions);
+
+   call_for_basic_blocks(instructions, tree_grafting_basic_block, &info);
+
+   return info.progress;
+}