diff options
Diffstat (limited to 'gcc/range-op.cc')
-rw-r--r-- | gcc/range-op.cc | 144 |
1 files changed, 99 insertions, 45 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 35b3e18..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), @@ -761,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 @@ -817,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; } @@ -836,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 { } @@ -1777,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 @@ -2423,7 +2455,7 @@ class operator_div : public cross_product_operator 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; + relation_trio) const final override; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2432,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; @@ -3201,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); } @@ -3311,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; @@ -3678,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; } @@ -3705,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); } @@ -4151,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); } @@ -4432,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; |