示例#1
0
glsl_precision higher_precision (ir_instruction* a, ir_instruction* b)
{
	if (!a && !b)
		return glsl_precision_undefined;
	if (!a)
		return precision_from_ir (b);
	if (!b)
		return precision_from_ir (a);
	return higher_precision (precision_from_ir(a), precision_from_ir(b));
}
void
lower_instructions_visitor::mod_to_fract(ir_expression *ir)
{
   ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b",
					   ir_var_temporary, precision_from_ir(ir->operands[1]));
   this->base_ir->insert_before(temp);

   ir_assignment *const assign =
      new(ir) ir_assignment(new(ir) ir_dereference_variable(temp),
			    ir->operands[1], NULL);

   this->base_ir->insert_before(assign);

   ir_expression *const div_expr =
      new(ir) ir_expression(ir_binop_div, ir->operands[0]->type,
			    ir->operands[0],
			    new(ir) ir_dereference_variable(temp));

   /* Don't generate new IR that would need to be lowered in an additional
    * pass.
    */
   if (lowering(DIV_TO_MUL_RCP))
      div_to_mul_rcp(div_expr);

   ir_rvalue *expr = new(ir) ir_expression(ir_unop_fract,
					   ir->operands[0]->type,
					   div_expr,
					   NULL);

   ir->operation = ir_binop_mul;
   ir->operands[0] = new(ir) ir_dereference_variable(temp);
   ir->operands[1] = expr;
   this->progress = true;
}
示例#3
0
ir_expression::ir_expression(int op, const struct glsl_type *type,
			     ir_rvalue *op0)
: ir_rvalue(precision_from_ir(op0))
{
   assert(get_num_operands(ir_expression_operation(op)) == 1);
   this->ir_type = ir_type_expression;
   this->type = type;
   this->operation = ir_expression_operation(op);
   this->operands[0] = op0;
   this->operands[1] = NULL;
   this->operands[2] = NULL;
   this->operands[3] = NULL;
}
/**
 * Generate a comparison value for a block of indices
 *
 * Lowering passes for non-constant indexing of arrays, matrices, or vectors
 * can use this to generate blocks of index comparison values.
 *
 * \param instructions  List where new instructions will be appended
 * \param index         \c ir_variable containing the desired index
 * \param base          Base value for this block of comparisons
 * \param components    Number of unique index values to compare.  This must
 *                      be on the range [1, 4].
 * \param mem_ctx       ralloc memory context to be used for all allocations.
 *
 * \returns
 * An \c ir_rvalue that \b must be cloned for each use in conditional
 * assignments, etc.
 */
