Fold strstr (s, t) eq/ne s to strcmp (s, t) eq/ne 0 if strlen (t) is known

Jakub Jelinek jakub@redhat.com
Tue Dec 13 09:57:00 GMT 2016


On Tue, Dec 13, 2016 at 03:08:17PM +0530, Prathamesh Kulkarni wrote:
> Thanks for the suggestions. It didn't occur to me to check for gimple_cond.
> I have tried to do the changes in the attached version.
> I am not sure if I have handled cond_expr correctly.
> IIUC, if gimple_assign has code cond_expr, then the condition is
> stored in gimple_assign_rhs1,
> however it's not a single operand but a tree of the form "op1 cond_code op2".
> Is that correct ?

Yes.  gimple_assign_rhs1 will be in what you are looking for EQ_EXPR or
NE_EXPR tree, its TREE_CODE will be this code you want to check, and
TREE_OPERAND (exp, 0) and TREE_OPERAND (exp, 1) the rhs1 and rhs2 you use
elsewhere.

> However I am not able to write a test-case that generates cond_expr in the IL.
> I tried:
> t1 = strstr (s, t);
> (t1 == s)  ? foo() : bar ();
> and other such variants but it seems the ?: operator is getting
> lowered to gimple_cond instead.

It is, but in some cases tree-if-conv.c turns them back into COND_EXPRs.
I guess you need -ftree-loop-if-convert now, and it has to be in some loop
where the addition of cond_expr would likely turn it into a single bb loop.
You probably want constants or vars, not function calls in the ? :
expressions though.

> +/* Try to fold strstr (s, t) == s to memcmp (s, t, strlen (t)) == 0.  */
> +
> +static void
> +fold_strstr_to_memcmp(enum tree_code code, tree rhs1, tree rhs2, gimple *stmt)

Formatting, space before (.

> +{
> +  gimple *call_stmt = NULL;
> +  for (int pass = 0; pass < 2; pass++)
> +    {
> +      gimple *g = SSA_NAME_DEF_STMT (rhs1);
> +      if (g

I think g should be always non-NULL (except for invalid IL), so probably no
need to check it.

> +	  && gimple_call_builtin_p (g, BUILT_IN_STRSTR)
> +	  && has_single_use (rhs1)
> +	  && gimple_call_arg (as_a<gcall *> (g), 0) == rhs2)

I think gimple_call_arg works fine even with just gimple * argument.
So you can avoid the as_a<gcall *> (g) uglification and just use g.

> +	      if (is_gimple_assign (stmt))
> +		{
> +		  if (gimple_assign_rhs_code (stmt) == COND_EXPR)
> +		    {
> +		      tree cond = gimple_assign_rhs1 (stmt);
> +		      TREE_SET_CODE (cond, EQ_EXPR);

This looks weird.  You are hardcoding EQ_EXPR, while for the
other case below you use code.  So, do you handle properly both
EQ_EXPR and NE_EXPR for this and gimple_cond cases?
Also, for non-COND_EXPR assign you build a new stmt instead of reusing
the existing one, why?

> +		      TREE_OPERAND (cond, 0) = memcmp_lhs;
> +		      TREE_OPERAND (cond, 1) = zero;
> +		      update_stmt (stmt);
> +		    }
> +		  else
> +		    {
> +		      gsi = gsi_for_stmt (stmt);
> +		      tree lhs = gimple_assign_lhs (stmt);
> +		      gassign *ga = gimple_build_assign (lhs, code, memcmp_lhs,
> +							 zero);
> +		      gsi_replace (&gsi, ga, false);
> +		    }
> +		}
> +	      else
> +		{
> +		  gcond *cond = as_a<gcond *> (stmt);
> +		  gimple_cond_set_lhs (cond, memcmp_lhs);
> +		  gimple_cond_set_rhs (cond, zero);
> +		  gimple_cond_set_code (cond, EQ_EXPR);

Likewise here.

	Jakub



More information about the Gcc-patches mailing list