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);