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 "ir_builder.h"
36 #include "compiler/glsl_types.h"
37 #include "main/consts_exts.h"
38
39 using namespace ir_builder;
40
41 namespace {
42
43 /**
44 * Visitor class for replacing expressions with ir_constant values.
45 */
46
47 class ir_algebraic_visitor : public ir_rvalue_visitor {
48 public:
ir_algebraic_visitor(bool native_integers,const struct gl_shader_compiler_options * options)49 ir_algebraic_visitor(bool native_integers,
50 const struct gl_shader_compiler_options *options)
51 : options(options)
52 {
53 this->progress = false;
54 this->mem_ctx = NULL;
55 this->native_integers = native_integers;
56 }
57
~ir_algebraic_visitor()58 virtual ~ir_algebraic_visitor()
59 {
60 }
61
62 virtual ir_visitor_status visit_enter(ir_assignment *ir);
63
64 ir_rvalue *handle_expression(ir_expression *ir);
65 void handle_rvalue(ir_rvalue **rvalue);
66 bool reassociate_constant(ir_expression *ir1,
67 int const_index,
68 ir_constant *constant,
69 ir_expression *ir2);
70 void reassociate_operands(ir_expression *ir1,
71 int op1,
72 ir_expression *ir2,
73 int op2);
74 ir_rvalue *swizzle_if_required(ir_expression *expr,
75 ir_rvalue *operand);
76
77 const struct gl_shader_compiler_options *options;
78 void *mem_ctx;
79
80 bool native_integers;
81 bool progress;
82 };
83
84 } /* unnamed namespace */
85
86 ir_visitor_status
visit_enter(ir_assignment * ir)87 ir_algebraic_visitor::visit_enter(ir_assignment *ir)
88 {
89 ir_variable *var = ir->lhs->variable_referenced();
90 if (var->data.invariant || var->data.precise) {
91 /* If we're assigning to an invariant or precise variable, just bail.
92 * Most of the algebraic optimizations aren't precision-safe.
93 *
94 * FINISHME: Find out which optimizations are precision-safe and enable
95 * then only for invariant or precise trees.
96 */
97 return visit_continue_with_parent;
98 } else {
99 return visit_continue;
100 }
101 }
102
103 static inline bool
is_valid_vec_const(ir_constant * ir)104 is_valid_vec_const(ir_constant *ir)
105 {
106 if (ir == NULL)
107 return false;
108
109 if (!glsl_type_is_scalar(ir->type) && !glsl_type_is_vector(ir->type))
110 return false;
111
112 return true;
113 }
114
115 static inline bool
is_less_than_one(ir_constant * ir)116 is_less_than_one(ir_constant *ir)
117 {
118 assert(glsl_type_is_float(ir->type));
119
120 if (!is_valid_vec_const(ir))
121 return false;
122
123 unsigned component = 0;
124 for (int c = 0; c < ir->type->vector_elements; c++) {
125 if (ir->get_float_component(c) < 1.0f)
126 component++;
127 }
128
129 return (component == ir->type->vector_elements);
130 }
131
132 static inline bool
is_greater_than_zero(ir_constant * ir)133 is_greater_than_zero(ir_constant *ir)
134 {
135 assert(glsl_type_is_float(ir->type));
136
137 if (!is_valid_vec_const(ir))
138 return false;
139
140 unsigned component = 0;
141 for (int c = 0; c < ir->type->vector_elements; c++) {
142 if (ir->get_float_component(c) > 0.0f)
143 component++;
144 }
145
146 return (component == ir->type->vector_elements);
147 }
148
149 static void
update_type(ir_expression * ir)150 update_type(ir_expression *ir)
151 {
152 if (glsl_type_is_vector(ir->operands[0]->type))
153 ir->type = ir->operands[0]->type;
154 else
155 ir->type = ir->operands[1]->type;
156 }
157
158 void
reassociate_operands(ir_expression * ir1,int op1,ir_expression * ir2,int op2)159 ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
160 int op1,
161 ir_expression *ir2,
162 int op2)
163 {
164 ir_rvalue *temp = ir2->operands[op2];
165 ir2->operands[op2] = ir1->operands[op1];
166 ir1->operands[op1] = temp;
167
168 /* Update the type of ir2. The type of ir1 won't have changed --
169 * base types matched, and at least one of the operands of the 2
170 * binops is still a vector if any of them were.
171 */
172 update_type(ir2);
173
174 this->progress = true;
175 }
176
177 /**
178 * Reassociates a constant down a tree of adds or multiplies.
179 *
180 * Consider (2 * (a * (b * 0.5))). We want to end up with a * b.
181 */
182 bool
reassociate_constant(ir_expression * ir1,int const_index,ir_constant * constant,ir_expression * ir2)183 ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
184 ir_constant *constant,
185 ir_expression *ir2)
186 {
187 if (!ir2 || ir1->operation != ir2->operation)
188 return false;
189
190 /* Don't want to even think about matrices. */
191 if (glsl_type_is_matrix(ir1->operands[0]->type) ||
192 glsl_type_is_matrix(ir1->operands[1]->type) ||
193 glsl_type_is_matrix(ir2->operands[0]->type) ||
194 glsl_type_is_matrix(ir2->operands[1]->type))
195 return false;
196
197 void *mem_ctx = ralloc_parent(ir2);
198
199 ir_constant *ir2_const[2];
200 ir2_const[0] = ir2->operands[0]->constant_expression_value(mem_ctx);
201 ir2_const[1] = ir2->operands[1]->constant_expression_value(mem_ctx);
202
203 if (ir2_const[0] && ir2_const[1])
204 return false;
205
206 if (ir2_const[0]) {
207 reassociate_operands(ir1, const_index, ir2, 1);
208 return true;
209 } else if (ir2_const[1]) {
210 reassociate_operands(ir1, const_index, ir2, 0);
211 return true;
212 }
213
214 if (reassociate_constant(ir1, const_index, constant,
215 ir2->operands[0]->as_expression())) {
216 update_type(ir2);
217 return true;
218 }
219
220 if (reassociate_constant(ir1, const_index, constant,
221 ir2->operands[1]->as_expression())) {
222 update_type(ir2);
223 return true;
224 }
225
226 return false;
227 }
228
229 /* When eliminating an expression and just returning one of its operands,
230 * we may need to swizzle that operand out to a vector if the expression was
231 * vector type.
232 */
233 ir_rvalue *
swizzle_if_required(ir_expression * expr,ir_rvalue * operand)234 ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
235 ir_rvalue *operand)
236 {
237 if (glsl_type_is_vector(expr->type) && glsl_type_is_scalar(operand->type)) {
238 return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0,
239 expr->type->vector_elements);
240 } else
241 return operand;
242 }
243
244 ir_rvalue *
handle_expression(ir_expression * ir)245 ir_algebraic_visitor::handle_expression(ir_expression *ir)
246 {
247 ir_constant *op_const[4] = {NULL, NULL, NULL, NULL};
248 ir_expression *op_expr[4] = {NULL, NULL, NULL, NULL};
249
250 if (ir->operation == ir_binop_mul &&
251 glsl_type_is_matrix(ir->operands[0]->type) &&
252 glsl_type_is_vector(ir->operands[1]->type)) {
253 ir_expression *matrix_mul = ir->operands[0]->as_expression();
254
255 if (matrix_mul && matrix_mul->operation == ir_binop_mul &&
256 glsl_type_is_matrix(matrix_mul->operands[0]->type) &&
257 glsl_type_is_matrix(matrix_mul->operands[1]->type)) {
258
259 return mul(matrix_mul->operands[0],
260 mul(matrix_mul->operands[1], ir->operands[1]));
261 }
262 }
263
264 assert(ir->num_operands <= 4);
265 for (unsigned i = 0; i < ir->num_operands; i++) {
266 if (glsl_type_is_matrix(ir->operands[i]->type))
267 return ir;
268
269 op_const[i] =
270 ir->operands[i]->constant_expression_value(ralloc_parent(ir));
271 op_expr[i] = ir->operands[i]->as_expression();
272 }
273
274 if (this->mem_ctx == NULL)
275 this->mem_ctx = ralloc_parent(ir);
276
277 switch (ir->operation) {
278 case ir_binop_add:
279 /* Reassociate addition of constants so that we can do constant
280 * folding.
281 */
282 if (op_const[0] && !op_const[1])
283 reassociate_constant(ir, 0, op_const[0], op_expr[1]);
284 if (op_const[1] && !op_const[0])
285 reassociate_constant(ir, 1, op_const[1], op_expr[0]);
286
287 break;
288
289 case ir_binop_mul:
290 /* Reassociate multiplication of constants so that we can do
291 * constant folding.
292 */
293 if (op_const[0] && !op_const[1])
294 reassociate_constant(ir, 0, op_const[0], op_expr[1]);
295 if (op_const[1] && !op_const[0])
296 reassociate_constant(ir, 1, op_const[1], op_expr[0]);
297 break;
298
299 case ir_binop_min:
300 case ir_binop_max:
301 if (!glsl_type_is_float(ir->type))
302 break;
303
304 /* Replace min(max) operations and its commutative combinations with
305 * a saturate operation
306 */
307 for (int op = 0; op < 2; op++) {
308 ir_expression *inner_expr = op_expr[op];
309 ir_constant *outer_const = op_const[1 - op];
310 ir_expression_operation op_cond = (ir->operation == ir_binop_max) ?
311 ir_binop_min : ir_binop_max;
312
313 if (!inner_expr || !outer_const || (inner_expr->operation != op_cond))
314 continue;
315
316 /* One of these has to be a constant */
317 if (!inner_expr->operands[0]->as_constant() &&
318 !inner_expr->operands[1]->as_constant())
319 break;
320
321 /* Found a min(max) combination. Now try to see if its operands
322 * meet our conditions that we can do just a single saturate operation
323 */
324 for (int minmax_op = 0; minmax_op < 2; minmax_op++) {
325 ir_rvalue *x = inner_expr->operands[minmax_op];
326 ir_rvalue *y = inner_expr->operands[1 - minmax_op];
327
328 ir_constant *inner_const = y->as_constant();
329 if (!inner_const)
330 continue;
331
332 /* min(max(x, 0.0), 1.0) is sat(x) */
333 if (ir->operation == ir_binop_min &&
334 inner_const->is_zero() &&
335 outer_const->is_one())
336 return saturate(x);
337
338 /* max(min(x, 1.0), 0.0) is sat(x) */
339 if (ir->operation == ir_binop_max &&
340 inner_const->is_one() &&
341 outer_const->is_zero())
342 return saturate(x);
343
344 /* min(max(x, 0.0), b) where b < 1.0 is sat(min(x, b)) */
345 if (ir->operation == ir_binop_min &&
346 inner_const->is_zero() &&
347 is_less_than_one(outer_const))
348 return saturate(expr(ir_binop_min, x, outer_const));
349
350 /* max(min(x, b), 0.0) where b < 1.0 is sat(min(x, b)) */
351 if (ir->operation == ir_binop_max &&
352 is_less_than_one(inner_const) &&
353 outer_const->is_zero())
354 return saturate(expr(ir_binop_min, x, inner_const));
355
356 /* max(min(x, 1.0), b) where b > 0.0 is sat(max(x, b)) */
357 if (ir->operation == ir_binop_max &&
358 inner_const->is_one() &&
359 is_greater_than_zero(outer_const))
360 return saturate(expr(ir_binop_max, x, outer_const));
361
362 /* min(max(x, b), 1.0) where b > 0.0 is sat(max(x, b)) */
363 if (ir->operation == ir_binop_min &&
364 is_greater_than_zero(inner_const) &&
365 outer_const->is_one())
366 return saturate(expr(ir_binop_max, x, inner_const));
367 }
368 }
369
370 break;
371
372 /* Remove interpolateAt* instructions for demoted inputs. They are
373 * assigned a constant expression to facilitate this.
374 */
375 case ir_unop_interpolate_at_centroid:
376 case ir_binop_interpolate_at_offset:
377 case ir_binop_interpolate_at_sample:
378 if (op_const[0])
379 return ir->operands[0];
380 break;
381
382 default:
383 break;
384 }
385
386 return ir;
387 }
388
389 void
handle_rvalue(ir_rvalue ** rvalue)390 ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue)
391 {
392 if (!*rvalue)
393 return;
394
395 ir_expression *expr = (*rvalue)->as_expression();
396 if (!expr || expr->operation == ir_quadop_vector)
397 return;
398
399 ir_rvalue *new_rvalue = handle_expression(expr);
400 if (new_rvalue == *rvalue)
401 return;
402
403 /* If the expr used to be some vec OP scalar returning a vector, and the
404 * optimization gave us back a scalar, we still need to turn it into a
405 * vector.
406 */
407 *rvalue = swizzle_if_required(expr, new_rvalue);
408
409 this->progress = true;
410 }
411
412 bool
do_algebraic(exec_list * instructions,bool native_integers,const struct gl_shader_compiler_options * options)413 do_algebraic(exec_list *instructions, bool native_integers,
414 const struct gl_shader_compiler_options *options)
415 {
416 ir_algebraic_visitor v(native_integers, options);
417
418 visit_list_elements(&v, instructions);
419
420 return v.progress;
421 }
422