[PATCH] strlenopt improvements

Andreas Krebbel krebbel@linux.vnet.ibm.com
Mon Oct 24 17:40:00 GMT 2011


Hi,

the attached patch fixes all the strlenopt failures on s390x (without
nuking the strcat folding).

The one case I couldn't get working so far is the second strlen in:

__attribute__((noinline, noclone)) size_t
bar (char *p, char *q)
{
  char *r;
  size_t l1, l2;

  r = strchr (p, '\0');
  strcpy (r, q);
  l1 = strlen (p);
  strcpy (r, "567");
  l2 = strlen (p);

  return l1 + l2;
}

Perhaps this could be fixed by putting a stmt_addend value into the
strinfo structs.

Bootstrapped on x86_64 and s390x. No regressions.

Ok for mainline?

Bye,

-Andreas-


2011-10-24  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* tree-ssa-strlen.c (get_string_length): Change assertion to STPCPY.
	(zero_length_string): Change assertion to accept strinfo without
	length but with stmt instead.
	Set the endptr pointer also if starting a new chain.
	(adjust_related_strinfos): Ignore strinfos marked for delayed
	length computation.
	(handle_builtin_strcpy): Mark earlier strinfo elements also for
	delayed length computation.

2011-10-24  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* gcc.dg/strlenopt-22.c: New testcase.
	* gcc.dg/strlenopt-4.c: Change scan value for s390(x).

Index: gcc/tree-ssa-strlen.c
===================================================================
*** gcc/tree-ssa-strlen.c.orig
--- gcc/tree-ssa-strlen.c
*************** get_string_length (strinfo si)
*** 397,403 ****
        callee = gimple_call_fndecl (stmt);
        gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
        lhs = gimple_call_lhs (stmt);
!       gcc_assert (builtin_decl_implicit_p (BUILT_IN_STRCPY));
        /* unshare_strinfo is intentionally not called here.  The (delayed)
  	 transformation of strcpy or strcat into stpcpy is done at the place
  	 of the former strcpy/strcat call and so can affect all the strinfos
--- 397,403 ----
        callee = gimple_call_fndecl (stmt);
        gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
        lhs = gimple_call_lhs (stmt);
!       gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
        /* unshare_strinfo is intentionally not called here.  The (delayed)
  	 transformation of strcpy or strcat into stpcpy is done at the place
  	 of the former strcpy/strcat call and so can affect all the strinfos
*************** zero_length_string (tree ptr, strinfo ch
*** 588,600 ****
  		  || si->prev != chainsi->idx)
  		break;
  	    }
! 	  gcc_assert (chainsi->length);
  	  if (chainsi->endptr == NULL_TREE)
  	    {
  	      chainsi = unshare_strinfo (chainsi);
  	      chainsi->endptr = ptr;
  	    }
! 	  if (integer_zerop (chainsi->length))
  	    {
  	      if (chainsi->next)
  		{
--- 588,600 ----
  		  || si->prev != chainsi->idx)
  		break;
  	    }
! 	  gcc_assert (chainsi->length || chainsi->stmt);
  	  if (chainsi->endptr == NULL_TREE)
  	    {
  	      chainsi = unshare_strinfo (chainsi);
  	      chainsi->endptr = ptr;
  	    }
! 	  if (chainsi->length && integer_zerop (chainsi->length))
  	    {
  	      if (chainsi->next)
  		{
*************** zero_length_string (tree ptr, strinfo ch
*** 626,631 ****
--- 626,633 ----
        if (chainsi->first == 0)
  	chainsi->first = chainsi->idx;
        chainsi->next = idx;
+       if (chainsi->endptr == NULL_TREE)
+ 	chainsi->endptr = ptr;
        si->prev = chainsi->idx;
        si->first = chainsi->first;
        si->writable = chainsi->writable;
*************** adjust_related_strinfos (location_t loc,
*** 654,664 ****
  	  tree tem;
  
  	  si = unshare_strinfo (si);
! 	  gcc_assert (si->length);
! 	  tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
! 	  si->length = fold_build2_loc (loc, PLUS_EXPR,
! 					TREE_TYPE (si->length), si->length,
! 					tem);
  	  si->endptr = NULL_TREE;
  	  si->dont_invalidate = true;
  	}
--- 656,674 ----
  	  tree tem;
  
  	  si = unshare_strinfo (si);
! 	  if (si->length)
! 	    {
! 	      tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
! 	      si->length = fold_build2_loc (loc, PLUS_EXPR,
! 					    TREE_TYPE (si->length), si->length,
! 					    tem);
! 	    }
! 	  else if (si->stmt != NULL)
! 	    /* Delayed length computation is unaffected.  */
! 	    ;
! 	  else
! 	    gcc_unreachable ();
! 
  	  si->endptr = NULL_TREE;
  	  si->dont_invalidate = true;
  	}
