Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright © 2010 Intel Corporation
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21.  * DEALINGS IN THE SOFTWARE.
  22.  */
  23.  
  24. /**
  25.  * \file lower_vec_index_to_cond_assign.cpp
  26.  *
  27.  * Turns indexing into vector types to a series of conditional moves
  28.  * of each channel's swizzle into a temporary.
  29.  *
  30.  * Most GPUs don't have a native way to do this operation, and this
  31.  * works around that.  For drivers using both this pass and
  32.  * ir_vec_index_to_swizzle, there's a risk that this pass will happen
  33.  * before sufficient constant folding to find that the array index is
  34.  * constant.  However, we hope that other optimization passes,
  35.  * particularly constant folding of assignment conditions and copy
  36.  * propagation, will result in the same code in the end.
  37.  */
  38.  
  39. #include "ir.h"
  40. #include "ir_visitor.h"
  41. #include "ir_optimization.h"
  42. #include "glsl_types.h"
  43.  
  44. /**
  45.  * Visitor class for replacing expressions with ir_constant values.
  46.  */
  47.  
  48. class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
  49. public:
  50.    ir_vec_index_to_cond_assign_visitor()
  51.    {
  52.       progress = false;
  53.    }
  54.  
  55.    ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
  56.  
  57.    virtual ir_visitor_status visit_enter(ir_expression *);
  58.    virtual ir_visitor_status visit_enter(ir_swizzle *);
  59.    virtual ir_visitor_status visit_leave(ir_assignment *);
  60.    virtual ir_visitor_status visit_enter(ir_return *);
  61.    virtual ir_visitor_status visit_enter(ir_call *);
  62.    virtual ir_visitor_status visit_enter(ir_if *);
  63.  
  64.    bool progress;
  65. };
  66.  
  67. ir_rvalue *
  68. ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
  69. {
  70.    ir_dereference_array *orig_deref = ir->as_dereference_array();
  71.    ir_assignment *assign;
  72.    ir_variable *index, *var;
  73.    ir_dereference *deref;
  74.    ir_expression *condition;
  75.    ir_swizzle *swizzle;
  76.    int i;
  77.  
  78.    if (!orig_deref)
  79.       return ir;
  80.  
  81.    if (orig_deref->array->type->is_matrix() ||
  82.        orig_deref->array->type->is_array())
  83.       return ir;
  84.  
  85.    void *mem_ctx = ralloc_parent(ir);
  86.  
  87.    assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
  88.  
  89.    /* Store the index to a temporary to avoid reusing its tree. */
  90.    index = new(base_ir) ir_variable(glsl_type::int_type,
  91.                                     "vec_index_tmp_i",
  92.                                     ir_var_temporary);
  93.    base_ir->insert_before(index);
  94.    deref = new(base_ir) ir_dereference_variable(index);
  95.    assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
  96.    base_ir->insert_before(assign);
  97.  
  98.    /* Temporary where we store whichever value we swizzle out. */
  99.    var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
  100.                                   ir_var_temporary);
  101.    base_ir->insert_before(var);
  102.  
  103.    /* Generate a conditional move of each vector element to the temp. */
  104.    for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
  105.       deref = new(base_ir) ir_dereference_variable(index);
  106.       condition = new(base_ir) ir_expression(ir_binop_equal,
  107.                                              glsl_type::bool_type,
  108.                                              deref,
  109.                                              new(base_ir) ir_constant(i));
  110.  
  111.       /* Just clone the rest of the deref chain when trying to get at the
  112.        * underlying variable.
  113.        */
  114.       swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
  115.                                         i, 0, 0, 0, 1);
  116.  
  117.       deref = new(base_ir) ir_dereference_variable(var);
  118.       assign = new(base_ir) ir_assignment(deref, swizzle, condition);
  119.       base_ir->insert_before(assign);
  120.    }
  121.  
  122.    this->progress = true;
  123.    return new(base_ir) ir_dereference_variable(var);
  124. }
  125.  
  126. ir_visitor_status
  127. ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
  128. {
  129.    unsigned int i;
  130.  
  131.    for (i = 0; i < ir->get_num_operands(); i++) {
  132.       ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
  133.    }
  134.  
  135.    return visit_continue;
  136. }
  137.  
  138. ir_visitor_status
  139. ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
  140. {
  141.    /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
  142.     * the result of indexing a vector is.  But maybe at some point we'll end up
  143.     * using swizzling of scalars for vector construction.
  144.     */
  145.    ir->val = convert_vec_index_to_cond_assign(ir->val);
  146.  
  147.    return visit_continue;
  148. }
  149.  
  150. ir_visitor_status
  151. ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
  152. {
  153.    ir_variable *index, *var;
  154.    ir_dereference_variable *deref;
  155.    ir_assignment *assign;
  156.    int i;
  157.  
  158.    ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
  159.    if (ir->condition)
  160.       ir->condition = convert_vec_index_to_cond_assign(ir->condition);
  161.  
  162.    /* Last, handle the LHS */
  163.    ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
  164.  
  165.    if (!orig_deref ||
  166.        orig_deref->array->type->is_matrix() ||
  167.        orig_deref->array->type->is_array())
  168.       return visit_continue;
  169.  
  170.    void *mem_ctx = ralloc_parent(ir);
  171.  
  172.    assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
  173.  
  174.    /* Store the index to a temporary to avoid reusing its tree. */
  175.    index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
  176.                                ir_var_temporary);
  177.    ir->insert_before(index);
  178.    deref = new(ir) ir_dereference_variable(index);
  179.    assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
  180.    ir->insert_before(assign);
  181.  
  182.    /* Store the RHS to a temporary to avoid reusing its tree. */
  183.    var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
  184.                              ir_var_temporary);
  185.    ir->insert_before(var);
  186.    deref = new(ir) ir_dereference_variable(var);
  187.    assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
  188.    ir->insert_before(assign);
  189.  
  190.    /* Generate a conditional move of each vector element to the temp. */
  191.    for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
  192.       ir_rvalue *condition, *swizzle;
  193.  
  194.       deref = new(ir) ir_dereference_variable(index);
  195.       condition = new(ir) ir_expression(ir_binop_equal,
  196.                                         glsl_type::bool_type,
  197.                                         deref,
  198.                                         new(ir) ir_constant(i));
  199.  
  200.       /* Just clone the rest of the deref chain when trying to get at the
  201.        * underlying variable.
  202.        */
  203.       swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
  204.                                    i, 0, 0, 0, 1);
  205.  
  206.       deref = new(ir) ir_dereference_variable(var);
  207.       assign = new(ir) ir_assignment(swizzle, deref, condition);
  208.       ir->insert_before(assign);
  209.    }
  210.    ir->remove();
  211.  
  212.    this->progress = true;
  213.  
  214.    return visit_continue;
  215. }
  216.  
  217. ir_visitor_status
  218. ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
  219. {
  220.    foreach_iter(exec_list_iterator, iter, *ir) {
  221.       ir_rvalue *param = (ir_rvalue *)iter.get();
  222.       ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);
  223.  
  224.       if (new_param != param) {
  225.          param->replace_with(new_param);
  226.       }
  227.    }
  228.  
  229.    return visit_continue;
  230. }
  231.  
  232. ir_visitor_status
  233. ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
  234. {
  235.    if (ir->value) {
  236.       ir->value = convert_vec_index_to_cond_assign(ir->value);
  237.    }
  238.  
  239.    return visit_continue;
  240. }
  241.  
  242. ir_visitor_status
  243. ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
  244. {
  245.    ir->condition = convert_vec_index_to_cond_assign(ir->condition);
  246.  
  247.    return visit_continue;
  248. }
  249.  
  250. bool
  251. do_vec_index_to_cond_assign(exec_list *instructions)
  252. {
  253.    ir_vec_index_to_cond_assign_visitor v;
  254.  
  255.    visit_list_elements(&v, instructions);
  256.  
  257.    return v.progress;
  258. }
  259.