[gcc r15-154] Implement pointer_plus_operator for prange.
Aldy Hernandez
aldyh@gcc.gnu.org
Sat May 4 08:28:28 GMT 2024
https://gcc.gnu.org/g:86ff3c45ea82452888244476f26a4f628b148ace
commit r15-154-g86ff3c45ea82452888244476f26a4f628b148ace
Author: Aldy Hernandez <aldyh@redhat.com>
Date: Wed Mar 20 10:04:41 2024 +0100
Implement pointer_plus_operator for prange.
gcc/ChangeLog:
* range-op-ptr.cc (class pointer_plus_operator): Add overloaded declarations
for pointer variants.
(pointer_plus_operator::fold_range): New.
(pointer_plus_operator::op2_range): New.
(pointer_plus_operator::pointers_handled_p): New.
Diff:
---
gcc/range-op-ptr.cc | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 38d9f65566f..a4418215613 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -265,8 +265,17 @@ range_operator::update_bitmask (irange &,
class pointer_plus_operator : public range_operator
{
using range_operator::update_bitmask;
+ using range_operator::fold_range;
using range_operator::op2_range;
public:
+ virtual bool fold_range (prange &r, tree type,
+ const prange &op1,
+ const irange &op2,
+ relation_trio) const final override;
+ virtual bool op2_range (irange &r, tree type,
+ const prange &lhs,
+ const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -276,10 +285,99 @@ public:
const irange &lhs,
const irange &op1,
relation_trio = TRIO_VARYING) const;
+ bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
void update_bitmask (irange &r, const irange &lh, const irange &rh) const
{ update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); }
} op_pointer_plus;
+bool
+pointer_plus_operator::fold_range (prange &r, tree type,
+ const prange &op1,
+ const irange &op2,
+ relation_trio) const
+{
+ if (empty_range_varying (r, type, op1, op2))
+ return true;
+
+ const wide_int lh_lb = op1.lower_bound ();
+ const wide_int lh_ub = op1.upper_bound ();
+ const wide_int rh_lb = op2.lower_bound ();
+ const wide_int rh_ub = op2.upper_bound ();
+
+ // Check for [0,0] + const, and simply return the const.
+ if (lh_lb == 0 && lh_ub == 0 && rh_lb == rh_ub)
+ {
+ r.set (type, rh_lb, rh_lb);
+ return true;
+ }
+
+ // For pointer types, we are really only interested in asserting
+ // whether the expression evaluates to non-NULL.
+ //
+ // With -fno-delete-null-pointer-checks we need to be more
+ // conservative. As some object might reside at address 0,
+ // then some offset could be added to it and the same offset
+ // subtracted again and the result would be NULL.
+ // E.g.
+ // static int a[12]; where &a[0] is NULL and
+ // ptr = &a[6];
+ // ptr -= 6;
+ // ptr will be NULL here, even when there is POINTER_PLUS_EXPR
+ // where the first range doesn't include zero and the second one
+ // doesn't either. As the second operand is sizetype (unsigned),
+ // consider all ranges where the MSB could be set as possible
+ // subtractions where the result might be NULL.
+ if ((!wi_includes_zero_p (type, lh_lb, lh_ub)
+ || !wi_includes_zero_p (type, rh_lb, rh_ub))
+ && !TYPE_OVERFLOW_WRAPS (type)
+ && (flag_delete_null_pointer_checks
+ || !wi::sign_mask (rh_ub)))
+ r.set_nonzero (type);
+ else if (lh_lb == lh_ub && lh_lb == 0
+ && rh_lb == rh_ub && rh_lb == 0)
+ r.set_zero (type);
+ else
+ r.set_varying (type);
+
+ update_known_bitmask (r, POINTER_PLUS_EXPR, op1, op2);
+ return true;
+}
+
+bool
+pointer_plus_operator::op2_range (irange &r, tree type,
+ const prange &lhs ATTRIBUTE_UNUSED,
+ const prange &op1 ATTRIBUTE_UNUSED,
+ relation_trio trio) const
+{
+ relation_kind rel = trio.lhs_op1 ();
+ r.set_varying (type);
+
+ // If the LHS and OP1 are equal, the op2 must be zero.
+ if (rel == VREL_EQ)
+ r.set_zero (type);
+ // If the LHS and OP1 are not equal, the offset must be non-zero.
+ else if (rel == VREL_NE)
+ r.set_nonzero (type);
+ else
+ return false;
+ return true;
+}
+
+bool
+pointer_plus_operator::pointers_handled_p (range_op_dispatch_type type,
+ unsigned dispatch) const
+{
+ switch (type)
+ {
+ case DISPATCH_FOLD_RANGE:
+ return dispatch == RO_PPI;
+ case DISPATCH_OP2_RANGE:
+ return dispatch == RO_IPP;
+ default:
+ return true;
+ }
+}
+
void
pointer_plus_operator::wi_fold (irange &r, tree type,
const wide_int &lh_lb,
More information about the Gcc-cvs
mailing list