*************** handle_builtin_strcpy (enum built_in_fun
*** 1117,1126 ****
--- 1127,1162 ----
  
    if (dsi->length == NULL_TREE)
      {
+       strinfo chainsi;
+ 
        /* If string length of src is unknown, use delayed length
  	 computation.  If string lenth of dst will be needed, it
  	 can be computed by transforming this strcpy call into
  	 stpcpy and subtracting dst from the return value.  */
+ 
+       /* Look for earlier strings whose length could be determined if
+ 	 this strcpy is turned into an stpcpy.  */
+ 
+       if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
+ 	{
+ 	  bool stmt_set_p = false;
+ 
+ 	  for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
+ 	    {
+ 	      /* When setting a stmt for delayed length computation
+ 		 prevent all strinfos through dsi from being
+ 		 invalidated.  */
+ 	      if (stmt_set_p)
+ 		chainsi->dont_invalidate = true;
+ 
+ 	      chainsi = unshare_strinfo (chainsi);
+ 	      chainsi->stmt = stmt;
+ 	      chainsi->length = NULL_TREE;
+ 	      chainsi->endptr = NULL_TREE;
+ 	      chainsi->dont_invalidate = true;
+ 	      stmt_set_p = true;
+ 	    }
+ 	}
        dsi->stmt = stmt;
        return;
      }
Index: gcc/testsuite/gcc.dg/strlenopt-22.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.dg/strlenopt-22.c
***************
*** 0 ****
--- 1,41 ----
+ /* { dg-do run } */
+ /* { dg-options "-O2 -fdump-tree-strlen" } */
+ 
+ #define USE_GNU
+ #include "strlenopt.h"
+ 
+ __attribute__((noinline, noclone)) size_t
+ bar (char *p, char *q)
+ {
+   size_t l1, l2, l3;
+   char *r = strchr (p, '\0');
+   strcpy (r, "abcde");
+   char *s = strchr (r, '\0');
+   strcpy (s, q);
+   l1 = strlen (p);
+   l2 = strlen (r);
+   l3 = strlen (s);
+   return l1 + l2 + l3;
+ }
+ 
+ int
+ main ()
+ {
+   char buf[16] = "01234";
+ 
+   if (bar (buf, "56789") != 30)
+     abort ();
+ 
+   if (memcmp (buf, "01234abcde56789", 16) != 0)
+     abort ();
+ 
+   return 0;
+ }
+ 
+ /* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+ /* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
+ /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+ /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+ /* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+ /* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
+ /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-4.c
===================================================================
*** gcc/testsuite/gcc.dg/strlenopt-4.c.orig
--- gcc/testsuite/gcc.dg/strlenopt-4.c
*************** main ()
*** 66,75 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
  /* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
! /* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen" } } */
! /* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen" } } */
  /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
  /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
  /* { dg-final { cleanup-tree-dump "strlen" } } */
--- 66,81 ----
    return 0;
  }
  
! /* For targets providing a movstr pattern strcat is already decomposed
!    into strlen + strcpy by fold_builtin_strcat.  */
! 
! /* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" { target { ! s390*-*-* } } } } */
! /* { dg-final { scan-tree-dump-times "strlen \\(" 6 "strlen" { target s390*-*-* } } } */
  /* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
! /* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen" { target { ! s390*-*-* } } } } */
! /* { dg-final { scan-tree-dump-times "strcpy \\(" 6 "strlen" { target s390*-*-* } } } */
! /* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen" { target { ! s390*-*-* } } } } */
! /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" { target s390*-*-* } } } */
  /* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
  /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
  /* { dg-final { cleanup-tree-dump "strlen" } } */



More information about the Gcc-patches mailing list