diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/glsl/ir.cpp | 113 | ||||
| -rw-r--r-- | src/glsl/ir.h | 44 | ||||
| -rw-r--r-- | src/glsl/ir_clone.cpp | 3 | ||||
| -rw-r--r-- | src/glsl/ir_constant_variable.cpp | 2 | ||||
| -rw-r--r-- | src/glsl/ir_copy_propagation.cpp | 2 | ||||
| -rw-r--r-- | src/glsl/ir_dead_code_local.cpp | 2 | ||||
| -rw-r--r-- | src/glsl/ir_print_visitor.cpp | 14 | ||||
| -rw-r--r-- | src/glsl/ir_tree_grafting.cpp | 2 | ||||
| -rw-r--r-- | src/glsl/ir_vec_index_to_swizzle.cpp | 2 | ||||
| -rw-r--r-- | src/mesa/program/ir_to_mesa.cpp | 67 | 
10 files changed, 199 insertions, 52 deletions
| diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 79cbaa9ea0..c3bade8d54 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -22,6 +22,7 @@   */  #include <string.h>  #include "main/imports.h" +#include "main/macros.h"  #include "ir.h"  #include "ir_visitor.h"  #include "glsl_types.h" @@ -31,13 +32,121 @@ ir_rvalue::ir_rvalue()     this->type = glsl_type::error_type;  } +/** + * Modify the swizzle make to move one component to another + * + * \param m    IR swizzle to be modified + * \param from Component in the RHS that is to be swizzled + * \param to   Desired swizzle location of \c from + */ +static void +update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to) +{ +   switch (to) { +   case 0: m.x = from; break; +   case 1: m.y = from; break; +   case 2: m.z = from; break; +   case 3: m.w = from; break; +   default: assert(!"Should not get here."); +   } + +   m.num_components = MAX2(m.num_components, (to + 1)); +} + +void +ir_assignment::set_lhs(ir_rvalue *lhs) +{ +   while (lhs != NULL) { +      ir_swizzle *swiz = lhs->as_swizzle(); + +      if (swiz == NULL) +	 break; + +      unsigned write_mask = 0; +      ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 }; + +      for (unsigned i = 0; i < swiz->mask.num_components; i++) { +	 unsigned c = 0; + +	 switch (i) { +	 case 0: c = swiz->mask.x; break; +	 case 1: c = swiz->mask.y; break; +	 case 2: c = swiz->mask.z; break; +	 case 3: c = swiz->mask.w; break; +	 default: assert(!"Should not get here."); +	 } + +	 write_mask |= (((this->write_mask >> i) & 1) << c); +	 update_rhs_swizzle(rhs_swiz, i, c); +      } + +      this->write_mask = write_mask; +      lhs = swiz->val; + +      this->rhs = new(this) ir_swizzle(this->rhs, rhs_swiz); +   } + +   assert((lhs == NULL) || lhs->as_dereference()); + +   this->lhs = (ir_dereference *) lhs; +} + +ir_variable * +ir_assignment::whole_variable_written() +{ +   ir_variable *v = this->lhs->whole_variable_referenced(); + +   if (v == NULL) +      return NULL; + +   if (v->type->is_scalar()) +      return v; + +   if (v->type->is_vector()) { +      const unsigned mask = (1U << v->type->vector_elements) - 1; + +      if (mask != this->write_mask) +	 return NULL; +   } + +   /* Either all the vector components are assigned or the variable is some +    * composite type (and the whole thing is assigned. +    */ +   return v; +} + +ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, +			     ir_rvalue *condition, unsigned write_mask) +{ +   this->ir_type = ir_type_assignment; +   this->condition = condition; +   this->rhs = rhs; +   this->lhs = lhs; +   this->write_mask = write_mask; +} +  ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,  			     ir_rvalue *condition)  {     this->ir_type = ir_type_assignment; -   this->lhs = lhs; -   this->rhs = rhs;     this->condition = condition; +   this->rhs = rhs; + +   /* If the RHS is a vector type, assume that all components of the vector +    * type are being written to the LHS.  The write mask comes from the RHS +    * because we can have a case where the LHS is a vec4 and the RHS is a +    * vec3.  In that case, the assignment is: +    * +    *     (assign (...) (xyz) (var_ref lhs) (var_ref rhs)) +    */ +   if (rhs->type->is_vector()) +      this->write_mask = (1U << rhs->type->vector_elements) - 1; +   else if (rhs->type->is_scalar()) +      this->write_mask = 1; +   else +      this->write_mask = 0; + +   this->set_lhs(lhs);  } diff --git a/src/glsl/ir.h b/src/glsl/ir.h index f964b36083..98789503e0 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -514,6 +514,16 @@ class ir_assignment : public ir_instruction {  public:     ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, ir_rvalue *condition); +   /** +    * Construct an assignment with an explicit write mask +    * +    * \note +    * Since a write mask is supplied, the LHS must already be a bare +    * \c ir_dereference.  The cannot be any swizzles in the LHS. +    */ +   ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, ir_rvalue *condition, +		 unsigned write_mask); +     virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const;     virtual ir_constant *constant_expression_value(); @@ -531,9 +541,31 @@ public:     }     /** +    * Get a whole variable written by an assignment +    * +    * If the LHS of the assignment writes a whole variable, the variable is +    * returned.  Otherwise \c NULL is returned.  Examples of whole-variable +    * assignment are: +    * +    *  - Assigning to a scalar +    *  - Assigning to all components of a vector +    *  - Whole array (or matrix) assignment +    *  - Whole structure assignment +    */ +   ir_variable *whole_variable_written(); + +   /** +    * Set the LHS of an assignment +    */ +   void set_lhs(ir_rvalue *lhs); + +   /**      * Left-hand side of the assignment. +    * +    * This should be treated as read only.  If you need to set the LHS of an +    * assignment, use \c ir_assignment::set_lhs.      */ -   ir_rvalue *lhs; +   ir_dereference *lhs;     /**      * Value being assigned @@ -544,6 +576,16 @@ public:      * Optional condition for the assignment.      */     ir_rvalue *condition; + + +   /** +    * Component mask written +    * +    * For non-vector types in the LHS, this field will be zero.  For vector +    * types, a bit will be set for each component that is written.  Note that +    * for \c vec2 and \c vec3 types only the lower bits will ever be set. +    */ +   unsigned write_mask:4;  };  /* Update ir_expression::num_operands() and operator_strs when diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index 59831834bd..0e202164b3 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -242,7 +242,8 @@ ir_assignment::clone(void *mem_ctx, struct hash_table *ht) const     return new(mem_ctx) ir_assignment(this->lhs->clone(mem_ctx, ht),  				     this->rhs->clone(mem_ctx, ht), -				     new_condition); +				     new_condition, +				     this->write_mask);  }  ir_function * diff --git a/src/glsl/ir_constant_variable.cpp b/src/glsl/ir_constant_variable.cpp index 749e2cf809..1fb73e765e 100644 --- a/src/glsl/ir_constant_variable.cpp +++ b/src/glsl/ir_constant_variable.cpp @@ -110,7 +110,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)  	 return visit_continue;     } -   ir_variable *var = ir->lhs->whole_variable_referenced(); +   ir_variable *var = ir->whole_variable_written();     if (!var)        return visit_continue; diff --git a/src/glsl/ir_copy_propagation.cpp b/src/glsl/ir_copy_propagation.cpp index 5712398732..26588a352c 100644 --- a/src/glsl/ir_copy_propagation.cpp +++ b/src/glsl/ir_copy_propagation.cpp @@ -224,7 +224,7 @@ add_copy(void *ctx, ir_assignment *ir, exec_list *acp)  	 return;     } -   ir_variable *lhs_var = ir->lhs->whole_variable_referenced(); +   ir_variable *lhs_var = ir->whole_variable_written();     ir_variable *rhs_var = ir->rhs->whole_variable_referenced();     if ((lhs_var != NULL) && (rhs_var != NULL)) { diff --git a/src/glsl/ir_dead_code_local.cpp b/src/glsl/ir_dead_code_local.cpp index 7a44ec8a4a..b22cc558df 100644 --- a/src/glsl/ir_dead_code_local.cpp +++ b/src/glsl/ir_dead_code_local.cpp @@ -137,7 +137,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)     }     /* Now, check if we did a whole-variable assignment. */ -   if (always_assign && (ir->lhs->whole_variable_referenced() != NULL)) { +   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.         */ diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp index 73476e7e9b..39b11bb32c 100644 --- a/src/glsl/ir_print_visitor.cpp +++ b/src/glsl/ir_print_visitor.cpp @@ -296,7 +296,19 @@ void ir_print_visitor::visit(ir_assignment *ir)     else        printf("(constant bool (1))"); -   printf(" "); + +   char mask[5]; +   unsigned j = 0; + +   for (unsigned i = 0; i < 4; i++) { +      if ((ir->write_mask & (1 << i)) != 0) { +	 mask[j] = "xyzw"[i]; +	 j++; +      } +   } +   mask[j] = '\0'; + +   printf(" (%s) ", mask);     ir->lhs->accept(this); diff --git a/src/glsl/ir_tree_grafting.cpp b/src/glsl/ir_tree_grafting.cpp index 6f62de758b..38034a6197 100644 --- a/src/glsl/ir_tree_grafting.cpp +++ b/src/glsl/ir_tree_grafting.cpp @@ -315,7 +315,7 @@ tree_grafting_basic_block(ir_instruction *bb_first,        if (!assign)  	 continue; -      ir_variable *lhs_var = assign->lhs->whole_variable_referenced(); +      ir_variable *lhs_var = assign->whole_variable_written();        if (!lhs_var)  	 continue; diff --git a/src/glsl/ir_vec_index_to_swizzle.cpp b/src/glsl/ir_vec_index_to_swizzle.cpp index 1e170cbae6..b3de91f8ab 100644 --- a/src/glsl/ir_vec_index_to_swizzle.cpp +++ b/src/glsl/ir_vec_index_to_swizzle.cpp @@ -107,7 +107,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)  ir_visitor_status  ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)  { -   ir->lhs = convert_vec_index_to_swizzle(ir->lhs); +   ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));     ir->rhs = convert_vec_index_to_swizzle(ir->rhs);     return visit_continue; diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 777b4d91f4..1cec4aa621 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -356,6 +356,7 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,  					ir_to_mesa_dst_reg dst,  					ir_to_mesa_src_reg src0)  { +   assert(dst.writemask != 0);     return ir_to_mesa_emit_op3(ir, op, dst,  			      src0, ir_to_mesa_undef, ir_to_mesa_undef);  } @@ -1615,21 +1616,17 @@ ir_to_mesa_visitor::visit(ir_dereference_record *ir)   * We want to be careful in assignment setup to hit the actual storage   * instead of potentially using a temporary like we might with the   * ir_dereference handler. - * - * Thanks to ir_swizzle_swizzle, and ir_vec_index_to_swizzle, we - * should only see potentially one variable array index of a vector, - * and one swizzle, before getting to actual vec4 storage.  So handle - * those, then go use ir_dereference to handle the rest.   */  static struct ir_to_mesa_dst_reg -get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v, +get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v,  		   ir_to_mesa_src_reg *r)  { -   struct ir_to_mesa_dst_reg dst_reg; -   ir_swizzle *swiz; - +   /* The LHS must be a dereference.  If the LHS is a variable indexed array +    * access of a vector, it must be separated into a series conditional moves +    * before reaching this point (see ir_vec_index_to_cond_assign). +    */ +   assert(ir->as_dereference());     ir_dereference_array *deref_array = ir->as_dereference_array(); -   /* This should have been handled by ir_vec_index_to_cond_assign */     if (deref_array) {        assert(!deref_array->array->type->is_vector());     } @@ -1638,38 +1635,7 @@ get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v,      * swizzles in it and write swizzles using writemask, though.      */     ir->accept(v); -   dst_reg = ir_to_mesa_dst_reg_from_src(v->result); - -   if ((swiz = ir->as_swizzle())) { -      int swizzles[4] = { -	 swiz->mask.x, -	 swiz->mask.y, -	 swiz->mask.z, -	 swiz->mask.w -      }; -      int new_r_swizzle[4]; -      int orig_r_swizzle = r->swizzle; -      int i; - -      for (i = 0; i < 4; i++) { -	 new_r_swizzle[i] = GET_SWZ(orig_r_swizzle, 0); -      } - -      dst_reg.writemask = 0; -      for (i = 0; i < 4; i++) { -	 if (i < swiz->mask.num_components) { -	    dst_reg.writemask |= 1 << swizzles[i]; -	    new_r_swizzle[swizzles[i]] = GET_SWZ(orig_r_swizzle, i); -	 } -      } - -      r->swizzle = MAKE_SWIZZLE4(new_r_swizzle[0], -				 new_r_swizzle[1], -				 new_r_swizzle[2], -				 new_r_swizzle[3]); -   } - -   return dst_reg; +   return ir_to_mesa_dst_reg_from_src(v->result);  }  void @@ -1684,6 +1650,23 @@ ir_to_mesa_visitor::visit(ir_assignment *ir)     l = get_assignment_lhs(ir->lhs, this, &r); +   /* FINISHME: This should really set to the correct maximal writemask for each +    * FINISHME: component written (in the loops below).  This case can only +    * FINISHME: occur for matrices, arrays, and structures. +    */ +   if (ir->write_mask == 0) { +      assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector()); +      l.writemask = WRITEMASK_XYZW; +   } else if (ir->lhs->type->is_scalar()) { +      /* FINISHME: This hack makes writing to gl_FragData, which lives in the +       * FINISHME: W component of fragment shader output zero, work correctly. +       */ +      l.writemask = WRITEMASK_XYZW; +   } else { +      assert(ir->lhs->type->is_vector()); +      l.writemask = ir->write_mask; +   } +     assert(l.file != PROGRAM_UNDEFINED);     assert(r.file != PROGRAM_UNDEFINED); | 
