On Fri, Dec 09, 2016 at 05:36:41PM +0530, Prathamesh Kulkarni wrote:
> --- a/gcc/tree-ssa-strlen.c
> +++ b/gcc/tree-ssa-strlen.c
> @@ -2302,7 +2302,81 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
> else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
> handle_pointer_plus (gsi);
> }
> - else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
> +
> + /* Fold strstr (s, t) == s to memcmp (s, t, strlen (t)) == 0.
> + if strlen (t) is known and var holding return value of strstr
> + has single use. */
> +
> + else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE
> (lhs)))
> + {
> + enum tree_code code = gimple_assign_rhs_code (stmt);
> + if (code == EQ_EXPR || code == NE_EXPR)
This way you handle _8 = _5 == _7;, but not if (_5 == _7) bar ();. Shouldn't
you
also handle GIMPLE_COND similarly (of course, the rhs1 and rhs2 grabbing
and code grabbing is different for GIMPLE_COND. But the rest should be
the same, except again that you don't want to replace the GIMPLE_COND, but
adjust it. Maybe also COND_EXPR in gimple_assign (_9 = _5 == _7 ? _10 : _11;).
> + {
> + tree rhs1 = gimple_assign_rhs1 (stmt);
> + tree rhs2 = gimple_assign_rhs2 (stmt);
> + if (TREE_CODE (rhs1) == SSA_NAME
> + && TREE_CODE (rhs2) == SSA_NAME)
> + {
> + gcall *call_stmt = dyn_cast<gcall *> (SSA_NAME_DEF_STMT
> (rhs1));
> + if (!call_stmt)
> + {
> + call_stmt = dyn_cast<gcall *> (SSA_NAME_DEF_STMT (rhs2));
> + tree tmp = rhs1;
> + rhs1 = rhs2;
> + rhs2 = tmp;
We use std::swap (rhs1, rhs2); in this case these days.
> + }
> +
> + tree call_lhs;
> + if (call_stmt
> + && gimple_call_builtin_p (call_stmt, BUILT_IN_STRSTR)
> + && (call_lhs = gimple_call_lhs (call_stmt))
> + && has_single_use (call_lhs))
This might not optimize if you have:
_5 = foo ();
_7 = __builtin_strstr (_5, "abcd");
_8 = _5 == _7;
Or even you could have:
_5 = __builtin_strstr (...);
_7 = __builtin_strstr (_5, "abcd");
_8 = _5 == _7;
So I wonder if you shouldn't do:
gimple *call_stmt = NULL;
for (int pass = 0; pass < 2; pass++)
{
gimple *g = SSA_NAME_DEF_STMT (rhs1);
if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
&& gimple_call_lhs (g) == rhs1
&& has_single_use (rhs1)
&& gimple_call_arg (g, 0) == rhs2)
{
call_stmt = g;
break;
}
std::swap (rhs1, rhs2);
}
if (call_stmt)
...
I think you don't need operand_equal_p, because SSA_NAMEs should just
be the same pointer if they are the same thing.
The above way you handle both orderings. Perhaps also it is big enough to
be done in a separate function, which you call with the code/rhs1/rhs2 and
stmt for the EQ/NE_EXPR is_gimple_assign as well as for COND_EXPR and
GIMPLE_COND.
Jakub