{ return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
};
-class operator_bitwise_xor : public range_operator
-{
-public:
- using range_operator::op1_range;
- using range_operator::op2_range;
- using range_operator::op1_op2_relation_effect;
- using range_operator::update_bitmask;
- bool op1_range (irange &r, tree type,
- const irange &lhs, const irange &op2,
- relation_trio rel = TRIO_VARYING) const final override;
- bool op2_range (irange &r, tree type,
- const irange &lhs, const irange &op1,
- relation_trio rel = TRIO_VARYING) const final override;
- bool op1_op2_relation_effect (irange &lhs_range,
- tree type,
- const irange &op1_range,
- const irange &op2_range,
- relation_kind rel) const final override;
- void update_bitmask (irange &r, const irange &lh,
- const irange &rh) const final override;
- // Check compatibility of all operands.
- bool operand_check_p (tree t1, tree t2, tree t3) const final override
- { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
-private:
- void wi_fold (irange &r, tree type, const wide_int &lh_lb,
- const wide_int &lh_ub, const wide_int &rh_lb,
- const wide_int &rh_ub) const final override;
-};
-
class operator_bitwise_and : public range_operator
{
public:
const wide_int &rh_ub) const override;
};
+class operator_bitwise_xor : public range_operator
+{
+public:
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
+ using range_operator::op1_op2_relation_effect;
+ using range_operator::update_bitmask;
+ bool fold_range (irange &r, tree type,
+ const irange &lh, const irange &rh,
+ relation_trio rel = TRIO_VARYING) const final override;
+ bool op1_range (irange &r, tree type,
+ const irange &lhs, const irange &op2,
+ relation_trio rel = TRIO_VARYING) const final override;
+ bool op2_range (irange &r, tree type,
+ const irange &lhs, const irange &op1,
+ relation_trio rel = TRIO_VARYING) const final override;
+ bool op1_op2_relation_effect (irange &lhs_range,
+ tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const final override;
+ void update_bitmask (irange &r, const irange &lh,
+ const irange &rh) const final override;
+ // Check compatibility of all operands.
+ bool operand_check_p (tree t1, tree t2, tree t3) const final override
+ { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+private:
+ void wi_fold (irange &r, tree type, const wide_int &lh_lb,
+ const wide_int &lh_ub, const wide_int &rh_lb,
+ const wide_int &rh_ub) const final override;
+ class operator_bitwise_and m_and;
+ class operator_bitwise_or m_or;
+ class operator_bitwise_not m_not;
+};
+
+
class operator_min : public range_operator
{
public:
update_known_bitmask (r, BIT_XOR_EXPR, lh, rh);
}
+bool
+operator_bitwise_xor::fold_range (irange &r, tree type,
+ const irange &lh, const irange &rh,
+ relation_trio rel) const
+{
+ // Handle X ^ UNDEFINED = UNDEFINED.
+ if (lh.undefined_p () || rh.undefined_p ())
+ {
+ r.set_undefined ();
+ return true;
+ }
+
+ // Next, handle X ^ X == [0, 0].
+ if (rel.op1_op2 () == VREL_EQ)
+ {
+ r.set_zero (type);
+ return true;
+ }
+
+ // If either operand is VARYING, the result is VARYING.
+ if (lh.varying_p () || rh.varying_p ())
+ {
+ // If the operands are not equal, zero is not possible.
+ if (rel.op1_op2 () != VREL_NE)
+ r.set_varying (type);
+ else
+ r.set_nonzero (type);
+ return true;
+ }
+
+ // Now deal with X ^ 0 == X.
+ if (lh.zero_p ())
+ {
+ r = rh;
+ return true;
+ }
+ if (rh.zero_p ())
+ {
+ r = lh;
+ return true;
+ }
+
+ // Start with the legacy range. This can sometimes pick up values
+ // when there are a lot of subranges and fold_range aggregates them.
+ bool res = range_operator::fold_range (r, type, lh, rh, rel);
+
+ // Calculate the XOR identity : x ^ y = (x | y) & ~(x & y)
+ // AND and OR are already much better optimized.
+ int_range_max tmp1, tmp2, tmp3, new_result;
+ int_range<2> varying;
+ varying.set_varying (type);
+
+ if (m_or.fold_range (tmp1, type, lh, rh, rel)
+ && m_and.fold_range (tmp2, type, lh, rh, rel)
+ && m_not.fold_range (tmp3, type, tmp2, varying, rel)
+ && m_and.fold_range (new_result, type, tmp1, tmp3, rel))
+ {
+ // If the operands are not equal, or the LH does not contain any
+ // element of the RH, zero is not possible.
+ tmp1 = lh;
+ if (rel.op1_op2 () == VREL_NE
+ || (tmp1.intersect (rh) && tmp1.undefined_p ()))
+ {
+ tmp1.set_nonzero (type);
+ new_result.intersect (tmp1);
+ }
+
+ // Combine with the legacy range if there was one.
+ if (res)
+ r.intersect (new_result);
+ else
+ r = new_result;
+ return true;
+ }
+ return res;
+}
+
void
operator_bitwise_xor::wi_fold (irange &r, tree type,
const wide_int &lh_lb,