Example #1
0
/**
 * If a 1D gl_ClipDistance variable appears as an argument in an ir_call
 * expression, replace it with a temporary variable, and make sure the ir_call
 * is preceded and/or followed by assignments that copy the contents of the
 * temporary variable to and/or from gl_ClipDistance.  Each of these
 * assignments is then lowered to refer to gl_ClipDistanceMESA.
 *
 * We need to do a similar replacement for 2D gl_ClipDistance, however since
 * it's an input, the only case we need to address is where a 1D slice of it
 * is passed as an "in" parameter to an ir_call, e.g.:
 *
 *     foo(gl_in[i].gl_ClipDistance)
 */
ir_visitor_status
lower_clip_distance_visitor::visit_leave(ir_call *ir)
{
   void *ctx = ralloc_parent(ir);

   const exec_node *formal_param_node = ir->callee->parameters.head;
   const exec_node *actual_param_node = ir->actual_parameters.head;
   while (!actual_param_node->is_tail_sentinel()) {
      ir_variable *formal_param = (ir_variable *) formal_param_node;
      ir_rvalue *actual_param = (ir_rvalue *) actual_param_node;

      /* Advance formal_param_node and actual_param_node now so that we can
       * safely replace actual_param with another node, if necessary, below.
       */
      formal_param_node = formal_param_node->next;
      actual_param_node = actual_param_node->next;

      if (this->is_clip_distance_vec8(actual_param)) {
         /* User is trying to pass the whole 1D gl_ClipDistance array (or a 1D
          * slice of a 2D gl_ClipDistance array) to a function call.  Since we
          * are reshaping gl_ClipDistance from an array of floats to an array
          * of vec4's, this isn't going to work anymore, so use a temporary
          * array instead.
          */
         ir_variable *temp_clip_distance = new(ctx) ir_variable(
            actual_param->type, "temp_clip_distance", ir_var_temporary, actual_param->get_precision());
         this->base_ir->insert_before(temp_clip_distance);
         actual_param->replace_with(
            new(ctx) ir_dereference_variable(temp_clip_distance));
         if (formal_param->data.mode == ir_var_function_in
             || formal_param->data.mode == ir_var_function_inout) {
            /* Copy from gl_ClipDistance to the temporary before the call.
             * Since we are going to insert this copy before the current
             * instruction, we need to visit it afterwards to make sure it
             * gets lowered.
             */
            ir_assignment *new_assignment = new(ctx) ir_assignment(
               new(ctx) ir_dereference_variable(temp_clip_distance),
               actual_param->clone(ctx, NULL));
            this->base_ir->insert_before(new_assignment);
            this->visit_new_assignment(new_assignment);
         }
         if (formal_param->data.mode == ir_var_function_out
             || formal_param->data.mode == ir_var_function_inout) {
            /* Copy from the temporary to gl_ClipDistance after the call.
             * Since visit_list_elements() has already decided which
             * instruction it's going to visit next, we need to visit
             * afterwards to make sure it gets lowered.
             */
            ir_assignment *new_assignment = new(ctx) ir_assignment(
               actual_param->clone(ctx, NULL),
               new(ctx) ir_dereference_variable(temp_clip_distance));
            this->base_ir->insert_after(new_assignment);
            this->visit_new_assignment(new_assignment);
         }
      }
   }

   return rvalue_visit(ir);
}
/**
 * Replace any assignment having gl_ClipDistance (undereferenced) as its LHS
 * or RHS with a sequence of assignments, one for each component of the array.
 * Each of these assignments is lowered to refer to gl_ClipDistanceMESA as
 * appropriate.
 */
ir_visitor_status
lower_clip_distance_visitor::visit_leave(ir_assignment *ir)
{
   ir_dereference_variable *lhs_var = ir->lhs->as_dereference_variable();
   ir_dereference_variable *rhs_var = ir->rhs->as_dereference_variable();
   if ((lhs_var && lhs_var->var == this->old_clip_distance_var)
       || (rhs_var && rhs_var->var == this->old_clip_distance_var)) {
      /* LHS or RHS of the assignment is the entire gl_ClipDistance array.
       * Since we are reshaping gl_ClipDistance from an array of floats to an
       * array of vec4's, this isn't going to work as a bulk assignment
       * anymore, so unroll it to element-by-element assignments and lower
       * each of them.
       *
       * Note: to unroll into element-by-element assignments, we need to make
       * clones of the LHS and RHS.  This is safe because expressions and
       * l-values are side-effect free.
       */
      void *ctx = ralloc_parent(ir);
      int array_size = this->old_clip_distance_var->type->array_size();
      for (int i = 0; i < array_size; ++i) {
         ir_dereference_array *new_lhs = new(ctx) ir_dereference_array(
            ir->lhs->clone(ctx, NULL), new(ctx) ir_constant(i));
         ir_dereference_array *new_rhs = new(ctx) ir_dereference_array(
            ir->rhs->clone(ctx, NULL), new(ctx) ir_constant(i));
         this->handle_rvalue((ir_rvalue **) &new_rhs);

         /* Handle the LHS after creating the new assignment.  This must
          * happen in this order because handle_rvalue may replace the old LHS
          * with an ir_expression of ir_binop_vector_extract.  Since this is
          * not a valide l-value, this will cause an assertion in the
          * ir_assignment constructor to fail.
          *
          * If this occurs, replace the mangled LHS with a dereference of the
          * vector, and replace the RHS with an ir_triop_vector_insert.
          */
         ir_assignment *const assign = new(ctx) ir_assignment(new_lhs, new_rhs);
         this->handle_rvalue((ir_rvalue **) &assign->lhs);
         this->fix_lhs(assign);

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

      return visit_continue;
   }

   /* Handle the LHS as if it were an r-value.  Normally
    * rvalue_visit(ir_assignment *) only visits the RHS, but we need to lower
    * expressions in the LHS as well.
    *
    * This may cause the LHS to get replaced with an ir_expression of
    * ir_binop_vector_extract.  If this occurs, replace it with a dereference
    * of the vector, and replace the RHS with an ir_triop_vector_insert.
    */
   handle_rvalue((ir_rvalue **)&ir->lhs);
   this->fix_lhs(ir);

   return rvalue_visit(ir);
}