ir_rvalue *
compare_index_block(exec_list *instructions, ir_variable *index,
		    unsigned base, unsigned components, void *mem_ctx)
{
   ir_rvalue *broadcast_index = new(mem_ctx) ir_dereference_variable(index);

   assert(index->type->is_scalar());
   assert(index->type->base_type == GLSL_TYPE_INT);
   assert(components >= 1 && components <= 4);

   if (components > 1) {
      const ir_swizzle_mask m = { 0, 0, 0, 0, components, false };
      broadcast_index = new(mem_ctx) ir_swizzle(broadcast_index, m);
   }

   /* Compare the desired index value with the next block of four indices.
    */
   ir_constant_data test_indices_data;
   memset(&test_indices_data, 0, sizeof(test_indices_data));
   test_indices_data.i[0] = base;
   test_indices_data.i[1] = base + 1;
   test_indices_data.i[2] = base + 2;
   test_indices_data.i[3] = base + 3;

   ir_constant *const test_indices =
      new(mem_ctx) ir_constant(broadcast_index->type,
			       &test_indices_data);

   ir_rvalue *const condition_val =
      new(mem_ctx) ir_expression(ir_binop_equal,
				 &glsl_type::bool_type[components - 1],
				 broadcast_index,
				 test_indices);

   ir_variable *const condition =
      new(mem_ctx) ir_variable(condition_val->type,
			       "dereference_condition",
			       ir_var_temporary, precision_from_ir(condition_val));
   instructions->push_tail(condition);

   ir_rvalue *const cond_deref =
      new(mem_ctx) ir_dereference_variable(condition);
   instructions->push_tail(new(mem_ctx) ir_assignment(cond_deref, condition_val, 0));

   return cond_deref;
}
示例#5
0
ir_expression::ir_expression(int op, ir_rvalue *op0)
: ir_rvalue(precision_from_ir(op0))
{
   this->ir_type = ir_type_expression;

   this->operation = ir_expression_operation(op);
   this->operands[0] = op0;
   this->operands[1] = NULL;
   this->operands[2] = NULL;
   this->operands[3] = NULL;

   assert(op <= ir_last_unop);

   switch (this->operation) {
   case ir_unop_bit_not:
   case ir_unop_logic_not:
   case ir_unop_neg:
   case ir_unop_abs:
   case ir_unop_sign:
   case ir_unop_rcp:
   case ir_unop_rsq:
   case ir_unop_sqrt:
   case ir_unop_normalize:
   case ir_unop_exp:
   case ir_unop_log:
   case ir_unop_exp2:
   case ir_unop_log2:
   case ir_unop_trunc:
   case ir_unop_ceil:
   case ir_unop_floor:
   case ir_unop_fract:
   case ir_unop_round_even:
   case ir_unop_sin:
   case ir_unop_cos:
   case ir_unop_sin_reduced:
   case ir_unop_cos_reduced:
   case ir_unop_dFdx:
   case ir_unop_dFdy:
      this->type = op0->type;
      break;

   case ir_unop_f2i:
   case ir_unop_b2i:
   case ir_unop_u2i:
   case ir_unop_bitcast_f2i:
      this->type = glsl_type::get_instance(GLSL_TYPE_INT,
					   op0->type->vector_elements, 1);
      break;

   case ir_unop_b2f:
   case ir_unop_i2f:
   case ir_unop_u2f:
   case ir_unop_bitcast_i2f:
   case ir_unop_bitcast_u2f:
      this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
					   op0->type->vector_elements, 1);
      break;

   case ir_unop_f2b:
   case ir_unop_i2b:
      this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
					   op0->type->vector_elements, 1);
      break;

   case ir_unop_i2u:
   case ir_unop_f2u:
   case ir_unop_bitcast_f2u:
      this->type = glsl_type::get_instance(GLSL_TYPE_UINT,
					   op0->type->vector_elements, 1);
      break;

   case ir_unop_noise:
      this->type = glsl_type::float_type;
      break;

   case ir_unop_any:
      this->type = glsl_type::bool_type;
      break;

   default:
      assert(!"not reached: missing automatic type setup for ir_expression");
      this->type = op0->type;
      break;
   }
}
示例#6
0
void
lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_expression *expr = (*rvalue)->as_expression();
   if ((expr == NULL) || (expr->operation != ir_quadop_vector))
      return;

   if (this->dont_lower_swz && is_extended_swizzle(expr))
      return;

   /* FINISHME: Is this the right thing to use for the ralloc context?
    */
   void *const mem_ctx = expr;

   assert(expr->type->vector_elements == expr->get_num_operands());

   /* Generate a temporary with the same type as the ir_quadop_operation.
    */
   ir_variable *const temp =
      new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary, precision_from_ir(expr));

   this->base_ir->insert_before(temp);

   /* Counter of the number of components collected so far.
    */
   unsigned assigned;

   /* Write-mask in the destination that receives counted by 'assigned'.
    */
   unsigned write_mask;


   /* Generate upto four assignments to that variable.  Try to group component
    * assignments together:
    *
    * - All constant components can be assigned at once.
    * - All assigments of components from a single variable with the same
    *   unary operator can be assigned at once.
    */
   ir_constant_data d = { { 0 } };

   assigned = 0;
   write_mask = 0;
   for (unsigned i = 0; i < expr->type->vector_elements; i++) {
      const ir_constant *const c = expr->operands[i]->as_constant();

      if (c == NULL)
	 continue;

      switch (expr->type->base_type) {
      case GLSL_TYPE_UINT:  d.u[assigned] = c->value.u[0]; break;
      case GLSL_TYPE_INT:   d.i[assigned] = c->value.i[0]; break;
      case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break;
      case GLSL_TYPE_BOOL:  d.b[assigned] = c->value.b[0]; break;
      default:              assert(!"Should not get here."); break;
      }

      write_mask |= (1U << i);
      assigned++;
   }

   assert((write_mask == 0) == (assigned == 0));

   /* If there were constant values, generate an assignment.
    */
   if (assigned > 0) {
      ir_constant *const c =
	 new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type,
							  assigned, 1),
				  &d);
      ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
      ir_assignment *const assign =
	 new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask);

      this->base_ir->insert_before(assign);
   }

   /* FINISHME: This should try to coalesce assignments.
    */
   for (unsigned i = 0; i < expr->type->vector_elements; i++) {
      if (expr->operands[i]->ir_type == ir_type_constant)
	 continue;

      ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
      ir_assignment *const assign =
	 new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i));

      this->base_ir->insert_before(assign);
      assigned++;
   }

   assert(assigned == expr->type->vector_elements);

   *rvalue = new(mem_ctx) ir_dereference_variable(temp);
   this->progress = true;
}
   ir_variable *convert_dereference_array(ir_dereference_array *orig_deref,
					  ir_assignment* orig_assign,
					  ir_dereference *orig_base)
   {
      assert(is_array_or_matrix(orig_deref->array));

      const unsigned length = (orig_deref->array->type->is_array())
         ? orig_deref->array->type->length
         : orig_deref->array->type->matrix_columns;

      void *const mem_ctx = ralloc_parent(base_ir);

      /* Temporary storage for either the result of the dereference of
       * the array, or the RHS that's being assigned into the
       * dereference of the array.
       */
      ir_variable *var;

      if (orig_assign) {
	 var = new(mem_ctx) ir_variable(orig_assign->rhs->type,
					"dereference_array_value",
					ir_var_temporary, precision_from_ir(orig_deref));
	 base_ir->insert_before(var);

	 ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(var);
	 ir_assignment *assign = new(mem_ctx) ir_assignment(lhs,
							    orig_assign->rhs,
							    NULL);

         base_ir->insert_before(assign);
      } else {
	 var = new(mem_ctx) ir_variable(orig_deref->type,
					"dereference_array_value",
					ir_var_temporary, precision_from_ir(orig_deref));
	 base_ir->insert_before(var);
      }

      /* Store the index to a temporary to avoid reusing its tree. */
      ir_variable *index =
	 new(mem_ctx) ir_variable(orig_deref->array_index->type,
				  "dereference_array_index", ir_var_temporary, precision_from_ir(orig_deref->array_index));
      base_ir->insert_before(index);

      ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(index);
      ir_assignment *assign =
	 new(mem_ctx) ir_assignment(lhs, orig_deref->array_index, NULL);
      base_ir->insert_before(assign);

      orig_deref->array_index = lhs->clone(mem_ctx, NULL);

      assignment_generator ag;
      ag.rvalue = orig_base;
      ag.base_ir = base_ir;
      ag.old_index = index;
      ag.var = var;
      if (orig_assign) {
	 ag.is_write = true;
	 ag.write_mask = orig_assign->write_mask;
      } else {
	 ag.is_write = false;
      }

      switch_generator sg(ag, index, 4, 4);

      /* If the original assignment has a condition, respect that original
       * condition!  This is acomplished by wrapping the new conditional
       * assignments in an if-statement that uses the original condition.
       */
      if ((orig_assign != NULL) && (orig_assign->condition != NULL)) {
	 /* No need to clone the condition because the IR that it hangs on is
	  * going to be removed from the instruction sequence.
	  */
	 ir_if *if_stmt = new(mem_ctx) ir_if(orig_assign->condition);

	 sg.generate(0, length, &if_stmt->then_instructions);
	 base_ir->insert_before(if_stmt);
      } else {
	 exec_list list;

	 sg.generate(0, length, &list);
	 base_ir->insert_before(&list);
      }

      return var;
   }
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;
   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 = ralloc_parent(ir);

   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

   exec_list list;

   /* Store the index to a temporary to avoid reusing its tree. */
   index = new(base_ir) ir_variable(glsl_type::int_type,
				    "vec_index_tmp_i",
				    ir_var_temporary, glsl_precision_undefined);
	list.push_tail(index);
   deref = new(base_ir) ir_dereference_variable(index);
   assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
   list.push_tail(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, precision_from_ir(ir));
	list.push_tail(var);

   /* Generate a single comparison condition "mask" for all of the components
    * in the vector.
    */
   ir_rvalue *const cond_deref =
      compare_index_block(&list, index, 0,
			  orig_deref->array->type->vector_elements,
			  mem_ctx);

   /* Generate a conditional move of each vector element to the temp. */
   for (i = 0; i < (int)orig_deref->array->type->vector_elements; i++) {
      ir_rvalue *condition_swizzle =
	 new(base_ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);

      /* Just clone the rest of the deref chain when trying to get at the
       * underlying variable.
       */
      ir_rvalue *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_swizzle);
      list.push_tail(assign);
   }

   /* Put all of the new instructions in the IR stream before the old
    * instruction.
    */
   base_ir->insert_before(&list);

   this->progress = true;
   return new(base_ir) ir_dereference_variable(var);
}
ir_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 = ralloc_parent(ir);

   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

   exec_list list;

   /* Store the index to a temporary to avoid reusing its tree. */
   index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
			       ir_var_temporary, glsl_precision_undefined);
	list.push_tail(index);
   deref = new(ir) ir_dereference_variable(index);
   assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
   list.push_tail(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, precision_from_ir(ir->rhs));
	list.push_tail(var);
   deref = new(ir) ir_dereference_variable(var);
   assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
   list.push_tail(assign);

   /* Generate a single comparison condition "mask" for all of the components
    * in the vector.
    */
   ir_rvalue *const cond_deref =
      compare_index_block(&list, index, 0,
			  orig_deref->array->type->vector_elements,
			  mem_ctx);

   /* Generate a conditional move of each vector element to the temp. */
   for (i = 0; i < (int)orig_deref->array->type->vector_elements; i++) {
      ir_rvalue *condition_swizzle =
	 new(ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);


      /* Just clone the rest of the deref chain when trying to get at the
       * underlying variable.
       */
      ir_rvalue *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_swizzle);
      list.push_tail(assign);
   }

   /* If the original assignment has a condition, respect that original
    * condition!  This is acomplished by wrapping the new conditional
    * assignments in an if-statement that uses the original condition.
    */
   if (ir->condition != NULL) {
      /* No need to clone the condition because the IR that it hangs on is
       * going to be removed from the instruction sequence.
       */
      ir_if *if_stmt = new(mem_ctx) ir_if(ir->condition);

      list.move_nodes_to(&if_stmt->then_instructions);
      ir->insert_before(if_stmt);
   } else {
      ir->insert_before(&list);
   }

   ir->remove();

   this->progress = true;

   return visit_continue;
}