2 * Copyright © 2010 Intel Corporation
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:
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
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.
25 * \file ir_algebraic.cpp
27 * Takes advantage of association, commutivity, and other algebraic
28 * properties to simplify expressions.
32 #include "ir_visitor.h"
33 #include "ir_optimization.h"
34 #include "glsl_types.h"
37 * Visitor class for replacing expressions with ir_constant values.
40 class ir_algebraic_visitor
: public ir_hierarchical_visitor
{
42 ir_algebraic_visitor()
44 this->progress
= false;
47 virtual ~ir_algebraic_visitor()
51 virtual ir_visitor_status
visit_leave(ir_assignment
*);
52 virtual ir_visitor_status
visit_leave(ir_call
*);
53 virtual ir_visitor_status
visit_leave(ir_dereference_array
*);
54 virtual ir_visitor_status
visit_leave(ir_expression
*);
55 virtual ir_visitor_status
visit_leave(ir_if
*);
56 virtual ir_visitor_status
visit_leave(ir_return
*);
57 virtual ir_visitor_status
visit_leave(ir_swizzle
*);
58 virtual ir_visitor_status
visit_leave(ir_texture
*);
60 ir_rvalue
*handle_expression(ir_rvalue
*in_ir
);
66 is_vec_zero(ir_constant
*ir
)
72 if (!ir
->type
->is_scalar() &&
73 !ir
->type
->is_vector())
76 for (c
= 0; c
< ir
->type
->vector_elements
; c
++) {
77 switch (ir
->type
->base_type
) {
79 if (ir
->value
.f
[c
] != 0.0)
83 if (ir
->value
.i
[c
] != 0)
87 if (ir
->value
.u
[c
] != 0)
91 if (ir
->value
.b
[c
] != false)
95 assert(!"bad base type");
104 is_vec_one(ir_constant
*ir
)
110 if (!ir
->type
->is_scalar() &&
111 !ir
->type
->is_vector())
114 for (c
= 0; c
< ir
->type
->vector_elements
; c
++) {
115 switch (ir
->type
->base_type
) {
116 case GLSL_TYPE_FLOAT
:
117 if (ir
->value
.f
[c
] != 1.0)
121 if (ir
->value
.i
[c
] != 1)
125 if (ir
->value
.u
[c
] != 1)
129 if (ir
->value
.b
[c
] != true)
133 assert(!"bad base type");
142 ir_algebraic_visitor::handle_expression(ir_rvalue
*in_ir
)
144 ir_expression
*ir
= (ir_expression
*)in_ir
;
145 ir_constant
*op_const
[2] = {NULL
, NULL
};
146 ir_expression
*op_expr
[2] = {NULL
, NULL
};
152 if (in_ir
->ir_type
!= ir_type_expression
)
155 for (i
= 0; i
< ir
->get_num_operands(); i
++) {
156 if (ir
->operands
[i
]->type
->is_matrix())
159 op_const
[i
] = ir
->operands
[i
]->constant_expression_value();
160 op_expr
[i
] = ir
->operands
[i
]->as_expression();
163 switch (ir
->operation
) {
164 case ir_unop_logic_not
: {
165 enum ir_expression_operation new_op
= ir_unop_logic_not
;
167 if (op_expr
[0] == NULL
)
170 switch (op_expr
[0]->operation
) {
171 case ir_binop_less
: new_op
= ir_binop_gequal
; break;
172 case ir_binop_greater
: new_op
= ir_binop_lequal
; break;
173 case ir_binop_lequal
: new_op
= ir_binop_greater
; break;
174 case ir_binop_gequal
: new_op
= ir_binop_less
; break;
175 case ir_binop_equal
: new_op
= ir_binop_nequal
; break;
176 case ir_binop_nequal
: new_op
= ir_binop_equal
; break;
179 /* The default case handler is here to silence a warning from GCC.
184 if (new_op
!= ir_unop_logic_not
) {
185 this->progress
= true;
186 return new(ir
) ir_expression(new_op
,
188 op_expr
[0]->operands
[0],
189 op_expr
[0]->operands
[1]);
196 if (is_vec_zero(op_const
[0])) {
197 this->progress
= true;
198 return ir
->operands
[1];
200 if (is_vec_zero(op_const
[1])) {
201 this->progress
= true;
202 return ir
->operands
[0];
207 if (is_vec_zero(op_const
[0])) {
208 this->progress
= true;
209 return new(ir
) ir_expression(ir_unop_neg
,
214 if (is_vec_zero(op_const
[1])) {
215 this->progress
= true;
216 return ir
->operands
[0];
221 if (is_vec_one(op_const
[0])) {
222 this->progress
= true;
223 return ir
->operands
[1];
225 if (is_vec_one(op_const
[1])) {
226 this->progress
= true;
227 return ir
->operands
[0];
230 if (is_vec_zero(op_const
[0]) || is_vec_zero(op_const
[1])) {
231 this->progress
= true;
232 return ir_constant::zero(ir
, ir
->type
);
237 if (is_vec_one(op_const
[0]) && ir
->type
->base_type
== GLSL_TYPE_FLOAT
) {
238 this->progress
= true;
239 return new(ir
) ir_expression(ir_unop_rcp
,
244 if (is_vec_one(op_const
[1])) {
245 this->progress
= true;
246 return ir
->operands
[0];
251 if (op_expr
[0] && op_expr
[0]->operation
== ir_unop_rcp
) {
252 this->progress
= true;
253 return op_expr
[0]->operands
[0];
256 /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
257 * backends, except that some backends will have done sqrt ->
258 * rcp(rsq(x)) and we don't want to undo it for them.
261 /* As far as we know, all backends are OK with rsq. */
262 if (op_expr
[0] && op_expr
[0]->operation
== ir_unop_sqrt
) {
263 this->progress
= true;
264 return new(ir
) ir_expression(ir_unop_rsq
,
266 op_expr
[0]->operands
[0],
280 ir_algebraic_visitor::visit_leave(ir_expression
*ir
)
282 unsigned int operand
;
284 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
285 ir
->operands
[operand
] = handle_expression(ir
->operands
[operand
]);
288 return visit_continue
;
292 ir_algebraic_visitor::visit_leave(ir_texture
*ir
)
294 ir
->coordinate
= handle_expression(ir
->coordinate
);
295 ir
->projector
= handle_expression(ir
->projector
);
296 ir
->shadow_comparitor
= handle_expression(ir
->shadow_comparitor
);
302 ir
->lod_info
.bias
= handle_expression(ir
->lod_info
.bias
);
306 ir
->lod_info
.lod
= handle_expression(ir
->lod_info
.lod
);
309 ir
->lod_info
.grad
.dPdx
= handle_expression(ir
->lod_info
.grad
.dPdx
);
310 ir
->lod_info
.grad
.dPdy
= handle_expression(ir
->lod_info
.grad
.dPdy
);
314 return visit_continue
;
318 ir_algebraic_visitor::visit_leave(ir_swizzle
*ir
)
320 ir
->val
= handle_expression(ir
->val
);
321 return visit_continue
;
325 ir_algebraic_visitor::visit_leave(ir_dereference_array
*ir
)
327 ir
->array_index
= handle_expression(ir
->array_index
);
328 return visit_continue
;
332 ir_algebraic_visitor::visit_leave(ir_assignment
*ir
)
334 ir
->rhs
= handle_expression(ir
->rhs
);
335 ir
->condition
= handle_expression(ir
->condition
);
336 return visit_continue
;
340 ir_algebraic_visitor::visit_leave(ir_call
*ir
)
342 foreach_iter(exec_list_iterator
, iter
, *ir
) {
343 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
344 ir_rvalue
*new_param
= handle_expression(param
);
346 if (new_param
!= param
) {
347 param
->replace_with(new_param
);
350 return visit_continue
;
354 ir_algebraic_visitor::visit_leave(ir_return
*ir
)
356 ir
->value
= handle_expression(ir
->value
);;
357 return visit_continue
;
361 ir_algebraic_visitor::visit_leave(ir_if
*ir
)
363 ir
->condition
= handle_expression(ir
->condition
);
364 return visit_continue
;
369 do_algebraic(exec_list
*instructions
)
371 ir_algebraic_visitor v
;
373 visit_list_elements(&v
, instructions
);