Move common code from range-op.cc to header files.
In preparation for the agnostication of ranger, this patch moves common code that can be shared between non-integer ranges (initially pointers) into the relevant header files. This is a relatively non-invasive change, as any changes that would need to be ported to GCC 12, would occur in the range-op entries themselves, not in the supporting glue which I'm moving. Tested and benchmarked on x86-64 Linux. gcc/ChangeLog: * range-op.cc (empty_range_varying): Move to range-op.h. (range_true): Move to range.h. (range_false): Same. (range_true_and_false): Same. (enum bool_range_state): Move to range-op.h. (relop_early_resolve): Same. (operator_equal::op1_op2_relation): Abstract code to... (equal_op1_op2_relation): ...here. (operator_not_equal::op1_op2_relation): Abstract code to... (not_equal_op1_op2_relation): ...here. (operator_lt::op1_op2_relation): Abstract code to... (lt_op1_op2_relation): ...here. (operator_le::op1_op2_relation): Abstract code to... (le_op1_op2_relation): ...here. (operator_gt::op1_op2_relation): Abstract code to... (gt_op1_op2_relation): ...here. (operator_ge::op1_op2_relation): Abstract code to... (ge_op1_op2_relation): ...here. (class range_op_table): Move to range-op.h. * range-op.h (equal_op1_op2_relation): Moved from range-op.cc. (not_equal_op1_op2_relation): Same. (lt_op1_op2_relation): Same. (le_op1_op2_relation): Same. (gt_op1_op2_relation): Same. (ge_op1_op2_relation): Same. (enum bool_range_state): Same. (get_bool_state): Same. (empty_range_varying): Same. (relop_early_resolve): Same. (class range_op_table): Same. * range.h (range_true): Same. (range_false): Same. (range_true_and_false): Same.
This commit is contained in:
parent
c13fd1b8fd
commit
9eb38e88ce
140
gcc/range-op.cc
140
gcc/range-op.cc
|
@ -63,24 +63,6 @@ min_limit (const_tree type)
|
|||
return wi::min_value (TYPE_PRECISION (type) , TYPE_SIGN (type));
|
||||
}
|
||||
|
||||
// If the range of either op1 or op2 is undefined, set the result to
|
||||
// varying and return TRUE. If the caller truely cares about a result,
|
||||
// they should pass in a varying if it has an undefined that it wants
|
||||
// treated as a varying.
|
||||
|
||||
inline bool
|
||||
empty_range_varying (irange &r, tree type,
|
||||
const irange &op1, const irange & op2)
|
||||
{
|
||||
if (op1.undefined_p () || op2.undefined_p ())
|
||||
{
|
||||
r.set_varying (type);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return false if shifting by OP is undefined behavior. Otherwise, return
|
||||
// true and the range it is to be shifted by. This allows trimming out of
|
||||
// undefined ranges, leaving only valid ranges if there are any.
|
||||
|
@ -432,39 +414,10 @@ create_possibly_reversed_range (irange &r, tree type,
|
|||
r.set (wide_int_to_tree (type, new_lb), wide_int_to_tree (type, new_ub));
|
||||
}
|
||||
|
||||
// Return an irange instance that is a boolean TRUE.
|
||||
|
||||
static inline int_range<1>
|
||||
range_true (tree type)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
return int_range<1> (type, wi::one (prec), wi::one (prec));
|
||||
}
|
||||
|
||||
// Return an irange instance that is a boolean FALSE.
|
||||
|
||||
static inline int_range<1>
|
||||
range_false (tree type)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
return int_range<1> (type, wi::zero (prec), wi::zero (prec));
|
||||
}
|
||||
|
||||
// Return an irange that covers both true and false.
|
||||
|
||||
static inline int_range<1>
|
||||
range_true_and_false (tree type)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
return int_range<1> (type, wi::zero (prec), wi::one (prec));
|
||||
}
|
||||
|
||||
enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
|
||||
|
||||
// Return the summary information about boolean range LHS. If EMPTY/FULL,
|
||||
// return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing.
|
||||
|
||||
static bool_range_state
|
||||
bool_range_state
|
||||
get_bool_state (irange &r, const irange &lhs, tree val_type)
|
||||
{
|
||||
// If there is no result, then this is unexecutable.
|
||||
|
@ -488,37 +441,6 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
|
|||
return BRS_TRUE;
|
||||
}
|
||||
|
||||
// For relation opcodes, first try to see if the supplied relation
|
||||
// forces a true or false result, and return that.
|
||||
// Then check for undefined operands. If none of this applies,
|
||||
// return false.
|
||||
|
||||
static inline bool
|
||||
relop_early_resolve (irange &r, tree type, const irange &op1,
|
||||
const irange &op2, relation_kind rel,
|
||||
relation_kind my_rel)
|
||||
{
|
||||
// If known relation is a complete subset of this relation, always true.
|
||||
if (relation_union (rel, my_rel) == my_rel)
|
||||
{
|
||||
r = range_true (type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If known relation has no subset of this relation, always false.
|
||||
if (relation_intersect (rel, my_rel) == VREL_EMPTY)
|
||||
{
|
||||
r = range_false (type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If either operand is undefined, return VARYING.
|
||||
if (empty_range_varying (r, type, op1, op2))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class operator_equal : public range_operator
|
||||
{
|
||||
|
@ -541,7 +463,7 @@ public:
|
|||
// Check if the LHS range indicates a relation between OP1 and OP2.
|
||||
|
||||
enum tree_code
|
||||
operator_equal::op1_op2_relation (const irange &lhs) const
|
||||
equal_op1_op2_relation (const irange &lhs)
|
||||
{
|
||||
if (lhs.undefined_p ())
|
||||
return VREL_EMPTY;
|
||||
|
@ -556,6 +478,12 @@ operator_equal::op1_op2_relation (const irange &lhs) const
|
|||
return VREL_NONE;
|
||||
}
|
||||
|
||||
enum tree_code
|
||||
operator_equal::op1_op2_relation (const irange &lhs) const
|
||||
{
|
||||
return equal_op1_op2_relation (lhs);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
operator_equal::fold_range (irange &r, tree type,
|
||||
|
@ -651,7 +579,7 @@ public:
|
|||
// Check if the LHS range indicates a relation between OP1 and OP2.
|
||||
|
||||
enum tree_code
|
||||
operator_not_equal::op1_op2_relation (const irange &lhs) const
|
||||
not_equal_op1_op2_relation (const irange &lhs)
|
||||
{
|
||||
if (lhs.undefined_p ())
|
||||
return VREL_EMPTY;
|
||||
|
@ -666,6 +594,12 @@ operator_not_equal::op1_op2_relation (const irange &lhs) const
|
|||
return VREL_NONE;
|
||||
}
|
||||
|
||||
enum tree_code
|
||||
operator_not_equal::op1_op2_relation (const irange &lhs) const
|
||||
{
|
||||
return not_equal_op1_op2_relation (lhs);
|
||||
}
|
||||
|
||||
bool
|
||||
operator_not_equal::fold_range (irange &r, tree type,
|
||||
const irange &op1,
|
||||
|
@ -821,7 +755,7 @@ public:
|
|||
// Check if the LHS range indicates a relation between OP1 and OP2.
|
||||
|
||||
enum tree_code
|
||||
operator_lt::op1_op2_relation (const irange &lhs) const
|
||||
lt_op1_op2_relation (const irange &lhs)
|
||||
{
|
||||
if (lhs.undefined_p ())
|
||||
return VREL_EMPTY;
|
||||
|
@ -836,6 +770,12 @@ operator_lt::op1_op2_relation (const irange &lhs) const
|
|||
return VREL_NONE;
|
||||
}
|
||||
|
||||
enum tree_code
|
||||
operator_lt::op1_op2_relation (const irange &lhs) const
|
||||
{
|
||||
return lt_op1_op2_relation (lhs);
|
||||
}
|
||||
|
||||
bool
|
||||
operator_lt::fold_range (irange &r, tree type,
|
||||
const irange &op1,
|
||||
|
@ -923,7 +863,7 @@ public:
|
|||
// Check if the LHS range indicates a relation between OP1 and OP2.
|
||||
|
||||
enum tree_code
|
||||
operator_le::op1_op2_relation (const irange &lhs) const
|
||||
le_op1_op2_relation (const irange &lhs)
|
||||
{
|
||||
if (lhs.undefined_p ())
|
||||
return VREL_EMPTY;
|
||||
|
@ -938,6 +878,12 @@ operator_le::op1_op2_relation (const irange &lhs) const
|
|||
return VREL_NONE;
|
||||
}
|
||||
|
||||
enum tree_code
|
||||
operator_le::op1_op2_relation (const irange &lhs) const
|
||||
{
|
||||
return le_op1_op2_relation (lhs);
|
||||
}
|
||||
|
||||
bool
|
||||
operator_le::fold_range (irange &r, tree type,
|
||||
const irange &op1,
|
||||
|
@ -1025,7 +971,7 @@ public:
|
|||
// Check if the LHS range indicates a relation between OP1 and OP2.
|
||||
|
||||
enum tree_code
|
||||
operator_gt::op1_op2_relation (const irange &lhs) const
|
||||
gt_op1_op2_relation (const irange &lhs)
|
||||
{
|
||||
if (lhs.undefined_p ())
|
||||
return VREL_EMPTY;
|
||||
|
@ -1040,6 +986,12 @@ operator_gt::op1_op2_relation (const irange &lhs) const
|
|||
return VREL_NONE;
|
||||
}
|
||||
|
||||
enum tree_code
|
||||
operator_gt::op1_op2_relation (const irange &lhs) const
|
||||
{
|
||||
return gt_op1_op2_relation (lhs);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
operator_gt::fold_range (irange &r, tree type,
|
||||
|
@ -1126,7 +1078,7 @@ public:
|
|||
// Check if the LHS range indicates a relation between OP1 and OP2.
|
||||
|
||||
enum tree_code
|
||||
operator_ge::op1_op2_relation (const irange &lhs) const
|
||||
ge_op1_op2_relation (const irange &lhs)
|
||||
{
|
||||
if (lhs.undefined_p ())
|
||||
return VREL_EMPTY;
|
||||
|
@ -1141,6 +1093,12 @@ operator_ge::op1_op2_relation (const irange &lhs) const
|
|||
return VREL_NONE;
|
||||
}
|
||||
|
||||
enum tree_code
|
||||
operator_ge::op1_op2_relation (const irange &lhs) const
|
||||
{
|
||||
return ge_op1_op2_relation (lhs);
|
||||
}
|
||||
|
||||
bool
|
||||
operator_ge::fold_range (irange &r, tree type,
|
||||
const irange &op1,
|
||||
|
@ -3993,18 +3951,6 @@ pointer_or_operator::wi_fold (irange &r, tree type,
|
|||
r.set_varying (type);
|
||||
}
|
||||
|
||||
// This implements the range operator tables as local objects in this file.
|
||||
|
||||
class range_op_table
|
||||
{
|
||||
public:
|
||||
inline range_operator *operator[] (enum tree_code code);
|
||||
protected:
|
||||
void set (enum tree_code code, range_operator &op);
|
||||
private:
|
||||
range_operator *m_range_tree[MAX_TREE_CODES];
|
||||
};
|
||||
|
||||
// Return a pointer to the range_operator instance, if there is one
|
||||
// associated with tree_code CODE.
|
||||
|
||||
|
|
|
@ -112,4 +112,76 @@ extern void wi_set_zero_nonzero_bits (tree type,
|
|||
wide_int &maybe_nonzero,
|
||||
wide_int &mustbe_nonzero);
|
||||
|
||||
// op1_op2_relation methods that are the same across irange and frange.
|
||||
enum tree_code equal_op1_op2_relation (const irange &lhs);
|
||||
enum tree_code not_equal_op1_op2_relation (const irange &lhs);
|
||||
enum tree_code lt_op1_op2_relation (const irange &lhs);
|
||||
enum tree_code le_op1_op2_relation (const irange &lhs);
|
||||
enum tree_code gt_op1_op2_relation (const irange &lhs);
|
||||
enum tree_code ge_op1_op2_relation (const irange &lhs);
|
||||
|
||||
enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
|
||||
bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
|
||||
|
||||
// If the range of either op1 or op2 is undefined, set the result to
|
||||
// varying and return TRUE. If the caller truely cares about a result,
|
||||
// they should pass in a varying if it has an undefined that it wants
|
||||
// treated as a varying.
|
||||
|
||||
inline bool
|
||||
empty_range_varying (irange &r, tree type,
|
||||
const irange &op1, const irange & op2)
|
||||
{
|
||||
if (op1.undefined_p () || op2.undefined_p ())
|
||||
{
|
||||
r.set_varying (type);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// For relation opcodes, first try to see if the supplied relation
|
||||
// forces a true or false result, and return that.
|
||||
// Then check for undefined operands. If none of this applies,
|
||||
// return false.
|
||||
|
||||
inline bool
|
||||
relop_early_resolve (irange &r, tree type, const irange &op1,
|
||||
const irange &op2, relation_kind rel,
|
||||
relation_kind my_rel)
|
||||
{
|
||||
// If known relation is a complete subset of this relation, always true.
|
||||
if (relation_union (rel, my_rel) == my_rel)
|
||||
{
|
||||
r = range_true (type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If known relation has no subset of this relation, always false.
|
||||
if (relation_intersect (rel, my_rel) == VREL_EMPTY)
|
||||
{
|
||||
r = range_false (type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If either operand is undefined, return VARYING.
|
||||
if (empty_range_varying (r, type, op1, op2))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This implements the range operator tables as local objects.
|
||||
|
||||
class range_op_table
|
||||
{
|
||||
public:
|
||||
range_operator *operator[] (enum tree_code code);
|
||||
protected:
|
||||
void set (enum tree_code code, range_operator &op);
|
||||
private:
|
||||
range_operator *m_range_tree[MAX_TREE_CODES];
|
||||
};
|
||||
|
||||
#endif // GCC_RANGE_OP_H
|
||||
|
|
28
gcc/range.h
28
gcc/range.h
|
@ -25,4 +25,32 @@ value_range range_zero (tree type);
|
|||
value_range range_nonzero (tree type);
|
||||
value_range range_positives (tree type);
|
||||
value_range range_negatives (tree type);
|
||||
|
||||
// Return an irange instance that is a boolean TRUE.
|
||||
|
||||
static inline int_range<1>
|
||||
range_true (tree type)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
return int_range<1> (type, wi::one (prec), wi::one (prec));
|
||||
}
|
||||
|
||||
// Return an irange instance that is a boolean FALSE.
|
||||
|
||||
static inline int_range<1>
|
||||
range_false (tree type)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
return int_range<1> (type, wi::zero (prec), wi::zero (prec));
|
||||
}
|
||||
|
||||
// Return an irange that covers both true and false.
|
||||
|
||||
static inline int_range<1>
|
||||
range_true_and_false (tree type)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
return int_range<1> (type, wi::zero (prec), wi::one (prec));
|
||||
}
|
||||
|
||||
#endif // GCC_RANGE_H
|
||||
|
|
Loading…
Reference in New Issue