Implement POINTER_DIFF_EXPR entry in range-op.

I've seen cases in the upcoming jump threader enhancements where we see
a difference of two pointers that are known to be equivalent, and yet we
fail to return 0 for the range.  This is because we have no working
range-op entry for POINTER_DIFF_EXPR.  The entry we currently have is
a mere placeholder to avoid ignoring POINTER_DIFF_EXPR's so
adjust_pointer_diff_expr() could get a whack at it here:

//	def = __builtin_memchr (arg, 0, sz)
//	n = def - arg
//
// The range for N can be narrowed to [0, PTRDIFF_MAX - 1].

This patch adds the relational magic to range-op, which we can just
steal from the minus_expr code.

gcc/ChangeLog:

	* range-op.cc (operator_minus::op1_op2_relation_effect): Abstract
	out to...
	(minus_op1_op2_relation_effect): ...here.
	(class operator_pointer_diff): New.
	(operator_pointer_diff::op1_op2_relation_effect): Call
	minus_op1_op2_relation_effect.
	(integral_table::integral_table): Add entry for POINTER_DIFF_EXPR.
This commit is contained in:
Aldy Hernandez 2021-09-03 10:01:25 +02:00
parent 47543e5f9d
commit 8af8abfbba

View File

@ -1372,13 +1372,14 @@ operator_minus::wi_fold (irange &r, tree type,
}
// Check to see if the relation REL between OP1 and OP2 has any effect on the
// LHS of the expression. If so, apply it to LHS_RANGE.
// LHS of the expression. If so, apply it to LHS_RANGE. This is a helper
// function for both MINUS_EXPR and POINTER_DIFF_EXPR.
bool
operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type,
const irange &op1_range ATTRIBUTE_UNUSED,
const irange &op2_range ATTRIBUTE_UNUSED,
relation_kind rel) const
static bool
minus_op1_op2_relation_effect (irange &lhs_range, tree type,
const irange &op1_range ATTRIBUTE_UNUSED,
const irange &op2_range ATTRIBUTE_UNUSED,
relation_kind rel)
{
if (rel == VREL_NONE)
return false;
@ -1440,6 +1441,16 @@ operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type,
return true;
}
bool
operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type,
const irange &op1_range,
const irange &op2_range,
relation_kind rel) const
{
return minus_op1_op2_relation_effect (lhs_range, type, op1_range, op2_range,
rel);
}
bool
operator_minus::op1_range (irange &r, tree type,
const irange &lhs,
@ -1459,6 +1470,26 @@ operator_minus::op2_range (irange &r, tree type,
}
class operator_pointer_diff : public range_operator
{
virtual bool op1_op2_relation_effect (irange &lhs_range,
tree type,
const irange &op1_range,
const irange &op2_range,
relation_kind rel) const;
} op_pointer_diff;
bool
operator_pointer_diff::op1_op2_relation_effect (irange &lhs_range, tree type,
const irange &op1_range,
const irange &op2_range,
relation_kind rel) const
{
return minus_op1_op2_relation_effect (lhs_range, type, op1_range, op2_range,
rel);
}
class operator_min : public range_operator
{
public:
@ -4018,7 +4049,7 @@ integral_table::integral_table ()
set (OBJ_TYPE_REF, op_identity);
set (IMAGPART_EXPR, op_unknown);
set (REALPART_EXPR, op_unknown);
set (POINTER_DIFF_EXPR, op_unknown);
set (POINTER_DIFF_EXPR, op_pointer_diff);
set (ABS_EXPR, op_abs);
set (ABSU_EXPR, op_absu);
set (NEGATE_EXPR, op_negate);