diff options
Diffstat (limited to 'gcc/range-op.cc')
-rw-r--r-- | gcc/range-op.cc | 162 |
1 files changed, 118 insertions, 44 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc index f72b4ae..1f91066 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -97,6 +97,8 @@ range_op_table::range_op_table () set (INTEGER_CST, op_cst); set (NOP_EXPR, op_cast); set (CONVERT_EXPR, op_cast); + set (FLOAT_EXPR, op_cast); + set (FIX_TRUNC_EXPR, op_cast); set (PLUS_EXPR, op_plus); set (ABS_EXPR, op_abs); set (MINUS_EXPR, op_minus); @@ -164,6 +166,8 @@ dispatch_trio (unsigned lhs, unsigned op1, unsigned op2) // These are the supported dispatch patterns. These map to the parameter list // of the routines in range_operator. Note the last 3 characters are // shorthand for the LHS, OP1, and OP2 range discriminator class. +// Reminder, single operand instructions use the LHS type for op2, even if +// unused. So FLOAT = INT would be RO_FIF. const unsigned RO_III = dispatch_trio (VR_IRANGE, VR_IRANGE, VR_IRANGE); const unsigned RO_IFI = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_IRANGE); @@ -246,6 +250,10 @@ range_op_handler::fold_range (vrange &r, tree type, return m_operator->fold_range (as_a <frange> (r), type, as_a <irange> (lh), as_a <irange> (rh), rel); + case RO_FIF: + return m_operator->fold_range (as_a <frange> (r), type, + as_a <irange> (lh), + as_a <frange> (rh), rel); case RO_PPP: return m_operator->fold_range (as_a <prange> (r), type, as_a <prange> (lh), @@ -292,6 +300,10 @@ range_op_handler::op1_range (vrange &r, tree type, return m_operator->op1_range (as_a <irange> (r), type, as_a <irange> (lhs), as_a <irange> (op2), rel); + case RO_IFI: + return m_operator->op1_range (as_a <irange> (r), type, + as_a <frange> (lhs), + as_a <irange> (op2), rel); case RO_PPP: return m_operator->op1_range (as_a <prange> (r), type, as_a <prange> (lhs), @@ -390,6 +402,10 @@ range_op_handler::lhs_op1_relation (const vrange &lhs, return m_operator->lhs_op1_relation (as_a <prange> (lhs), as_a <irange> (op1), as_a <irange> (op2), rel); + case RO_PPI: + return m_operator->lhs_op1_relation (as_a <prange> (lhs), + as_a <prange> (op1), + as_a <irange> (op2), rel); case RO_IFF: return m_operator->lhs_op1_relation (as_a <irange> (lhs), as_a <frange> (op1), @@ -757,6 +773,23 @@ range_operator::fold_range (irange &r, tree type, return true; } + +bool +range_operator::fold_range (frange &, tree, const irange &, + const frange &, relation_trio) const +{ + return false; +} + +bool +range_operator::op1_range (irange &, tree, const frange &, + const irange &, relation_trio) const +{ + return false; +} + + + // The default for op1_range is to return false. bool @@ -813,10 +846,13 @@ range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, bool range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - const irange &op1_range ATTRIBUTE_UNUSED, - const irange &op2_range ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + tree type ATTRIBUTE_UNUSED, + const irange &op1_range + ATTRIBUTE_UNUSED, + const irange &op2_range + ATTRIBUTE_UNUSED, + relation_kind rel + ATTRIBUTE_UNUSED) const { return false; } @@ -832,7 +868,7 @@ range_operator::overflow_free_p (const irange &, const irange &, void range_operator::update_bitmask (irange &, const irange &, - const irange &) const + const irange &) const { } @@ -1773,7 +1809,7 @@ operator_plus::wi_fold (irange &r, tree type, static relation_kind plus_minus_ranges (irange &r_ov, irange &r_normal, const irange &offset, - bool add_p) + bool add_p) { relation_kind kind = VREL_VARYING; // For now, only deal with constant adds. This could be extended to ranges @@ -2415,8 +2451,11 @@ operator_widen_mult_unsigned::wi_fold (irange &r, tree type, class operator_div : public cross_product_operator { using range_operator::update_bitmask; + using range_operator::op2_range; public: operator_div (tree_code div_kind) { m_code = div_kind; } + bool op2_range (irange &r, tree type, const irange &lhs, const irange &, + relation_trio) const final override; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2425,7 +2464,8 @@ public: virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &, const wide_int &) const final override; - void update_bitmask (irange &r, const irange &lh, const irange &rh) const + void update_bitmask (irange &r, const irange &lh, const irange &rh) + const final override { update_known_bitmask (r, m_code, lh, rh); } protected: tree_code m_code; @@ -2436,6 +2476,19 @@ static operator_div op_floor_div (FLOOR_DIV_EXPR); static operator_div op_round_div (ROUND_DIV_EXPR); static operator_div op_ceil_div (CEIL_DIV_EXPR); +// Set OP2 to non-zero if the LHS isn't UNDEFINED. +bool +operator_div::op2_range (irange &r, tree type, const irange &lhs, + const irange &, relation_trio) const +{ + if (!lhs.undefined_p ()) + { + r.set_nonzero (type); + return true; + } + return false; +} + bool operator_div::wi_op_overflows (wide_int &res, tree type, const wide_int &w0, const wide_int &w1) const @@ -3181,18 +3234,18 @@ class operator_logical_and : public range_operator using range_operator::op1_range; using range_operator::op2_range; public: - virtual bool fold_range (irange &r, tree type, - const irange &lh, - const irange &rh, - relation_trio rel = TRIO_VARYING) const; - virtual bool op1_range (irange &r, tree type, - const irange &lhs, - const irange &op2, - relation_trio rel = TRIO_VARYING) const; - virtual bool op2_range (irange &r, tree type, - const irange &lhs, - const irange &op1, - relation_trio rel = TRIO_VARYING) const; + 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; // 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); } @@ -3291,9 +3344,9 @@ wi_optimize_signed_bitwise_op (irange &r, tree type, relation_kind operator_bitwise_and::lhs_op1_relation (const irange &lhs, - const irange &op1, - const irange &op2, - relation_kind) const + const irange &op1, + const irange &op2, + relation_kind) const { if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ()) return VREL_VARYING; @@ -3658,14 +3711,34 @@ operator_bitwise_and::op1_range (irange &r, tree type, return true; } + if (!op2.singleton_p (mask)) + return true; + // For 0 = op1 & MASK, op1 is ~MASK. - if (lhs.zero_p () && op2.singleton_p ()) + if (lhs.zero_p ()) { wide_int nz = wi::bit_not (op2.get_nonzero_bits ()); int_range<2> tmp (type); tmp.set_nonzero_bits (nz); r.intersect (tmp); } + + irange_bitmask lhs_bm = lhs.get_bitmask (); + // given [5,7] mask 0x3 value 0x4 = N & [7, 7] mask 0x0 value 0x7 + // Nothing is known about the bits not specified in the mask value (op2), + // Start with the mask, 1's will occur where values were masked. + wide_int op1_mask = ~mask; + // Any bits that are unknown on the LHS are also unknown in op1, + // so union the current mask with the LHS mask. + op1_mask |= lhs_bm.mask (); + // The resulting zeros correspond to known bits in the LHS mask, and + // the LHS value should tell us what they are. Mask off any + // extraneous values thats are not convered by the mask. + wide_int op1_value = lhs_bm.value () & ~op1_mask; + irange_bitmask op1_bm (op1_value, op1_mask); + // INtersect this mask with anything already known about the value. + op1_bm.intersect (r.get_bitmask ()); + r.update_bitmask (op1_bm); return true; } @@ -3685,18 +3758,18 @@ class operator_logical_or : public range_operator using range_operator::op1_range; using range_operator::op2_range; public: - virtual bool fold_range (irange &r, tree type, - const irange &lh, - const irange &rh, - relation_trio rel = TRIO_VARYING) const; - virtual bool op1_range (irange &r, tree type, - const irange &lhs, - const irange &op2, - relation_trio rel = TRIO_VARYING) const; - virtual bool op2_range (irange &r, tree type, - const irange &lhs, - const irange &op1, - relation_trio rel = TRIO_VARYING) const; + 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; // 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); } @@ -4131,14 +4204,14 @@ class operator_logical_not : public range_operator using range_operator::fold_range; using range_operator::op1_range; public: - virtual bool fold_range (irange &r, tree type, - const irange &lh, - const irange &rh, - relation_trio rel = TRIO_VARYING) const; - virtual bool op1_range (irange &r, tree type, - const irange &lhs, - const irange &op2, - relation_trio rel = TRIO_VARYING) const; + 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; // Check compatibility of LHS and op1. bool operand_check_p (tree t1, tree t2, tree) const final override { return range_compatible_p (t1, t2); } @@ -4412,7 +4485,8 @@ class operator_absu : public range_operator public: virtual 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; + const wide_int &rh_lb, const wide_int &rh_ub) + const final override; virtual void update_bitmask (irange &r, const irange &lh, const irange &rh) const final override; } op_absu; |