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