From 586602c5d90a57717df9cf94ada3d66432ee4893 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 24 Jan 2018 20:23:15 +0800 Subject: [PATCH] nir/range-analysis: Range tracking for bcsel This could be squashed with the previous commit. I kept it separate to ease review. v2: Add some missing cases. Use nir_src_is_const helper. Both suggested by Caio. Use a table for mapping source ranges to a result range. Reviewed-by: Caio Marcelo de Oliveira Filho --- src/compiler/nir/nir_range_analysis.c | 77 +++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/compiler/nir/nir_range_analysis.c b/src/compiler/nir/nir_range_analysis.c index dac40ecb066..9555be3fa13 100644 --- a/src/compiler/nir/nir_range_analysis.c +++ b/src/compiler/nir/nir_range_analysis.c @@ -238,6 +238,83 @@ analyze_expression(const nir_alu_instr *instr, unsigned src, r = (struct ssa_result_range){ge_zero, alu->op == nir_op_b2f32}; break; + case nir_op_bcsel: { + const struct ssa_result_range left = analyze_expression(alu, 1, ht); + const struct ssa_result_range right = analyze_expression(alu, 2, ht); + + /* If either source is a constant load that is not zero, punt. The type + * will always be uint regardless of the actual type. We can't even + * decide if the value is non-zero because -0.0 is 0x80000000, and that + * will (possibly incorrectly) be considered non-zero. + */ + /* FINISHME: We could do better, but it would require having the expected + * FINISHME: type passed in. + */ + if ((nir_src_is_const(alu->src[1].src) && left.range != eq_zero) || + (nir_src_is_const(alu->src[2].src) && right.range != eq_zero)) { + return (struct ssa_result_range){unknown, false}; + } + + r.is_integral = left.is_integral && right.is_integral; + + /* le_zero: bcsel(, le_zero, lt_zero) + * | bcsel(, eq_zero, lt_zero) + * | bcsel(, le_zero, eq_zero) + * | bcsel(, lt_zero, le_zero) + * | bcsel(, lt_zero, eq_zero) + * | bcsel(, eq_zero, le_zero) + * | bcsel(, le_zero, le_zero) + * ; + * + * lt_zero: bcsel(, lt_zero, lt_zero) + * ; + * + * ge_zero: bcsel(, ge_zero, ge_zero) + * | bcsel(, ge_zero, gt_zero) + * | bcsel(, ge_zero, eq_zero) + * | bcsel(, gt_zero, ge_zero) + * | bcsel(, eq_zero, ge_zero) + * ; + * + * gt_zero: bcsel(, gt_zero, gt_zero) + * ; + * + * ne_zero: bcsel(, ne_zero, gt_zero) + * | bcsel(, ne_zero, lt_zero) + * | bcsel(, gt_zero, lt_zero) + * | bcsel(, gt_zero, ne_zero) + * | bcsel(, lt_zero, ne_zero) + * | bcsel(, lt_zero, gt_zero) + * | bcsel(, ne_zero, ne_zero) + * ; + * + * eq_zero: bcsel(, eq_zero, eq_zero) + * ; + * + * All other cases are 'unknown'. + * + * The ranges could be tightened if the range of the first source is + * known. However, opt_algebraic will (eventually) elminiate the bcsel + * if the condition is known. + */ + static const enum ssa_ranges table[last_range + 1][last_range + 1] = { + /* left\right unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */ + /* unknown */ { _______, _______, _______, _______, _______, _______, _______ }, + /* lt_zero */ { _______, lt_zero, le_zero, ne_zero, _______, ne_zero, le_zero }, + /* le_zero */ { _______, le_zero, le_zero, _______, _______, _______, le_zero }, + /* gt_zero */ { _______, ne_zero, _______, gt_zero, ge_zero, ne_zero, ge_zero }, + /* ge_zero */ { _______, _______, _______, ge_zero, ge_zero, _______, ge_zero }, + /* ne_zero */ { _______, ne_zero, _______, ne_zero, _______, ne_zero, _______ }, + /* eq_zero */ { _______, le_zero, le_zero, ge_zero, ge_zero, _______, eq_zero }, + }; + + ASSERT_TABLE_IS_COMMUTATIVE(table); + ASSERT_TABLE_IS_DIAGONAL(table); + + r.range = table[left.range][right.range]; + break; + } + case nir_op_i2f32: case nir_op_u2f32: r = analyze_expression(alu, 0, ht); -- 2.30.2