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 if (op_expr
[0] && op_expr
[0]->operation
== ir_binop_equal
) {
166 this->progress
= true;
167 return new(ir
) ir_expression(ir_binop_nequal
,
169 op_expr
[0]->operands
[0],
170 op_expr
[0]->operands
[1]);
172 if (op_expr
[0] && op_expr
[0]->operation
== ir_binop_nequal
) {
173 this->progress
= true;
174 return new(ir
) ir_expression(ir_binop_equal
,
176 op_expr
[0]->operands
[0],
177 op_expr
[0]->operands
[1]);
182 if (is_vec_zero(op_const
[0])) {
183 this->progress
= true;
184 return ir
->operands
[1];
186 if (is_vec_zero(op_const
[1])) {
187 this->progress
= true;
188 return ir
->operands
[0];
193 if (is_vec_zero(op_const
[0])) {
194 this->progress
= true;
195 return new(ir
) ir_expression(ir_unop_neg
,
200 if (is_vec_zero(op_const
[1])) {
201 this->progress
= true;
202 return ir
->operands
[0];
207 if (is_vec_one(op_const
[0])) {
208 this->progress
= true;
209 return ir
->operands
[1];
211 if (is_vec_one(op_const
[1])) {
212 this->progress
= true;
213 return ir
->operands
[0];
216 if (is_vec_zero(op_const
[0]) ||
217 is_vec_zero(op_const
[1])) {
218 ir_constant_data zero_data
;
219 memset(&zero_data
, 0, sizeof(zero_data
));
221 this->progress
= true;
222 return new(ir
) ir_constant(ir
->type
, &zero_data
);
227 if (is_vec_one(op_const
[0]) && ir
->type
->base_type
== GLSL_TYPE_FLOAT
) {
228 this->progress
= true;
229 return new(ir
) ir_expression(ir_unop_rcp
,
234 if (is_vec_one(op_const
[1])) {
235 this->progress
= true;
236 return ir
->operands
[0];
241 if (op_expr
[0] && op_expr
[0]->operation
== ir_unop_rcp
) {
242 this->progress
= true;
243 return op_expr
[0]->operands
[0];
246 /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
247 * backends, except that some backends will have done sqrt ->
248 * rcp(rsq(x)) and we don't want to undo it for them.
251 /* As far as we know, all backends are OK with rsq. */
252 if (op_expr
[0] && op_expr
[0]->operation
== ir_unop_sqrt
) {
253 this->progress
= true;
254 return new(ir
) ir_expression(ir_unop_rsq
,
256 op_expr
[0]->operands
[0],
270 ir_algebraic_visitor::visit_leave(ir_expression
*ir
)
272 unsigned int operand
;
274 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
275 ir
->operands
[operand
] = handle_expression(ir
->operands
[operand
]);
278 return visit_continue
;
282 ir_algebraic_visitor::visit_leave(ir_texture
*ir
)
284 ir
->coordinate
= handle_expression(ir
->coordinate
);
285 ir
->projector
= handle_expression(ir
->projector
);
286 ir
->shadow_comparitor
= handle_expression(ir
->shadow_comparitor
);
292 ir
->lod_info
.bias
= handle_expression(ir
->lod_info
.bias
);
296 ir
->lod_info
.lod
= handle_expression(ir
->lod_info
.lod
);
299 ir
->lod_info
.grad
.dPdx
= handle_expression(ir
->lod_info
.grad
.dPdx
);
300 ir
->lod_info
.grad
.dPdy
= handle_expression(ir
->lod_info
.grad
.dPdy
);
304 return visit_continue
;
308 ir_algebraic_visitor::visit_leave(ir_swizzle
*ir
)
310 ir
->val
= handle_expression(ir
->val
);
311 return visit_continue
;
315 ir_algebraic_visitor::visit_leave(ir_dereference_array
*ir
)
317 ir
->array_index
= handle_expression(ir
->array_index
);
318 return visit_continue
;
322 ir_algebraic_visitor::visit_leave(ir_assignment
*ir
)
324 ir
->rhs
= handle_expression(ir
->rhs
);
325 ir
->condition
= handle_expression(ir
->condition
);
326 return visit_continue
;
330 ir_algebraic_visitor::visit_leave(ir_call
*ir
)
332 foreach_iter(exec_list_iterator
, iter
, *ir
) {
333 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
334 ir_rvalue
*new_param
= handle_expression(param
);
336 if (new_param
!= param
) {
337 param
->replace_with(new_param
);
340 return visit_continue
;
344 ir_algebraic_visitor::visit_leave(ir_return
*ir
)
346 ir
->value
= handle_expression(ir
->value
);;
347 return visit_continue
;
351 ir_algebraic_visitor::visit_leave(ir_if
*ir
)
353 ir
->condition
= handle_expression(ir
->condition
);
354 return visit_continue
;
359 do_algebraic(exec_list
*instructions
)
361 ir_algebraic_visitor v
;
363 visit_list_elements(&v
, instructions
);