1 /*
2 * Copyright © 2014 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_minmax.cpp
26 *
27 * Drop operands from an expression tree of only min/max operations if they
28 * can be proven to not contribute to the final result.
29 *
30 * The algorithm is similar to alpha-beta pruning on a minmax search.
31 */
32
33 #include "ir.h"
34 #include "ir_visitor.h"
35 #include "ir_rvalue_visitor.h"
36 #include "ir_optimization.h"
37 #include "ir_builder.h"
38 #include "program/prog_instruction.h"
39 #include "compiler/glsl_types.h"
40 #include "main/macros.h"
41
42 using namespace ir_builder;
43
44 namespace {
45
46 enum compare_components_result {
47 LESS,
48 LESS_OR_EQUAL,
49 EQUAL,
50 GREATER_OR_EQUAL,
51 GREATER,
52 MIXED
53 };
54
55 class minmax_range {
56 public:
minmax_range(ir_constant * low=NULL,ir_constant * high=NULL)57 minmax_range(ir_constant *low = NULL, ir_constant *high = NULL)
58 {
59 this->low = low;
60 this->high = high;
61 }
62
63 /* low is the lower limit of the range, high is the higher limit. NULL on
64 * low means negative infinity (unlimited) and on high positive infinity
65 * (unlimited). Because of the two interpretations of the value NULL,
66 * arbitrary comparison between ir_constants is impossible.
67 */
68 ir_constant *low;
69 ir_constant *high;
70 };
71
72 class ir_minmax_visitor : public ir_rvalue_enter_visitor {
73 public:
ir_minmax_visitor()74 ir_minmax_visitor()
75 : progress(false)
76 {
77 }
78
79 ir_rvalue *prune_expression(ir_expression *expr, minmax_range baserange);
80
81 void handle_rvalue(ir_rvalue **rvalue);
82
83 bool progress;
84 };
85
86 /*
87 * Returns LESS if all vector components of `a' are strictly lower than of `b',
88 * GREATER if all vector components of `a' are strictly greater than of `b',
89 * MIXED if some vector components of `a' are strictly lower than of `b' while
90 * others are strictly greater, or EQUAL otherwise.
91 */
92 static enum compare_components_result
compare_components(ir_constant * a,ir_constant * b)93 compare_components(ir_constant *a, ir_constant *b)
94 {
95 assert(a != NULL);
96 assert(b != NULL);
97
98 assert(a->type->base_type == b->type->base_type);
99
100 unsigned a_inc = a->type->is_scalar() ? 0 : 1;
101 unsigned b_inc = b->type->is_scalar() ? 0 : 1;
102 unsigned components = MAX2(a->type->components(), b->type->components());
103
104 bool foundless = false;
105 bool foundgreater = false;
106 bool foundequal = false;
107
108 for (unsigned i = 0, c0 = 0, c1 = 0;
109 i < components;
110 c0 += a_inc, c1 += b_inc, ++i) {
111 switch (a->type->base_type) {
112 case GLSL_TYPE_UINT:
113 if (a->value.u[c0] < b->value.u[c1])
114 foundless = true;
115 else if (a->value.u[c0] > b->value.u[c1])
116 foundgreater = true;
117 else
118 foundequal = true;
119 break;
120 case GLSL_TYPE_INT:
121 if (a->value.i[c0] < b->value.i[c1])
122 foundless = true;
123 else if (a->value.i[c0] > b->value.i[c1])
124 foundgreater = true;
125 else
126 foundequal = true;
127 break;
128 case GLSL_TYPE_FLOAT:
129 if (a->value.f[c0] < b->value.f[c1])
130 foundless = true;
131 else if (a->value.f[c0] > b->value.f[c1])
132 foundgreater = true;
133 else
134 foundequal = true;
135 break;
136 case GLSL_TYPE_DOUBLE:
137 if (a->value.d[c0] < b->value.d[c1])
138 foundless = true;
139 else if (a->value.d[c0] > b->value.d[c1])
140 foundgreater = true;
141 else
142 foundequal = true;
143 break;
144 default:
145 unreachable("not reached");
146 }
147 }
148
149 if (foundless && foundgreater) {
150 /* Some components are strictly lower, others are strictly greater */
151 return MIXED;
152 }
153
154 if (foundequal) {
155 /* It is not mixed, but it is not strictly lower or greater */
156 if (foundless)
157 return LESS_OR_EQUAL;
158 if (foundgreater)
159 return GREATER_OR_EQUAL;
160 return EQUAL;
161 }
162
163 /* All components are strictly lower or strictly greater */
164 return foundless ? LESS : GREATER;
165 }
166
167 static ir_constant *
combine_constant(bool ismin,ir_constant * a,ir_constant * b)168 combine_constant(bool ismin, ir_constant *a, ir_constant *b)
169 {
170 void *mem_ctx = ralloc_parent(a);
171 ir_constant *c = a->clone(mem_ctx, NULL);
172 for (unsigned i = 0; i < c->type->components(); i++) {
173 switch (c->type->base_type) {
174 case GLSL_TYPE_UINT:
175 if ((ismin && b->value.u[i] < c->value.u[i]) ||
176 (!ismin && b->value.u[i] > c->value.u[i]))
177 c->value.u[i] = b->value.u[i];
178 break;
179 case GLSL_TYPE_INT:
180 if ((ismin && b->value.i[i] < c->value.i[i]) ||
181 (!ismin && b->value.i[i] > c->value.i[i]))
182 c->value.i[i] = b->value.i[i];
183 break;
184 case GLSL_TYPE_FLOAT:
185 if ((ismin && b->value.f[i] < c->value.f[i]) ||
186 (!ismin && b->value.f[i] > c->value.f[i]))
187 c->value.f[i] = b->value.f[i];
188 break;
189 case GLSL_TYPE_DOUBLE:
190 if ((ismin && b->value.d[i] < c->value.d[i]) ||
191 (!ismin && b->value.d[i] > c->value.d[i]))
192 c->value.d[i] = b->value.d[i];
193 break;
194 default:
195 assert(!"not reached");
196 }
197 }
198 return c;
199 }
200
201 static ir_constant *
smaller_constant(ir_constant * a,ir_constant * b)202 smaller_constant(ir_constant *a, ir_constant *b)
203 {
204 assert(a != NULL);
205 assert(b != NULL);
206
207 enum compare_components_result ret = compare_components(a, b);
208 if (ret == MIXED)
209 return combine_constant(true, a, b);
210 else if (ret < EQUAL)
211 return a;
212 else
213 return b;
214 }
215
216 static ir_constant *
larger_constant(ir_constant * a,ir_constant * b)217 larger_constant(ir_constant *a, ir_constant *b)
218 {
219 assert(a != NULL);
220 assert(b != NULL);
221
222 enum compare_components_result ret = compare_components(a, b);
223 if (ret == MIXED)
224 return combine_constant(false, a, b);
225 else if (ret < EQUAL)
226 return b;
227 else
228 return a;
229 }
230
231 /* Combines two ranges by doing an element-wise min() / max() depending on the
232 * operation.
233 */
234 static minmax_range
combine_range(minmax_range r0,minmax_range r1,bool ismin)235 combine_range(minmax_range r0, minmax_range r1, bool ismin)
236 {
237 minmax_range ret;
238
239 if (!r0.low) {
240 ret.low = ismin ? r0.low : r1.low;
241 } else if (!r1.low) {
242 ret.low = ismin ? r1.low : r0.low;
243 } else {
244 ret.low = ismin ? smaller_constant(r0.low, r1.low) :
245 larger_constant(r0.low, r1.low);
246 }
247
248 if (!r0.high) {
249 ret.high = ismin ? r1.high : r0.high;
250 } else if (!r1.high) {
251 ret.high = ismin ? r0.high : r1.high;
252 } else {
253 ret.high = ismin ? smaller_constant(r0.high, r1.high) :
254 larger_constant(r0.high, r1.high);
255 }
256
257 return ret;
258 }
259
260 /* Returns a range so that lower limit is the larger of the two lower limits,
261 * and higher limit is the smaller of the two higher limits.
262 */
263 static minmax_range
range_intersection(minmax_range r0,minmax_range r1)264 range_intersection(minmax_range r0, minmax_range r1)
265 {
266 minmax_range ret;
267
268 if (!r0.low)
269 ret.low = r1.low;
270 else if (!r1.low)
271 ret.low = r0.low;
272 else
273 ret.low = larger_constant(r0.low, r1.low);
274
275 if (!r0.high)
276 ret.high = r1.high;
277 else if (!r1.high)
278 ret.high = r0.high;
279 else
280 ret.high = smaller_constant(r0.high, r1.high);
281
282 return ret;
283 }
284
285 static minmax_range
get_range(ir_rvalue * rval)286 get_range(ir_rvalue *rval)
287 {
288 ir_expression *expr = rval->as_expression();
289 if (expr && (expr->operation == ir_binop_min ||
290 expr->operation == ir_binop_max)) {
291 minmax_range r0 = get_range(expr->operands[0]);
292 minmax_range r1 = get_range(expr->operands[1]);
293 return combine_range(r0, r1, expr->operation == ir_binop_min);
294 }
295
296 ir_constant *c = rval->as_constant();
297 if (c) {
298 return minmax_range(c, c);
299 }
300
301 return minmax_range();
302 }
303
304 /**
305 * Prunes a min/max expression considering the base range of the parent
306 * min/max expression.
307 *
308 * @param baserange the range that the parents of this min/max expression
309 * in the min/max tree will clamp its value to.
310 */
311 ir_rvalue *
prune_expression(ir_expression * expr,minmax_range baserange)312 ir_minmax_visitor::prune_expression(ir_expression *expr, minmax_range baserange)
313 {
314 assert(expr->operation == ir_binop_min ||
315 expr->operation == ir_binop_max);
316
317 bool ismin = expr->operation == ir_binop_min;
318 minmax_range limits[2];
319
320 /* Recurse to get the ranges for each of the subtrees of this
321 * expression. We need to do this as a separate step because we need to
322 * know the ranges of each of the subtrees before we prune either one.
323 * Consider something like this:
324 *
325 * max
326 * / \
327 * max max
328 * / \ / \
329 * 3 a b 2
330 *
331 * We would like to prune away the max on the bottom-right, but to do so
332 * we need to know the range of the expression on the left beforehand,
333 * and there's no guarantee that we will visit either subtree in a
334 * particular order.
335 */
336 for (unsigned i = 0; i < 2; ++i)
337 limits[i] = get_range(expr->operands[i]);
338
339 for (unsigned i = 0; i < 2; ++i) {
340 bool is_redundant = false;
341
342 enum compare_components_result cr = LESS;
343 if (ismin) {
344 /* If this operand will always be greater than the other one, it's
345 * redundant.
346 */
347 if (limits[i].low && limits[1 - i].high) {
348 cr = compare_components(limits[i].low, limits[1 - i].high);
349 if (cr >= EQUAL && cr != MIXED)
350 is_redundant = true;
351 }
352 /* If this operand is always greater than baserange, then even if
353 * it's smaller than the other one it'll get clamped, so it's
354 * redundant.
355 */
356 if (!is_redundant && limits[i].low && baserange.high) {
357 cr = compare_components(limits[i].low, baserange.high);
358 if (cr > EQUAL && cr != MIXED)
359 is_redundant = true;
360 }
361 } else {
362 /* If this operand will always be lower than the other one, it's
363 * redundant.
364 */
365 if (limits[i].high && limits[1 - i].low) {
366 cr = compare_components(limits[i].high, limits[1 - i].low);
367 if (cr <= EQUAL)
368 is_redundant = true;
369 }
370 /* If this operand is always lower than baserange, then even if
371 * it's greater than the other one it'll get clamped, so it's
372 * redundant.
373 */
374 if (!is_redundant && limits[i].high && baserange.low) {
375 cr = compare_components(limits[i].high, baserange.low);
376 if (cr < EQUAL)
377 is_redundant = true;
378 }
379 }
380
381 if (is_redundant) {
382 progress = true;
383
384 /* Recurse if necessary. */
385 ir_expression *op_expr = expr->operands[1 - i]->as_expression();
386 if (op_expr && (op_expr->operation == ir_binop_min ||
387 op_expr->operation == ir_binop_max)) {
388 return prune_expression(op_expr, baserange);
389 }
390
391 return expr->operands[1 - i];
392 } else if (cr == MIXED) {
393 /* If we have mixed vector operands, we can try to resolve the minmax
394 * expression by doing a component-wise minmax:
395 *
396 * min min
397 * / \ / \
398 * min a ===> [1,1] a
399 * / \
400 * [1,3] [3,1]
401 *
402 */
403 ir_constant *a = expr->operands[0]->as_constant();
404 ir_constant *b = expr->operands[1]->as_constant();
405 if (a && b)
406 return combine_constant(ismin, a, b);
407 }
408 }
409
410 /* Now recurse to operands giving them the proper baserange. The baserange
411 * to pass is the intersection of our baserange and the other operand's
412 * limit with one of the ranges unlimited. If we can't compute a valid
413 * intersection, we use the current baserange.
414 */
415 for (unsigned i = 0; i < 2; ++i) {
416 ir_expression *op_expr = expr->operands[i]->as_expression();
417 if (op_expr && (op_expr->operation == ir_binop_min ||
418 op_expr->operation == ir_binop_max)) {
419 /* We can only compute a new baserange for this operand if we managed
420 * to compute a valid range for the other operand.
421 */
422 if (ismin)
423 limits[1 - i].low = NULL;
424 else
425 limits[1 - i].high = NULL;
426 minmax_range base = range_intersection(limits[1 - i], baserange);
427 expr->operands[i] = prune_expression(op_expr, base);
428 }
429 }
430
431 /* If we got here we could not discard any of the operands of the minmax
432 * expression, but we can still try to resolve the expression if both
433 * operands are constant. We do this after the loop above, to make sure
434 * that if our operands are minmax expressions we have tried to prune them
435 * first (hopefully reducing them to constants).
436 */
437 ir_constant *a = expr->operands[0]->as_constant();
438 ir_constant *b = expr->operands[1]->as_constant();
439 if (a && b)
440 return combine_constant(ismin, a, b);
441
442 return expr;
443 }
444
445 static ir_rvalue *
swizzle_if_required(ir_expression * expr,ir_rvalue * rval)446 swizzle_if_required(ir_expression *expr, ir_rvalue *rval)
447 {
448 if (expr->type->is_vector() && rval->type->is_scalar()) {
449 return swizzle(rval, SWIZZLE_XXXX, expr->type->vector_elements);
450 } else {
451 return rval;
452 }
453 }
454
455 void
handle_rvalue(ir_rvalue ** rvalue)456 ir_minmax_visitor::handle_rvalue(ir_rvalue **rvalue)
457 {
458 if (!*rvalue)
459 return;
460
461 ir_expression *expr = (*rvalue)->as_expression();
462 if (!expr || (expr->operation != ir_binop_min &&
463 expr->operation != ir_binop_max))
464 return;
465
466 ir_rvalue *new_rvalue = prune_expression(expr, minmax_range());
467 if (new_rvalue == *rvalue)
468 return;
469
470 /* If the expression type is a vector and the optimization leaves a scalar
471 * as the result, we need to turn it into a vector.
472 */
473 *rvalue = swizzle_if_required(expr, new_rvalue);
474
475 progress = true;
476 }
477
478 }
479
480 bool
do_minmax_prune(exec_list * instructions)481 do_minmax_prune(exec_list *instructions)
482 {
483 ir_minmax_visitor v;
484
485 visit_list_elements(&v, instructions);
486
487 return v.progress;
488 }
489