Home | History | Annotate | Download | only in glsl
      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 "compiler/glsl_types.h"
     43 
     44 namespace {
     45 
     46 /**
     47  * Visitor class for replacing expressions with ir_constant values.
     48  */
     49 
     50 class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
     51 public:
     52    ir_vec_index_to_cond_assign_visitor()
     53    {
     54       progress = false;
     55    }
     56 
     57    ir_rvalue *convert_vec_index_to_cond_assign(void *mem_ctx,
     58                                                ir_rvalue *orig_vector,
     59                                                ir_rvalue *orig_index,
     60                                                const glsl_type *type);
     61 
     62    ir_rvalue *convert_vector_extract_to_cond_assign(ir_rvalue *ir);
     63 
     64    virtual ir_visitor_status visit_enter(ir_expression *);
     65    virtual ir_visitor_status visit_enter(ir_swizzle *);
     66    virtual ir_visitor_status visit_leave(ir_assignment *);
     67    virtual ir_visitor_status visit_enter(ir_return *);
     68    virtual ir_visitor_status visit_enter(ir_call *);
     69    virtual ir_visitor_status visit_enter(ir_if *);
     70 
     71    bool progress;
     72 };
     73 
     74 } /* anonymous namespace */
     75 
     76 ir_rvalue *
     77 ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(void *mem_ctx,
     78                                                                       ir_rvalue *orig_vector,
     79                                                                       ir_rvalue *orig_index,
     80                                                                       const glsl_type *type)
     81 {
     82    ir_assignment *assign, *value_assign;
     83    ir_variable *index, *var, *value;
     84    ir_dereference *deref, *deref_value;
     85    unsigned i;
     86 
     87 
     88    exec_list list;
     89 
     90    /* Store the index to a temporary to avoid reusing its tree. */
     91    assert(orig_index->type == glsl_type::int_type ||
     92           orig_index->type == glsl_type::uint_type);
     93    index = new(base_ir) ir_variable(orig_index->type,
     94 				    "vec_index_tmp_i",
     95 				    ir_var_temporary);
     96    list.push_tail(index);
     97    deref = new(base_ir) ir_dereference_variable(index);
     98    assign = new(base_ir) ir_assignment(deref, orig_index, NULL);
     99    list.push_tail(assign);
    100 
    101    /* Store the value inside a temp, thus avoiding matrixes duplication */
    102    value = new(base_ir) ir_variable(orig_vector->type, "vec_value_tmp",
    103                                     ir_var_temporary);
    104    list.push_tail(value);
    105    deref_value = new(base_ir) ir_dereference_variable(value);
    106    value_assign = new(base_ir) ir_assignment(deref_value, orig_vector);
    107    list.push_tail(value_assign);
    108 
    109    /* Temporary where we store whichever value we swizzle out. */
    110    var = new(base_ir) ir_variable(type, "vec_index_tmp_v",
    111 				  ir_var_temporary);
    112    list.push_tail(var);
    113 
    114    /* Generate a single comparison condition "mask" for all of the components
    115     * in the vector.
    116     */
    117    ir_rvalue *const cond_deref =
    118       compare_index_block(&list, index, 0,
    119                           orig_vector->type->vector_elements,
    120 			  mem_ctx);
    121 
    122    /* Generate a conditional move of each vector element to the temp. */
    123    for (i = 0; i < orig_vector->type->vector_elements; i++) {
    124       ir_rvalue *condition_swizzle =
    125          new(base_ir) ir_swizzle(cond_deref->clone(mem_ctx, NULL),
    126                                  i, 0, 0, 0, 1);
    127 
    128       /* Just clone the rest of the deref chain when trying to get at the
    129        * underlying variable.
    130        */
    131       ir_rvalue *swizzle =
    132 	 new(base_ir) ir_swizzle(deref_value->clone(mem_ctx, NULL),
    133 				 i, 0, 0, 0, 1);
    134 
    135       deref = new(base_ir) ir_dereference_variable(var);
    136       assign = new(base_ir) ir_assignment(deref, swizzle, condition_swizzle);
    137       list.push_tail(assign);
    138    }
    139 
    140    /* Put all of the new instructions in the IR stream before the old
    141     * instruction.
    142     */
    143    base_ir->insert_before(&list);
    144 
    145    this->progress = true;
    146    return new(base_ir) ir_dereference_variable(var);
    147 }
    148 
    149 ir_rvalue *
    150 ir_vec_index_to_cond_assign_visitor::convert_vector_extract_to_cond_assign(ir_rvalue *ir)
    151 {
    152    ir_expression *const expr = ir->as_expression();
    153 
    154    if (expr == NULL || expr->operation != ir_binop_vector_extract)
    155       return ir;
    156 
    157    return convert_vec_index_to_cond_assign(ralloc_parent(ir),
    158                                            expr->operands[0],
    159                                            expr->operands[1],
    160                                            ir->type);
    161 }
    162 
    163 ir_visitor_status
    164 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
    165 {
    166    unsigned int i;
    167 
    168    for (i = 0; i < ir->get_num_operands(); i++) {
    169       ir->operands[i] = convert_vector_extract_to_cond_assign(ir->operands[i]);
    170    }
    171 
    172    return visit_continue;
    173 }
    174 
    175 ir_visitor_status
    176 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
    177 {
    178    /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
    179     * the result of indexing a vector is.  But maybe at some point we'll end up
    180     * using swizzling of scalars for vector construction.
    181     */
    182    ir->val = convert_vector_extract_to_cond_assign(ir->val);
    183 
    184    return visit_continue;
    185 }
    186 
    187 ir_visitor_status
    188 ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
    189 {
    190    ir->rhs = convert_vector_extract_to_cond_assign(ir->rhs);
    191 
    192    if (ir->condition) {
    193       ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
    194    }
    195 
    196    return visit_continue;
    197 }
    198 
    199 ir_visitor_status
    200 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
    201 {
    202    foreach_in_list_safe(ir_rvalue, param, &ir->actual_parameters) {
    203       ir_rvalue *new_param = convert_vector_extract_to_cond_assign(param);
    204 
    205       if (new_param != param) {
    206 	 param->replace_with(new_param);
    207       }
    208    }
    209 
    210    return visit_continue;
    211 }
    212 
    213 ir_visitor_status
    214 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
    215 {
    216    if (ir->value) {
    217       ir->value = convert_vector_extract_to_cond_assign(ir->value);
    218    }
    219 
    220    return visit_continue;
    221 }
    222 
    223 ir_visitor_status
    224 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
    225 {
    226    ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
    227 
    228    return visit_continue;
    229 }
    230 
    231 bool
    232 do_vec_index_to_cond_assign(exec_list *instructions)
    233 {
    234    ir_vec_index_to_cond_assign_visitor v;
    235 
    236    visit_list_elements(&v, instructions);
    237 
    238    return v.progress;
    239 }
    240