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 opt_algebraic.cpp
     26  *
     27  * Takes advantage of association, commutivity, and other algebraic
     28  * properties to simplify expressions.
     29  */
     30 
     31 #include "ir.h"
     32 #include "ir_visitor.h"
     33 #include "ir_rvalue_visitor.h"
     34 #include "ir_optimization.h"
     35 #include "glsl_types.h"
     36 
     37 namespace {
     38 
     39 /**
     40  * Visitor class for replacing expressions with ir_constant values.
     41  */
     42 
     43 class ir_algebraic_visitor : public ir_rvalue_visitor {
     44 public:
     45    ir_algebraic_visitor()
     46    {
     47       this->progress = false;
     48       this->mem_ctx = NULL;
     49    }
     50 
     51    virtual ~ir_algebraic_visitor()
     52    {
     53    }
     54 
     55    ir_rvalue *handle_expression(ir_expression *ir);
     56    void handle_rvalue(ir_rvalue **rvalue);
     57    bool reassociate_constant(ir_expression *ir1,
     58 			     int const_index,
     59 			     ir_constant *constant,
     60 			     ir_expression *ir2);
     61    void reassociate_operands(ir_expression *ir1,
     62 			     int op1,
     63 			     ir_expression *ir2,
     64 			     int op2);
     65    ir_rvalue *swizzle_if_required(ir_expression *expr,
     66 				  ir_rvalue *operand);
     67 
     68    void *mem_ctx;
     69 
     70    bool progress;
     71 };
     72 
     73 } /* unnamed namespace */
     74 
     75 static inline bool
     76 is_vec_zero(ir_constant *ir)
     77 {
     78    return (ir == NULL) ? false : ir->is_zero();
     79 }
     80 
     81 static inline bool
     82 is_vec_one(ir_constant *ir)
     83 {
     84    return (ir == NULL) ? false : ir->is_one();
     85 }
     86 
     87 static inline bool
     88 is_vec_basis(ir_constant *ir)
     89 {
     90    return (ir == NULL) ? false : ir->is_basis();
     91 }
     92 
     93 static void
     94 update_type(ir_expression *ir)
     95 {
     96    if (ir->operands[0]->type->is_vector())
     97       ir->type = ir->operands[0]->type;
     98    else
     99       ir->type = ir->operands[1]->type;
    100 }
    101 
    102 void
    103 ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
    104 					   int op1,
    105 					   ir_expression *ir2,
    106 					   int op2)
    107 {
    108    ir_rvalue *temp = ir2->operands[op2];
    109    ir2->operands[op2] = ir1->operands[op1];
    110    ir1->operands[op1] = temp;
    111 
    112    /* Update the type of ir2.  The type of ir1 won't have changed --
    113     * base types matched, and at least one of the operands of the 2
    114     * binops is still a vector if any of them were.
    115     */
    116    update_type(ir2);
    117 
    118    this->progress = true;
    119 }
    120 
    121 /**
    122  * Reassociates a constant down a tree of adds or multiplies.
    123  *
    124  * Consider (2 * (a * (b * 0.5))).  We want to send up with a * b.
    125  */
    126 bool
    127 ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
    128 					   ir_constant *constant,
    129 					   ir_expression *ir2)
    130 {
    131    if (!ir2 || ir1->operation != ir2->operation)
    132       return false;
    133 
    134    /* Don't want to even think about matrices. */
    135    if (ir1->operands[0]->type->is_matrix() ||
    136        ir1->operands[1]->type->is_matrix() ||
    137        ir2->operands[0]->type->is_matrix() ||
    138        ir2->operands[1]->type->is_matrix())
    139       return false;
    140 
    141    ir_constant *ir2_const[2];
    142    ir2_const[0] = ir2->operands[0]->constant_expression_value();
    143    ir2_const[1] = ir2->operands[1]->constant_expression_value();
    144 
    145    if (ir2_const[0] && ir2_const[1])
    146       return false;
    147 
    148    if (ir2_const[0]) {
    149       reassociate_operands(ir1, const_index, ir2, 1);
    150       return true;
    151    } else if (ir2_const[1]) {
    152       reassociate_operands(ir1, const_index, ir2, 0);
    153       return true;
    154    }
    155 
    156    if (reassociate_constant(ir1, const_index, constant,
    157 			    ir2->operands[0]->as_expression())) {
    158       update_type(ir2);
    159       return true;
    160    }
    161 
    162    if (reassociate_constant(ir1, const_index, constant,
    163 			    ir2->operands[1]->as_expression())) {
    164       update_type(ir2);
    165       return true;
    166    }
    167 
    168    return false;
    169 }
    170 
    171 /* When eliminating an expression and just returning one of its operands,
    172  * we may need to swizzle that operand out to a vector if the expression was
    173  * vector type.
    174  */
    175 ir_rvalue *
    176 ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
    177 					  ir_rvalue *operand)
    178 {
    179    if (expr->type->is_vector() && operand->type->is_scalar()) {
    180       return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0,
    181 				     expr->type->vector_elements);
    182    } else
    183       return operand;
    184 }
    185 
    186 ir_rvalue *
    187 ir_algebraic_visitor::handle_expression(ir_expression *ir)
    188 {
    189    ir_constant *op_const[2] = {NULL, NULL};
    190    ir_expression *op_expr[2] = {NULL, NULL};
    191    ir_expression *temp;
    192    unsigned int i;
    193 
    194    assert(ir->get_num_operands() <= 2);
    195    for (i = 0; i < ir->get_num_operands(); i++) {
    196       if (ir->operands[i]->type->is_matrix())
    197 	 return ir;
    198 
    199       op_const[i] = ir->operands[i]->constant_expression_value();
    200       op_expr[i] = ir->operands[i]->as_expression();
    201    }
    202 
    203    if (this->mem_ctx == NULL)
    204       this->mem_ctx = ralloc_parent(ir);
    205 
    206    switch (ir->operation) {
    207    case ir_unop_logic_not: {
    208       enum ir_expression_operation new_op = ir_unop_logic_not;
    209 
    210       if (op_expr[0] == NULL)
    211 	 break;
    212 
    213       switch (op_expr[0]->operation) {
    214       case ir_binop_less:    new_op = ir_binop_gequal;  break;
    215       case ir_binop_greater: new_op = ir_binop_lequal;  break;
    216       case ir_binop_lequal:  new_op = ir_binop_greater; break;
    217       case ir_binop_gequal:  new_op = ir_binop_less;    break;
    218       case ir_binop_equal:   new_op = ir_binop_nequal;  break;
    219       case ir_binop_nequal:  new_op = ir_binop_equal;   break;
    220       case ir_binop_all_equal:   new_op = ir_binop_any_nequal;  break;
    221       case ir_binop_any_nequal:  new_op = ir_binop_all_equal;   break;
    222 
    223       default:
    224 	 /* The default case handler is here to silence a warning from GCC.
    225 	  */
    226 	 break;
    227       }
    228 
    229       if (new_op != ir_unop_logic_not) {
    230 	 this->progress = true;
    231 	 return new(mem_ctx) ir_expression(new_op,
    232 					   ir->type,
    233 					   op_expr[0]->operands[0],
    234 					   op_expr[0]->operands[1]);
    235       }
    236 
    237       break;
    238    }
    239 
    240    case ir_binop_add:
    241       if (is_vec_zero(op_const[0])) {
    242 	 this->progress = true;
    243 	 return swizzle_if_required(ir, ir->operands[1]);
    244       }
    245       if (is_vec_zero(op_const[1])) {
    246 	 this->progress = true;
    247 	 return swizzle_if_required(ir, ir->operands[0]);
    248       }
    249 
    250       /* Reassociate addition of constants so that we can do constant
    251        * folding.
    252        */
    253       if (op_const[0] && !op_const[1])
    254 	 reassociate_constant(ir, 0, op_const[0],
    255 			      ir->operands[1]->as_expression());
    256       if (op_const[1] && !op_const[0])
    257 	 reassociate_constant(ir, 1, op_const[1],
    258 			      ir->operands[0]->as_expression());
    259       break;
    260 
    261    case ir_binop_sub:
    262       if (is_vec_zero(op_const[0])) {
    263 	 this->progress = true;
    264 	 temp = new(mem_ctx) ir_expression(ir_unop_neg,
    265 					   ir->operands[1]->type,
    266 					   ir->operands[1],
    267 					   NULL);
    268 	 return swizzle_if_required(ir, temp);
    269       }
    270       if (is_vec_zero(op_const[1])) {
    271 	 this->progress = true;
    272 	 return swizzle_if_required(ir, ir->operands[0]);
    273       }
    274       break;
    275 
    276    case ir_binop_mul:
    277       if (is_vec_one(op_const[0])) {
    278 	 this->progress = true;
    279 	 return swizzle_if_required(ir, ir->operands[1]);
    280       }
    281       if (is_vec_one(op_const[1])) {
    282 	 this->progress = true;
    283 	 return swizzle_if_required(ir, ir->operands[0]);
    284       }
    285 
    286       if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
    287 	 this->progress = true;
    288 	 return ir_constant::zero(ir, ir->type);
    289       }
    290 
    291       /* Reassociate multiplication of constants so that we can do
    292        * constant folding.
    293        */
    294       if (op_const[0] && !op_const[1])
    295 	 reassociate_constant(ir, 0, op_const[0],
    296 			      ir->operands[1]->as_expression());
    297       if (op_const[1] && !op_const[0])
    298 	 reassociate_constant(ir, 1, op_const[1],
    299 			      ir->operands[0]->as_expression());
    300 
    301       break;
    302 
    303    case ir_binop_div:
    304       if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) {
    305 	 this->progress = true;
    306 	 temp = new(mem_ctx) ir_expression(ir_unop_rcp,
    307 					   ir->operands[1]->type,
    308 					   ir->operands[1],
    309 					   NULL);
    310 	 return swizzle_if_required(ir, temp);
    311       }
    312       if (is_vec_one(op_const[1])) {
    313 	 this->progress = true;
    314 	 return swizzle_if_required(ir, ir->operands[0]);
    315       }
    316       break;
    317 
    318    case ir_binop_dot:
    319       if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
    320 	 this->progress = true;
    321 	 return ir_constant::zero(mem_ctx, ir->type);
    322       }
    323       if (is_vec_basis(op_const[0])) {
    324 	 this->progress = true;
    325 	 unsigned component = 0;
    326 	 for (unsigned c = 0; c < op_const[0]->type->vector_elements; c++) {
    327 	    if (op_const[0]->value.f[c] == 1.0)
    328 	       component = c;
    329 	 }
    330 	 return new(mem_ctx) ir_swizzle(ir->operands[1], component, 0, 0, 0, 1);
    331       }
    332       if (is_vec_basis(op_const[1])) {
    333 	 this->progress = true;
    334 	 unsigned component = 0;
    335 	 for (unsigned c = 0; c < op_const[1]->type->vector_elements; c++) {
    336 	    if (op_const[1]->value.f[c] == 1.0)
    337 	       component = c;
    338 	 }
    339 	 return new(mem_ctx) ir_swizzle(ir->operands[0], component, 0, 0, 0, 1);
    340       }
    341       break;
    342 
    343    case ir_binop_logic_and:
    344       /* FINISHME: Also simplify (a && a) to (a). */
    345       if (is_vec_one(op_const[0])) {
    346 	 this->progress = true;
    347 	 return ir->operands[1];
    348       } else if (is_vec_one(op_const[1])) {
    349 	 this->progress = true;
    350 	 return ir->operands[0];
    351       } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
    352 	 this->progress = true;
    353 	 return ir_constant::zero(mem_ctx, ir->type);
    354       }
    355       break;
    356 
    357    case ir_binop_logic_xor:
    358       /* FINISHME: Also simplify (a ^^ a) to (false). */
    359       if (is_vec_zero(op_const[0])) {
    360 	 this->progress = true;
    361 	 return ir->operands[1];
    362       } else if (is_vec_zero(op_const[1])) {
    363 	 this->progress = true;
    364 	 return ir->operands[0];
    365       } else if (is_vec_one(op_const[0])) {
    366 	 this->progress = true;
    367 	 return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
    368 					   ir->operands[1], NULL);
    369       } else if (is_vec_one(op_const[1])) {
    370 	 this->progress = true;
    371 	 return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type,
    372 					   ir->operands[0], NULL);
    373       }
    374       break;
    375 
    376    case ir_binop_logic_or:
    377       /* FINISHME: Also simplify (a || a) to (a). */
    378       if (is_vec_zero(op_const[0])) {
    379 	 this->progress = true;
    380 	 return ir->operands[1];
    381       } else if (is_vec_zero(op_const[1])) {
    382 	 this->progress = true;
    383 	 return ir->operands[0];
    384       } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) {
    385 	 ir_constant_data data;
    386 
    387 	 for (unsigned i = 0; i < 16; i++)
    388 	    data.b[i] = true;
    389 
    390 	 this->progress = true;
    391 	 return new(mem_ctx) ir_constant(ir->type, &data);
    392       }
    393       break;
    394 
    395    case ir_unop_rcp:
    396       if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) {
    397 	 this->progress = true;
    398 	 return op_expr[0]->operands[0];
    399       }
    400 
    401       /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
    402        * backends, except that some backends will have done sqrt ->
    403        * rcp(rsq(x)) and we don't want to undo it for them.
    404        */
    405 
    406       /* As far as we know, all backends are OK with rsq. */
    407       if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) {
    408 	 this->progress = true;
    409 	 temp = new(mem_ctx) ir_expression(ir_unop_rsq,
    410 					   op_expr[0]->operands[0]->type,
    411 					   op_expr[0]->operands[0],
    412 					   NULL);
    413 	 return swizzle_if_required(ir, temp);
    414       }
    415 
    416       break;
    417 
    418    default:
    419       break;
    420    }
    421 
    422    return ir;
    423 }
    424 
    425 void
    426 ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
    427 {
    428    if (!*rvalue)
    429       return;
    430 
    431    ir_expression *expr = (*rvalue)->as_expression();
    432    if (!expr || expr->operation == ir_quadop_vector)
    433       return;
    434 
    435    *rvalue = handle_expression(expr);
    436 }
    437 
    438 bool
    439 do_algebraic(exec_list *instructions)
    440 {
    441    ir_algebraic_visitor v;
    442 
    443    visit_list_elements(&v, instructions);
    444 
    445    return v.progress;
    446 }
    447