Add operand_check_p to range-ops.
Add an optional method to verify operands are compatible, and check the operands before all range operations. * range-op-mixed.h (operator_equal::operand_check_p): New. (operator_not_equal::operand_check_p): New. (operator_lt::operand_check_p): New. (operator_le::operand_check_p): New. (operator_gt::operand_check_p): New. (operator_ge::operand_check_p): New. (operator_plus::operand_check_p): New. (operator_abs::operand_check_p): New. (operator_minus::operand_check_p): New. (operator_negate::operand_check_p): New. (operator_mult::operand_check_p): New. (operator_bitwise_not::operand_check_p): New. (operator_bitwise_xor::operand_check_p): New. (operator_bitwise_and::operand_check_p): New. (operator_bitwise_or::operand_check_p): New. (operator_min::operand_check_p): New. (operator_max::operand_check_p): New. * range-op.cc (range_op_handler::fold_range): Check operand parameter types. (range_op_handler::op1_range): Ditto. (range_op_handler::op2_range): Ditto. (range_op_handler::operand_check_p): New. (range_operator::operand_check_p): New. (operator_lshift::operand_check_p): New. (operator_rshift::operand_check_p): New. (operator_logical_and::operand_check_p): New. (operator_logical_or::operand_check_p): New. (operator_logical_not::operand_check_p): New. * range-op.h (range_operator::operand_check_p): New. (range_op_handler::operand_check_p): New.
This commit is contained in:
parent
302461ad9a
commit
ea19de921b
3 changed files with 114 additions and 7 deletions
|
@ -138,6 +138,9 @@ public:
|
|||
const frange &) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check op1 and op2 for compatibility.
|
||||
bool operand_check_p (tree, tree t1, tree t2) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
class operator_not_equal : public range_operator
|
||||
|
@ -174,6 +177,9 @@ public:
|
|||
const frange &) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check op1 and op2 for compatibility.
|
||||
bool operand_check_p (tree, tree t1, tree t2) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
class operator_lt : public range_operator
|
||||
|
@ -207,6 +213,9 @@ public:
|
|||
const frange &) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check op1 and op2 for compatibility.
|
||||
bool operand_check_p (tree, tree t1, tree t2) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
class operator_le : public range_operator
|
||||
|
@ -243,6 +252,9 @@ public:
|
|||
const frange &) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check op1 and op2 for compatibility.
|
||||
bool operand_check_p (tree, tree t1, tree t2) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
class operator_gt : public range_operator
|
||||
|
@ -278,6 +290,9 @@ public:
|
|||
const frange &) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check op1 and op2 for compatibility.
|
||||
bool operand_check_p (tree, tree t1, tree t2) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
class operator_ge : public range_operator
|
||||
|
@ -314,6 +329,9 @@ public:
|
|||
const frange &) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check op1 and op2 for compatibility.
|
||||
bool operand_check_p (tree, tree t1, tree t2) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
class operator_identity : public range_operator
|
||||
|
@ -409,7 +427,10 @@ public:
|
|||
|
||||
virtual bool overflow_free_p (const irange &lh, const irange &rh,
|
||||
relation_trio = TRIO_VARYING) const;
|
||||
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
private:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -436,6 +457,9 @@ class operator_abs : public range_operator
|
|||
relation_trio rel = TRIO_VARYING) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check compatibility of LHS and op1.
|
||||
bool operand_check_p (tree t1, tree t2, tree) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
private:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -477,7 +501,10 @@ public:
|
|||
|
||||
virtual bool overflow_free_p (const irange &lh, const irange &rh,
|
||||
relation_trio = TRIO_VARYING) const;
|
||||
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
private:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -506,6 +533,9 @@ class operator_negate : public range_operator
|
|||
bool op1_range (frange &r, tree type,
|
||||
const frange &lhs, const frange &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 TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -557,7 +587,10 @@ public:
|
|||
relation_kind kind) const final override;
|
||||
virtual bool overflow_free_p (const irange &lh, const irange &rh,
|
||||
relation_trio = TRIO_VARYING) const;
|
||||
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
};
|
||||
|
||||
class operator_addr_expr : public range_operator
|
||||
|
@ -586,6 +619,10 @@ public:
|
|||
relation_trio rel = TRIO_VARYING) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
};
|
||||
|
||||
class operator_bitwise_xor : public range_operator
|
||||
|
@ -606,6 +643,10 @@ public:
|
|||
relation_kind rel) const final override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
private:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -629,6 +670,10 @@ public:
|
|||
relation_kind) const override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const override;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
protected:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -651,6 +696,10 @@ public:
|
|||
relation_trio rel = TRIO_VARYING) const override;
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const override;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
protected:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -662,6 +711,10 @@ class operator_min : public range_operator
|
|||
public:
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const override;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
protected:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
@ -673,6 +726,10 @@ class operator_max : public range_operator
|
|||
public:
|
||||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const override;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
protected:
|
||||
void wi_fold (irange &r, tree type, const wide_int &lh_lb,
|
||||
const wide_int &lh_ub, const wide_int &rh_lb,
|
||||
|
|
|
@ -201,6 +201,10 @@ range_op_handler::fold_range (vrange &r, tree type,
|
|||
relation_trio rel) const
|
||||
{
|
||||
gcc_checking_assert (m_operator);
|
||||
#if CHECKING_P
|
||||
if (!lh.undefined_p () && !rh.undefined_p ())
|
||||
gcc_assert (m_operator->operand_check_p (type, lh.type (), rh.type ()));
|
||||
#endif
|
||||
switch (dispatch_kind (r, lh, rh))
|
||||
{
|
||||
case RO_III:
|
||||
|
@ -237,9 +241,12 @@ range_op_handler::op1_range (vrange &r, tree type,
|
|||
relation_trio rel) const
|
||||
{
|
||||
gcc_checking_assert (m_operator);
|
||||
|
||||
if (lhs.undefined_p ())
|
||||
return false;
|
||||
#if CHECKING_P
|
||||
if (!op2.undefined_p ())
|
||||
gcc_assert (m_operator->operand_check_p (lhs.type (), type, op2.type ()));
|
||||
#endif
|
||||
switch (dispatch_kind (r, lhs, op2))
|
||||
{
|
||||
case RO_III:
|
||||
|
@ -270,7 +277,10 @@ range_op_handler::op2_range (vrange &r, tree type,
|
|||
gcc_checking_assert (m_operator);
|
||||
if (lhs.undefined_p ())
|
||||
return false;
|
||||
|
||||
#if CHECKING_P
|
||||
if (!op1.undefined_p ())
|
||||
gcc_assert (m_operator->operand_check_p (lhs.type (), op1.type (), type));
|
||||
#endif
|
||||
switch (dispatch_kind (r, lhs, op1))
|
||||
{
|
||||
case RO_III:
|
||||
|
@ -394,6 +404,13 @@ range_op_handler::overflow_free_p (const vrange &lh,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
range_op_handler::operand_check_p (tree t1, tree t2, tree t3) const
|
||||
{
|
||||
gcc_checking_assert (m_operator);
|
||||
return m_operator->operand_check_p (t1, t2, t3);
|
||||
}
|
||||
|
||||
// Update the known bitmasks in R when applying the operation CODE to
|
||||
// LH and RH.
|
||||
|
||||
|
@ -737,6 +754,14 @@ range_operator::update_bitmask (irange &, const irange &,
|
|||
{
|
||||
}
|
||||
|
||||
// Check that operand types are OK. Default to always OK.
|
||||
|
||||
bool
|
||||
range_operator::operand_check_p (tree, tree, tree) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create and return a range from a pair of wide-ints that are known
|
||||
// to have overflowed (or underflowed).
|
||||
|
||||
|
@ -2466,6 +2491,9 @@ public:
|
|||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override
|
||||
{ update_known_bitmask (r, LSHIFT_EXPR, lh, rh); }
|
||||
// Check compatibility of LHS and op1.
|
||||
bool operand_check_p (tree t1, tree t2, tree) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
} op_lshift;
|
||||
|
||||
class operator_rshift : public cross_product_operator
|
||||
|
@ -2495,6 +2523,9 @@ public:
|
|||
void update_bitmask (irange &r, const irange &lh,
|
||||
const irange &rh) const final override
|
||||
{ update_known_bitmask (r, RSHIFT_EXPR, lh, rh); }
|
||||
// Check compatibility of LHS and op1.
|
||||
bool operand_check_p (tree t1, tree t2, tree) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
} op_rshift;
|
||||
|
||||
|
||||
|
@ -3070,9 +3101,12 @@ public:
|
|||
const irange &lhs,
|
||||
const irange &op1,
|
||||
relation_trio rel = TRIO_VARYING) const;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
} op_logical_and;
|
||||
|
||||
|
||||
bool
|
||||
operator_logical_and::fold_range (irange &r, tree type,
|
||||
const irange &lh,
|
||||
|
@ -3082,6 +3116,11 @@ operator_logical_and::fold_range (irange &r, tree type,
|
|||
if (empty_range_varying (r, type, lh, rh))
|
||||
return true;
|
||||
|
||||
// Precision of LHS and both operands must match.
|
||||
if (TYPE_PRECISION (lh.type ()) != TYPE_PRECISION (type)
|
||||
|| TYPE_PRECISION (type) != TYPE_PRECISION (rh.type ()))
|
||||
return false;
|
||||
|
||||
// 0 && anything is 0.
|
||||
if ((wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (lh.upper_bound (), 0))
|
||||
|| (wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (rh.upper_bound (), 0)))
|
||||
|
@ -3567,6 +3606,10 @@ public:
|
|||
const irange &lhs,
|
||||
const irange &op1,
|
||||
relation_trio rel = TRIO_VARYING) const;
|
||||
// Check compatibility of all operands.
|
||||
bool operand_check_p (tree t1, tree t2, tree t3) const final override
|
||||
{ return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
|
||||
&& TYPE_PRECISION (t1) == TYPE_PRECISION (t3)); }
|
||||
} op_logical_or;
|
||||
|
||||
bool
|
||||
|
@ -3993,6 +4036,9 @@ public:
|
|||
const irange &lhs,
|
||||
const irange &op2,
|
||||
relation_trio rel = TRIO_VARYING) const;
|
||||
// Check compatibility of LHS and op1.
|
||||
bool operand_check_p (tree t1, tree t2, tree) const final override
|
||||
{ return TYPE_PRECISION (t1) == TYPE_PRECISION (t2); }
|
||||
} op_logical_not;
|
||||
|
||||
// Folding a logical NOT, oddly enough, involves doing nothing on the
|
||||
|
@ -4036,7 +4082,6 @@ operator_logical_not::op1_range (irange &r,
|
|||
return fold_range (r, type, lhs, op2);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
operator_bitwise_not::fold_range (irange &r, tree type,
|
||||
const irange &lh,
|
||||
|
|
|
@ -157,6 +157,10 @@ public:
|
|||
|
||||
virtual bool overflow_free_p (const irange &lh, const irange &rh,
|
||||
relation_trio = TRIO_VARYING) const;
|
||||
|
||||
// Compatability check for operands.
|
||||
virtual bool operand_check_p (tree, tree, tree) const;
|
||||
|
||||
protected:
|
||||
// Perform an integral operation between 2 sub-ranges and return it.
|
||||
virtual void wi_fold (irange &r, tree type,
|
||||
|
@ -226,6 +230,7 @@ public:
|
|||
const vrange &op2) const;
|
||||
bool overflow_free_p (const vrange &lh, const vrange &rh,
|
||||
relation_trio = TRIO_VARYING) const;
|
||||
bool operand_check_p (tree, tree, tree) const;
|
||||
protected:
|
||||
unsigned dispatch_kind (const vrange &lhs, const vrange &op1,
|
||||
const vrange& op2) const;
|
||||
|
|
Loading…
Add table
Reference in a new issue