gcc_checking_assert (signed_op);
range_op_handler unsigned_op (OP_WIDEN_MULT_UNSIGNED);
gcc_checking_assert (unsigned_op);
+ range_op_handler signed_unsigned_op (OP_WIDEN_MULT_SIGNED_UNSIGNED);
+ gcc_checking_assert (signed_unsigned_op);
+ bool signed1, signed2;
if (gimple_code (m_stmt) == GIMPLE_ASSIGN)
switch (gimple_assign_rhs_code (m_stmt))
{
case WIDEN_MULT_EXPR:
- {
m_op1 = gimple_assign_rhs1 (m_stmt);
m_op2 = gimple_assign_rhs2 (m_stmt);
- tree ret = gimple_assign_lhs (m_stmt);
- bool signed1 = TYPE_SIGN (TREE_TYPE (m_op1)) == SIGNED;
- bool signed2 = TYPE_SIGN (TREE_TYPE (m_op2)) == SIGNED;
- bool signed_ret = TYPE_SIGN (TREE_TYPE (ret)) == SIGNED;
-
- /* Normally these operands should all have the same sign, but
- some passes and violate this by taking mismatched sign args. At
- the moment the only one that's possible is mismatch inputs and
- unsigned output. Once ranger supports signs for the operands we
- can properly fix it, for now only accept the case we can do
- correctly. */
- if ((signed1 ^ signed2) && signed_ret)
- return;
+ signed1 = TYPE_SIGN (TREE_TYPE (m_op1)) == SIGNED;
+ signed2 = TYPE_SIGN (TREE_TYPE (m_op2)) == SIGNED;
- if (signed2 && !signed1)
- std::swap (m_op1, m_op2);
-
- if (signed1 || signed2)
+ if (signed1 != signed2)
+ {
+ if (signed2 && !signed1)
+ std::swap (m_op1, m_op2);
+ m_operator = signed_unsigned_op.range_op ();
+ }
+ else if (signed1)
m_operator = signed_op.range_op ();
else
m_operator = unsigned_op.range_op ();
break;
- }
+
default:
break;
}
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
- signop s = TYPE_SIGN (type);
-
- wide_int lh_wlb = wide_int::from (lh_lb, wi::get_precision (lh_lb) * 2, SIGNED);
- wide_int lh_wub = wide_int::from (lh_ub, wi::get_precision (lh_ub) * 2, SIGNED);
- wide_int rh_wlb = wide_int::from (rh_lb, wi::get_precision (rh_lb) * 2, s);
- wide_int rh_wub = wide_int::from (rh_ub, wi::get_precision (rh_ub) * 2, s);
+ wide_int lh_wlb = wide_int::from (lh_lb, TYPE_PRECISION (type), SIGNED);
+ wide_int lh_wub = wide_int::from (lh_ub, TYPE_PRECISION (type), SIGNED);
+ wide_int rh_wlb = wide_int::from (rh_lb, TYPE_PRECISION (type), SIGNED);
+ wide_int rh_wub = wide_int::from (rh_ub, TYPE_PRECISION (type), SIGNED);
/* We don't expect a widening multiplication to be able to overflow but range
calculations for multiplications are complicated. After widening the
return op_mult.wi_fold (r, type, lh_wlb, lh_wub, rh_wlb, rh_wub);
}
-
class operator_widen_mult_unsigned : public range_operator
{
public:
const wide_int &rh_lb,
const wide_int &rh_ub) const
{
- signop s = TYPE_SIGN (type);
+ wide_int lh_wlb = wide_int::from (lh_lb, TYPE_PRECISION (type), UNSIGNED);
+ wide_int lh_wub = wide_int::from (lh_ub, TYPE_PRECISION (type), UNSIGNED);
+ wide_int rh_wlb = wide_int::from (rh_lb, TYPE_PRECISION (type), UNSIGNED);
+ wide_int rh_wub = wide_int::from (rh_ub, TYPE_PRECISION (type), UNSIGNED);
- wide_int lh_wlb = wide_int::from (lh_lb, wi::get_precision (lh_lb) * 2, UNSIGNED);
- wide_int lh_wub = wide_int::from (lh_ub, wi::get_precision (lh_ub) * 2, UNSIGNED);
- wide_int rh_wlb = wide_int::from (rh_lb, wi::get_precision (rh_lb) * 2, s);
- wide_int rh_wub = wide_int::from (rh_ub, wi::get_precision (rh_ub) * 2, s);
+ /* We don't expect a widening multiplication to be able to overflow but range
+ calculations for multiplications are complicated. After widening the
+ operands lets call the base class. */
+ return op_mult.wi_fold (r, type, lh_wlb, lh_wub, rh_wlb, rh_wub);
+}
+
+class operator_widen_mult_signed_unsigned : 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;
+} op_widen_mult_signed_unsigned;
+
+void
+operator_widen_mult_signed_unsigned::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
+{
+ wide_int lh_wlb = wide_int::from (lh_lb, TYPE_PRECISION (type), SIGNED);
+ wide_int lh_wub = wide_int::from (lh_ub, TYPE_PRECISION (type), SIGNED);
+ wide_int rh_wlb = wide_int::from (rh_lb, TYPE_PRECISION (type), UNSIGNED);
+ wide_int rh_wub = wide_int::from (rh_ub, TYPE_PRECISION (type), UNSIGNED);
/* We don't expect a widening multiplication to be able to overflow but range
calculations for multiplications are complicated. After widening the
set (ABSU_EXPR, op_absu);
set (OP_WIDEN_MULT_SIGNED, op_widen_mult_signed);
set (OP_WIDEN_MULT_UNSIGNED, op_widen_mult_unsigned);
+ set (OP_WIDEN_MULT_SIGNED_UNSIGNED, op_widen_mult_signed_unsigned);
set (OP_WIDEN_PLUS_SIGNED, op_widen_plus_signed);
set (OP_WIDEN_PLUS_UNSIGNED, op_widen_plus_unsigned);
// Add them to the end of the tree-code vector, and provide a name for
// each allowing for easy access when required.
-#define OP_WIDEN_MULT_SIGNED ((unsigned) MAX_TREE_CODES)
-#define OP_WIDEN_MULT_UNSIGNED ((unsigned) MAX_TREE_CODES + 1)
-#define OP_WIDEN_PLUS_SIGNED ((unsigned) MAX_TREE_CODES + 2)
-#define OP_WIDEN_PLUS_UNSIGNED ((unsigned) MAX_TREE_CODES + 3)
-#define RANGE_OP_TABLE_SIZE ((unsigned) MAX_TREE_CODES + 4)
+#define OP_WIDEN_MULT_SIGNED ((unsigned) MAX_TREE_CODES)
+#define OP_WIDEN_MULT_UNSIGNED ((unsigned) MAX_TREE_CODES + 1)
+#define OP_WIDEN_MULT_SIGNED_UNSIGNED ((unsigned) MAX_TREE_CODES + 2)
+#define OP_WIDEN_PLUS_SIGNED ((unsigned) MAX_TREE_CODES + 3)
+#define OP_WIDEN_PLUS_UNSIGNED ((unsigned) MAX_TREE_CODES + 4)
+#define RANGE_OP_TABLE_SIZE ((unsigned) MAX_TREE_CODES + 5)
// This implements the range operator tables as local objects.