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