@@ -1187,6 +1187,7 @@ gimple_range_op_handler::maybe_non_standard ()
{
range_operator *signed_op = ptr_op_widen_mult_signed;
range_operator *unsigned_op = ptr_op_widen_mult_unsigned;
+ bool signed1, signed2, signed_ret;
if (gimple_code (m_stmt) == GIMPLE_ASSIGN)
switch (gimple_assign_rhs_code (m_stmt))
{
@@ -1196,32 +1197,58 @@ gimple_range_op_handler::maybe_non_standard ()
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;
-
- m_valid = true;
- if (signed2 && !signed1)
- std::swap (m_op1, m_op2);
-
- if (signed1 || signed2)
- m_int = signed_op;
- else
- m_int = unsigned_op;
+ signed1 = TYPE_SIGN (TREE_TYPE (m_op1)) == SIGNED;
+ signed2 = TYPE_SIGN (TREE_TYPE (m_op2)) == SIGNED;
+ signed_ret = TYPE_SIGN (TREE_TYPE (ret)) == SIGNED;
break;
}
default:
- break;
+ return;
+ }
+ else if (gimple_code (m_stmt) == GIMPLE_CALL
+ && gimple_call_internal_p (m_stmt)
+ && gimple_get_lhs (m_stmt) != NULL_TREE)
+ switch (gimple_call_internal_fn (m_stmt))
+ {
+ case IFN_VEC_WIDEN_PLUS:
+ case IFN_VEC_WIDEN_PLUS_LO:
+ case IFN_VEC_WIDEN_PLUS_HI:
+ case IFN_VEC_WIDEN_PLUS_EVEN:
+ case IFN_VEC_WIDEN_PLUS_ODD:
+ {
+ signed_op = ptr_op_widen_plus_signed;
+ unsigned_op = ptr_op_widen_plus_unsigned;
+ m_valid = false;
+ m_op1 = gimple_call_arg (m_stmt, 0);
+ m_op2 = gimple_call_arg (m_stmt, 1);
+ tree ret = gimple_get_lhs (m_stmt);
+ signed1 = TYPE_SIGN (TREE_TYPE (m_op1)) == SIGNED;
+ signed2 = TYPE_SIGN (TREE_TYPE (m_op2)) == SIGNED;
+ signed_ret = TYPE_SIGN (TREE_TYPE (ret)) == SIGNED;
+ break;
+ }
+ default:
+ return;
}
+ else
+ return;
+
+ /* 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;
+
+ m_valid = true;
+ if (signed2 && !signed1)
+ std::swap (m_op1, m_op2);
+
+ if (signed1 || signed2)
+ m_int = signed_op;
+ else
+ m_int = unsigned_op;
}
// Set up a gimple_range_op_handler for any built in function which can be