re PR middle-end/61473 (register sized memmove not inlined)
authorRichard Biener <rguenther@suse.de>
Fri, 11 Jul 2014 13:42:55 +0000 (13:42 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 11 Jul 2014 13:42:55 +0000 (13:42 +0000)
2014-07-11  Richard Biener  <rguenther@suse.de>

PR middle-end/61473
* builtins.c (fold_builtin_memory_op): Inline memory moves
that can be implemented with a single load followed by a
single store.
(c_strlen): Only warn when only_value is not 2.

* gcc.dg/memmove-4.c: New testcase.
* gcc.dg/strlenopt-8.c: XFAIL.
* gfortran.dg/coarray_lib_realloc_1.f90: Adjust.

From-SVN: r212452

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/memmove-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/strlenopt-8.c
gcc/testsuite/gfortran.dg/coarray_lib_realloc_1.f90

index b8ab1223d735cc51ea7d39686a68a169d7776396..6fe9bfdb71974ff3a4843279b58cc6f13d92bf6c 100644 (file)
@@ -1,3 +1,11 @@
+2014-07-11  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/61473
+       * builtins.c (fold_builtin_memory_op): Inline memory moves
+       that can be implemented with a single load followed by a
+       single store.
+       (c_strlen): Only warn when only_value is not 2.
+
 2014-07-11  Evgeny Stupachenko  <evstupac@gmail.com>
 
        * config/i386/i386.c (expand_vec_perm_pblendv): Disable for AVX.
index 2d3d867b0b2d138a8fe9d4f2898746f7507e12aa..cc94302d0cf5fbced5df7204bbe9847fca45a017 100644 (file)
@@ -535,6 +535,10 @@ get_pointer_alignment (tree exp)
    len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not
    evaluate the side-effects.
 
+   If ONLY_VALUE is two then we do not emit warnings about out-of-bound
+   accesses.  Note that this implies the result is not going to be emitted
+   into the instruction stream.
+
    The value returned is of type `ssizetype'.
 
    Unfortunately, string_constant can't access the values of const char
@@ -606,7 +610,8 @@ c_strlen (tree src, int only_value)
 
   /* If the offset is known to be out of bounds, warn, and call strlen at
      runtime.  */
-  if (offset < 0 || offset > max)
+  if (only_value != 2
+      && (offset < 0 || offset > max))
     {
      /* Suppress multiple warnings for propagated constant strings.  */
       if (! TREE_NO_WARNING (src))
@@ -8637,11 +8642,57 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
       unsigned int src_align, dest_align;
       tree off0;
 
+      /* Build accesses at offset zero with a ref-all character type.  */
+      off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
+                                                        ptr_mode, true), 0);
+
+      /* If we can perform the copy efficiently with first doing all loads
+         and then all stores inline it that way.  Currently efficiently
+        means that we can load all the memory into a single integer
+        register which is what MOVE_MAX gives us.  */
+      src_align = get_pointer_alignment (src);
+      dest_align = get_pointer_alignment (dest);
+      if (tree_fits_uhwi_p (len)
+         && compare_tree_int (len, MOVE_MAX) <= 0
+         /* ???  Don't transform copies from strings with known length this
+            confuses the tree-ssa-strlen.c.  This doesn't handle
+            the case in gcc.dg/strlenopt-8.c which is XFAILed for that
+            reason.  */
+         && !c_strlen (src, 2))
+       {
+         unsigned ilen = tree_to_uhwi (len);
+         if (exact_log2 (ilen) != -1)
+           {
+             tree type = lang_hooks.types.type_for_size (ilen * 8, 1);
+             if (type
+                 && TYPE_MODE (type) != BLKmode
+                 && (GET_MODE_SIZE (TYPE_MODE (type)) * BITS_PER_UNIT
+                     == ilen * 8)
+                 /* If the pointers are not aligned we must be able to
+                    emit an unaligned load.  */
+                 && ((src_align >= GET_MODE_ALIGNMENT (TYPE_MODE (type))
+                      && dest_align >= GET_MODE_ALIGNMENT (TYPE_MODE (type)))
+                     || !SLOW_UNALIGNED_ACCESS (TYPE_MODE (type),
+                                                MIN (src_align, dest_align))))
+               {
+                 tree srctype = type;
+                 tree desttype = type;
+                 if (src_align < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
+                   srctype = build_aligned_type (type, src_align);
+                 if (dest_align < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
+                   desttype = build_aligned_type (type, dest_align);
+                 if (!ignore)
+                   dest = builtin_save_expr (dest);
+                 expr = build2 (MODIFY_EXPR, type,
+                                fold_build2 (MEM_REF, desttype, dest, off0),
+                                fold_build2 (MEM_REF, srctype, src, off0));
+                 goto done;
+               }
+           }
+       }
+
       if (endp == 3)
        {
-         src_align = get_pointer_alignment (src);
-         dest_align = get_pointer_alignment (dest);
-
          /* Both DEST and SRC must be pointer types.
             ??? This is what old code did.  Is the testing for pointer types
             really mandatory?
@@ -8818,10 +8869,6 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
       if (!ignore)
         dest = builtin_save_expr (dest);
 
-      /* Build accesses at offset zero with a ref-all character type.  */
-      off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
-                                                        ptr_mode, true), 0);
-
       destvar = dest;
       STRIP_NOPS (destvar);
       if (TREE_CODE (destvar) == ADDR_EXPR
@@ -8888,6 +8935,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
       expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
     }
 
+done:
   if (ignore)
     return expr;
 
index 63b51c675896d3a66607f14f9d50a998b9ba203d..324db9063630a1bdc446f3dc6f5d33bf458b0534 100644 (file)
@@ -1,3 +1,10 @@
+2014-07-11  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/61473
+       * gcc.dg/memmove-4.c: New testcase.
+       * gcc.dg/strlenopt-8.c: XFAIL.
+       * gfortran.dg/coarray_lib_realloc_1.f90: Adjust.
+
 2014-07-11  Marat Zakirov  <m.zakirov@samsung.com>
 
        PR target/61561
diff --git a/gcc/testsuite/gcc.dg/memmove-4.c b/gcc/testsuite/gcc.dg/memmove-4.c
new file mode 100644 (file)
index 0000000..120a4db
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+typedef int w __attribute__((mode(word)));
+
+void b(char *a, char *b, int i)
+{
+  __builtin_memmove (&a[i], &b[i], sizeof(w));
+}
+
+/* { dg-final { scan-tree-dump-not "memmove" "optimized" { xfail { ! non_strict_align } } } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index 3aaf660a12ccd940396527c6568325b7da694292..3f9ad511263f16ce2696481ea93d173633e78a59 100644 (file)
@@ -43,8 +43,8 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" { xfail *-*-* } } } */
 /* { 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 \\(" 0 "strlen" } } */
index 60d4456323f202d038ee112096f597a16b0166ef..4fd0e9b899fba6f31fe13456af720448d07a1fd9 100644 (file)
@@ -30,6 +30,6 @@ end
 ! { dg-final { scan-tree-dump-times "__builtin_malloc" 1 "original" } }
 
 ! But copy "ii" and "CAF":
-! { dg-final { scan-tree-dump-times "__builtin_memcpy" 2 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_memcpy|= MEM" 2 "original" } }
 
 ! { dg-final { cleanup-tree-dump "original" } }