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_swizzle.cpp
     26  *
     27  * Turns constant indexing into vector types to swizzles.  This will
     28  * let other swizzle-aware optimization passes catch these constructs,
     29  * and codegen backends not have to worry about this case.
     30  */
     31 
     32 #include "ir.h"
     33 #include "ir_visitor.h"
     34 #include "ir_optimization.h"
     35 #include "glsl_types.h"
     36 #include "main/macros.h"
     37 
     38 /**
     39  * Visitor class for replacing expressions with ir_constant values.
     40  */
     41 
     42 class ir_vec_index_to_swizzle_visitor : public ir_hierarchical_visitor {
     43 public:
     44    ir_vec_index_to_swizzle_visitor()
     45    {
     46       progress = false;
     47    }
     48 
     49    ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val);
     50 
     51    virtual ir_visitor_status visit_enter(ir_expression *);
     52    virtual ir_visitor_status visit_enter(ir_swizzle *);
     53    virtual ir_visitor_status visit_enter(ir_assignment *);
     54    virtual ir_visitor_status visit_enter(ir_return *);
     55    virtual ir_visitor_status visit_enter(ir_call *);
     56    virtual ir_visitor_status visit_enter(ir_if *);
     57 
     58    bool progress;
     59 };
     60 
     61 ir_rvalue *
     62 ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir)
     63 {
     64    ir_dereference_array *deref = ir->as_dereference_array();
     65    ir_constant *ir_constant;
     66 
     67    if (!deref)
     68       return ir;
     69 
     70    if (deref->array->type->is_matrix() || deref->array->type->is_array())
     71       return ir;
     72 
     73    assert(deref->array_index->type->base_type == GLSL_TYPE_INT);
     74    ir_constant = deref->array_index->constant_expression_value();
     75    if (!ir_constant)
     76       return ir;
     77 
     78    void *ctx = ralloc_parent(ir);
     79    this->progress = true;
     80 
     81    /* Page 40 of the GLSL 1.20 spec says:
     82     *
     83     *     "When indexing with non-constant expressions, behavior is undefined
     84     *     if the index is negative, or greater than or equal to the size of
     85     *     the vector."
     86     *
     87     * The quoted spec text mentions non-constant expressions, but this code
     88     * operates on constants.  These constants are the result of non-constant
     89     * expressions that have been optimized to constants.  The common case here
     90     * is a loop counter from an unrolled loop that is used to index a vector.
     91     *
     92     * The ir_swizzle constructor gets angry if the index is negative or too
     93     * large.  For simplicity sake, just clamp the index to [0, size-1].
     94     */
     95    const int i = MIN2(MAX2(ir_constant->value.i[0], 0),
     96 		      (deref->array->type->vector_elements - 1));
     97 
     98    return new(ctx) ir_swizzle(deref->array, i, 0, 0, 0, 1);
     99 }
    100 
    101 ir_visitor_status
    102 ir_vec_index_to_swizzle_visitor::visit_enter(ir_expression *ir)
    103 {
    104    unsigned int i;
    105 
    106    for (i = 0; i < ir->get_num_operands(); i++) {
    107       ir->operands[i] = convert_vec_index_to_swizzle(ir->operands[i]);
    108    }
    109 
    110    return visit_continue;
    111 }
    112 
    113 ir_visitor_status
    114 ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir)
    115 {
    116    /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
    117     * the result of indexing a vector is.  But maybe at some point we'll end up
    118     * using swizzling of scalars for vector construction.
    119     */
    120    ir->val = convert_vec_index_to_swizzle(ir->val);
    121 
    122    return visit_continue;
    123 }
    124 
    125 ir_visitor_status
    126 ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir)
    127 {
    128    ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs));
    129    ir->rhs = convert_vec_index_to_swizzle(ir->rhs);
    130 
    131    return visit_continue;
    132 }
    133 
    134 ir_visitor_status
    135 ir_vec_index_to_swizzle_visitor::visit_enter(ir_call *ir)
    136 {
    137    foreach_iter(exec_list_iterator, iter, *ir) {
    138       ir_rvalue *param = (ir_rvalue *)iter.get();
    139       ir_rvalue *new_param = convert_vec_index_to_swizzle(param);
    140 
    141       if (new_param != param) {
    142 	 param->replace_with(new_param);
    143       }
    144    }
    145 
    146    return visit_continue;
    147 }
    148 
    149 ir_visitor_status
    150 ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir)
    151 {
    152    if (ir->value) {
    153       ir->value = convert_vec_index_to_swizzle(ir->value);
    154    }
    155 
    156    return visit_continue;
    157 }
    158 
    159 ir_visitor_status
    160 ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir)
    161 {
    162    ir->condition = convert_vec_index_to_swizzle(ir->condition);
    163 
    164    return visit_continue;
    165 }
    166 
    167 bool
    168 do_vec_index_to_swizzle(exec_list *instructions)
    169 {
    170    ir_vec_index_to_swizzle_visitor v;
    171 
    172    v.run(instructions);
    173 
    174    return v.progress;
    175 }
    176