summaryrefslogtreecommitdiffstats
path: root/src/compiler/nir
diff options
context:
space:
mode:
authorIan Romanick <[email protected]>2018-01-24 20:23:15 +0800
committerIan Romanick <[email protected]>2019-08-05 20:14:13 -0700
commit586602c5d90a57717df9cf94ada3d66432ee4893 (patch)
tree64d15d40918c8e1ece9e915d64ff0c1f8601e668 /src/compiler/nir
parent3009cbed5053150fbee351ee7b9f61d3aaf6794b (diff)
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 <[email protected]>
Diffstat (limited to 'src/compiler/nir')
-rw-r--r--src/compiler/nir/nir_range_analysis.c77
1 files changed, 77 insertions, 0 deletions
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(<any>, le_zero, lt_zero)
+ * | bcsel(<any>, eq_zero, lt_zero)
+ * | bcsel(<any>, le_zero, eq_zero)
+ * | bcsel(<any>, lt_zero, le_zero)
+ * | bcsel(<any>, lt_zero, eq_zero)
+ * | bcsel(<any>, eq_zero, le_zero)
+ * | bcsel(<any>, le_zero, le_zero)
+ * ;
+ *
+ * lt_zero: bcsel(<any>, lt_zero, lt_zero)
+ * ;
+ *
+ * ge_zero: bcsel(<any>, ge_zero, ge_zero)
+ * | bcsel(<any>, ge_zero, gt_zero)
+ * | bcsel(<any>, ge_zero, eq_zero)
+ * | bcsel(<any>, gt_zero, ge_zero)
+ * | bcsel(<any>, eq_zero, ge_zero)
+ * ;
+ *
+ * gt_zero: bcsel(<any>, gt_zero, gt_zero)
+ * ;
+ *
+ * ne_zero: bcsel(<any>, ne_zero, gt_zero)
+ * | bcsel(<any>, ne_zero, lt_zero)
+ * | bcsel(<any>, gt_zero, lt_zero)
+ * | bcsel(<any>, gt_zero, ne_zero)
+ * | bcsel(<any>, lt_zero, ne_zero)
+ * | bcsel(<any>, lt_zero, gt_zero)
+ * | bcsel(<any>, ne_zero, ne_zero)
+ * ;
+ *
+ * eq_zero: bcsel(<any>, 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);