a6ecad7b659823ffd127242c1c229839753376e2
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]) || is_vec_zero(op_const
[1])) {
217 this->progress
= true;
218 return ir_constant::zero(ir
, ir
->type
);
223 if (is_vec_one(op_const
[0]) && ir
->type
->base_type
== GLSL_TYPE_FLOAT
) {
224 this->progress
= true;
225 return new(ir
) ir_expression(ir_unop_rcp
,
230 if (is_vec_one(op_const
[1])) {
231 this->progress
= true;
232 return ir
->operands
[0];
237 if (op_expr
[0] && op_expr
[0]->operation
== ir_unop_rcp
) {
238 this->progress
= true;
239 return op_expr
[0]->operands
[0];
242 /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some
243 * backends, except that some backends will have done sqrt ->
244 * rcp(rsq(x)) and we don't want to undo it for them.
247 /* As far as we know, all backends are OK with rsq. */
248 if (op_expr
[0] && op_expr
[0]->operation
== ir_unop_sqrt
) {
249 this->progress
= true;
250 return new(ir
) ir_expression(ir_unop_rsq
,
252 op_expr
[0]->operands
[0],
266 ir_algebraic_visitor::visit_leave(ir_expression
*ir
)
268 unsigned int operand
;
270 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
271 ir
->operands
[operand
] = handle_expression(ir
->operands
[operand
]);
274 return visit_continue
;
278 ir_algebraic_visitor::visit_leave(ir_texture
*ir
)
280 ir
->coordinate
= handle_expression(ir
->coordinate
);
281 ir
->projector
= handle_expression(ir
->projector
);
282 ir
->shadow_comparitor
= handle_expression(ir
->shadow_comparitor
);
288 ir
->lod_info
.bias
= handle_expression(ir
->lod_info
.bias
);
292 ir
->lod_info
.lod
= handle_expression(ir
->lod_info
.lod
);
295 ir
->lod_info
.grad
.dPdx
= handle_expression(ir
->lod_info
.grad
.dPdx
);
296 ir
->lod_info
.grad
.dPdy
= handle_expression(ir
->lod_info
.grad
.dPdy
);
300 return visit_continue
;
304 ir_algebraic_visitor::visit_leave(ir_swizzle
*ir
)
306 ir
->val
= handle_expression(ir
->val
);
307 return visit_continue
;
311 ir_algebraic_visitor::visit_leave(ir_dereference_array
*ir
)
313 ir
->array_index
= handle_expression(ir
->array_index
);
314 return visit_continue
;
318 ir_algebraic_visitor::visit_leave(ir_assignment
*ir
)
320 ir
->rhs
= handle_expression(ir
->rhs
);
321 ir
->condition
= handle_expression(ir
->condition
);
322 return visit_continue
;
326 ir_algebraic_visitor::visit_leave(ir_call
*ir
)
328 foreach_iter(exec_list_iterator
, iter
, *ir
) {
329 ir_rvalue
*param
= (ir_rvalue
*)iter
.get();
330 ir_rvalue
*new_param
= handle_expression(param
);
332 if (new_param
!= param
) {
333 param
->replace_with(new_param
);
336 return visit_continue
;
340 ir_algebraic_visitor::visit_leave(ir_return
*ir
)
342 ir
->value
= handle_expression(ir
->value
);;
343 return visit_continue
;
347 ir_algebraic_visitor::visit_leave(ir_if
*ir
)
349 ir
->condition
= handle_expression(ir
->condition
);
350 return visit_continue
;
355 do_algebraic(exec_list
*instructions
)
357 ir_algebraic_visitor v
;
359 visit_list_elements(&v
, instructions
);