]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
builtins.c (expand_builtin_memcpy): Remove endp argument and endp != 0 handling.
authorJakub Jelinek <jakub@redhat.com>
Tue, 3 Jun 2003 08:57:55 +0000 (10:57 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 3 Jun 2003 08:57:55 +0000 (10:57 +0200)
* builtins.c (expand_builtin_memcpy): Remove endp argument and endp
!= 0 handling.  Pass 0 to store_by_pieces.
(expand_builtin_mempcpy): Add endp argument.  Don't call
expand_builtin_memcpy, call store_by_pieces resp. move_by_pieces
directly.  If ignoring result, only do expand_call.
(expand_builtin_stpcpy): Likewise.  Call expand_builtin_mempcpy
otherwise.
(expand_builtin_strncpy, expand_builtin_memset): Adjust
store_by_pices callers.
(expand_builtin): Adjust expand_builtin_memcpy and
expand_builtin_mempcpy callers.
* expr.c (can_move_by_pieces): New function.
(move_by_pieces): Add endp argument, return to resp. memory at end
or one byte earlier depending on endp.
(store_by_pieces): Likewise.
(emit_block_move): Adjust call to move_by_pieces.
(emit_push_insn): Adjust move_by_pieces caller.
* expr.h (can_move_by_pieces): New prototype.
(store_by_pieces): Adjust prototypes.
* rtl.h (move_by_pieces): Adjust prototype.
* config/mips/mips.c (expand_block_move): Adjust move_by_pieces
caller.

* gcc.c-torture/execute/builtins/string-4.c (main_test): Remove
mempcpy test with post-increments.
* gcc.c-torture/execute/string-opt-3.c: New test.
* gcc.dg/string-opt-1.c: New test.

From-SVN: r67358

gcc/ChangeLog
gcc/builtins.c
gcc/config/mips/mips.c
gcc/expr.c
gcc/expr.h
gcc/rtl.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/builtins/string-4.c
gcc/testsuite/gcc.c-torture/execute/string-opt-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/string-opt-1.c [new file with mode: 0644]

index b1bf7f437e460366e033e57b2f97e5bede43dd8f..b628ed0649fd504f97e735dd076ac9291eed8f03 100644 (file)
@@ -1,3 +1,28 @@
+2003-06-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * builtins.c (expand_builtin_memcpy): Remove endp argument and endp
+       != 0 handling.  Pass 0 to store_by_pieces.
+       (expand_builtin_mempcpy): Add endp argument.  Don't call
+       expand_builtin_memcpy, call store_by_pieces resp. move_by_pieces
+       directly.  If ignoring result, only do expand_call.
+       (expand_builtin_stpcpy): Likewise.  Call expand_builtin_mempcpy
+       otherwise.
+       (expand_builtin_strncpy, expand_builtin_memset): Adjust
+       store_by_pices callers.
+       (expand_builtin): Adjust expand_builtin_memcpy and
+       expand_builtin_mempcpy callers.
+       * expr.c (can_move_by_pieces): New function.
+       (move_by_pieces): Add endp argument, return to resp. memory at end
+       or one byte earlier depending on endp.
+       (store_by_pieces): Likewise.
+       (emit_block_move): Adjust call to move_by_pieces.
+       (emit_push_insn): Adjust move_by_pieces caller.
+       * expr.h (can_move_by_pieces): New prototype.
+       (store_by_pieces): Adjust prototypes.
+       * rtl.h (move_by_pieces): Adjust prototype.
+       * config/mips/mips.c (expand_block_move): Adjust move_by_pieces
+       caller.
+
 2003-06-03  Ben Elliston  <bje@wasabisystems.com>
 
        * doc/md.texi (Processor pipeline description): Improve wording.
index eef1cce496c1c3b62c016f5dd30551facf18d4d9..557e397945ce9c23b15aee37e3e030cdbb30e8c4 100644 (file)
@@ -125,9 +125,9 @@ static rtx expand_builtin_strspn    PARAMS ((tree, rtx,
 static rtx expand_builtin_strcspn      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_memcpy       PARAMS ((tree, rtx,
-                                                enum machine_mode, int));
-static rtx expand_builtin_mempcpy      PARAMS ((tree, rtx,
                                                 enum machine_mode));
+static rtx expand_builtin_mempcpy      PARAMS ((tree, rtx,
+                                                enum machine_mode, int));
 static rtx expand_builtin_memmove      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_bcopy                PARAMS ((tree));
@@ -2274,16 +2274,12 @@ builtin_memcpy_read_str (data, offset, mode)
 /* Expand a call to the memcpy builtin, with arguments in ARGLIST.
    Return 0 if we failed, the caller should emit a normal call,
    otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   mode MODE if that's convenient).  */
 static rtx
-expand_builtin_memcpy (arglist, target, mode, endp)
+expand_builtin_memcpy (arglist, target, mode)
      tree arglist;
      rtx target;
      enum machine_mode mode;
-     int endp;
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -2294,7 +2290,6 @@ expand_builtin_memcpy (arglist, target, mode, endp)
       tree src = TREE_VALUE (TREE_CHAIN (arglist));
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
       const char *src_str;
-
       unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
@@ -2331,28 +2326,15 @@ expand_builtin_memcpy (arglist, target, mode, endp)
          && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
                                  (PTR) src_str, dest_align))
        {
-         store_by_pieces (dest_mem, INTVAL (len_rtx),
-                          builtin_memcpy_read_str,
-                          (PTR) src_str, dest_align);
+         dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+                                     builtin_memcpy_read_str,
+                                     (PTR) src_str, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
            dest_mem = convert_memory_address (ptr_mode, dest_mem);
 #endif
-         if (endp)
-           {
-             rtx result;
-             rtx delta = len_rtx;
-
-             if (endp == 2)
-               delta = GEN_INT (INTVAL (delta) - 1);
-
-             result = simplify_gen_binary (PLUS, GET_MODE (dest_mem),
-                                           dest_mem, delta);
-             return force_operand (result, NULL_RTX);
-           }
-         else
-           return dest_mem;
+         return dest_mem;
        }
 
       src_mem = get_memory_rtx (src);
@@ -2370,61 +2352,112 @@ expand_builtin_memcpy (arglist, target, mode, endp)
            dest_addr = convert_memory_address (ptr_mode, dest_addr);
 #endif
        }
-
-      if (endp)
-        {
-         rtx result = force_operand (len_rtx, NULL_RTX);
-
-         if (endp == 2)
-           {
-             result = simplify_gen_binary (MINUS, GET_MODE (dest_addr),
-                                           result, const1_rtx);
-             result = force_operand (result, NULL_RTX);
-           }
-
-         result = simplify_gen_binary (PLUS, GET_MODE (dest_addr),
-                                       dest_addr, result);
-         return force_operand (result, NULL_RTX);
-       }
-      else
-       return dest_addr;
+      return dest_addr;
     }
 }
 
 /* Expand a call to the mempcpy builtin, with arguments in ARGLIST.
    Return 0 if we failed the caller should emit a normal call,
    otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  */
+   mode MODE if that's convenient).  If ENDP is 0 return the
+   destination pointer, if ENDP is 1 return the end pointer ala
+   mempcpy, and if ENDP is 2 return the end pointer minus one ala
+   stpcpy.  */
 
 static rtx
-expand_builtin_mempcpy (arglist, target, mode)
+expand_builtin_mempcpy (arglist, target, mode, endp)
      tree arglist;
      rtx target;
      enum machine_mode mode;
+     int endp;
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
+  /* If return value is ignored, transform mempcpy into memcpy.  */
+  else if (target == const0_rtx)
+    {
+      tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+
+      if (!fn)
+       return 0;
+
+      return expand_expr (build_function_call_expr (fn, arglist),
+                         target, mode, EXPAND_NORMAL);
+    }
   else
     {
-      /* If return value is ignored, transform mempcpy into memcpy.  */
-      if (target == const0_rtx)
+      tree dest = TREE_VALUE (arglist);
+      tree src = TREE_VALUE (TREE_CHAIN (arglist));
+      tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      const char *src_str;
+      unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+      unsigned int dest_align
+       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+      rtx dest_mem, src_mem, len_rtx;
+
+      /* If DEST is not a pointer type or LEN is not constant,
+        call the normal function.  */
+      if (dest_align == 0 || !host_integerp (len, 1))
+       return 0;
+
+      /* If the LEN parameter is zero, return DEST.  */
+      if (tree_low_cst (len, 1) == 0)
        {
-         tree fn;
-         rtx ret = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
+         /* Evaluate and ignore SRC in case it has side-effects.  */
+         expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         return expand_expr (dest, target, mode, EXPAND_NORMAL);
+       }
 
-         if (ret)
-           return ret;
+      /* If either SRC is not a pointer type, don't do this
+         operation in-line.  */
+      if (src_align == 0)
+       return 0;
 
-         fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
-         if (!fn)
-           return 0;
+      len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+      src_str = c_getstr (src);
 
-         return expand_expr (build_function_call_expr (fn, arglist),
-                             target, mode, EXPAND_NORMAL);
+      /* If SRC is a string constant and block move would be done
+        by pieces, we can avoid loading the string from memory
+        and only stored the computed constants.  */
+      if (src_str
+         && GET_CODE (len_rtx) == CONST_INT
+         && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
+         && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
+                                 (PTR) src_str, dest_align))
+       {
+         dest_mem = get_memory_rtx (dest);
+         set_mem_align (dest_mem, dest_align);
+         dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+                                     builtin_memcpy_read_str,
+                                     (PTR) src_str, dest_align, endp);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
-      return expand_builtin_memcpy (arglist, target, mode, /*endp=*/1);
+      if (GET_CODE (len_rtx) == CONST_INT
+         && can_move_by_pieces (INTVAL (len_rtx),
+                                MIN (dest_align, src_align)))
+       {
+         dest_mem = get_memory_rtx (dest);
+         set_mem_align (dest_mem, dest_align);
+         src_mem = get_memory_rtx (src);
+         set_mem_align (src_mem, src_align);
+         dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
+                                    MIN (dest_align, src_align), endp);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
+       }
+
+      return 0;
     }
 }
 
@@ -2563,13 +2596,7 @@ expand_builtin_stpcpy (arglist, target, mode)
       /* If return value is ignored, transform stpcpy into strcpy.  */
       if (target == const0_rtx)
        {
-         tree fn;
-         rtx ret = expand_builtin_strcpy (arglist, target, mode);
-
-         if (ret)
-           return ret;
-
-         fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+         tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
          if (!fn)
            return 0;
 
@@ -2577,7 +2604,7 @@ expand_builtin_stpcpy (arglist, target, mode)
                              target, mode, EXPAND_NORMAL);
        }
 
-      /* Ensure we get an actual string who length can be evaluated at
+      /* Ensure we get an actual string whose length can be evaluated at
          compile-time, not an expression containing a string.  This is
          because the latter will potentially produce pessimized code
          when used to produce the return value.  */
@@ -2588,7 +2615,7 @@ expand_builtin_stpcpy (arglist, target, mode)
       len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
       newarglist = copy_list (arglist);
       chainon (newarglist, build_tree_list (NULL_TREE, len));
-      return expand_builtin_memcpy (newarglist, target, mode, /*endp=*/2);
+      return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
     }
 }
 
@@ -2670,7 +2697,7 @@ expand_builtin_strncpy (arglist, target, mode)
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
-                          (PTR) p, dest_align);
+                          (PTR) p, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2798,7 +2825,7 @@ expand_builtin_memset (arglist, target, mode)
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_gen_str,
-                          (PTR) val_rtx, dest_align);
+                          (PTR) val_rtx, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2822,7 +2849,7 @@ expand_builtin_memset (arglist, target, mode)
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_read_str,
-                          (PTR) &c, dest_align);
+                          (PTR) &c, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -4698,13 +4725,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_MEMCPY:
-      target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
+      target = expand_builtin_memcpy (arglist, target, mode);
       if (target)
        return target;
       break;
 
     case BUILT_IN_MEMPCPY:
-      target = expand_builtin_mempcpy (arglist, target, mode);
+      target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1);
       if (target)
        return target;
       break;
index e3921fbb764eb8b1ce990feebf709310ceb87c19..0b216105e0aeeeb75e55bcebc053d804f37614e5 100644 (file)
@@ -3821,7 +3821,7 @@ expand_block_move (operands)
 
   else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES
           && align == (unsigned) UNITS_PER_WORD)
-    move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD);
+    move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD, 0);
 
   else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES)
     emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest,
index e3872e8e2693cd958c78ae202dcfcc8dd1416375..f340335515b8443a747ed67653d8a3d96c567c6e 100644 (file)
@@ -1456,6 +1456,18 @@ convert_modes (mode, oldmode, x, unsignedp)
 
 #define STORE_MAX_PIECES  MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT))
 
+/* Determine whether the LEN bytes can be moved by using several move
+   instructions.  Return nonzero if a call to move_by_pieces should
+   succeed.  */
+
+int
+can_move_by_pieces (len, align)
+     unsigned HOST_WIDE_INT len;
+     unsigned int align;
+{
+  return MOVE_BY_PIECES_P (len, align);
+}
+
 /* Generate several move instructions to copy LEN bytes from block FROM to
    block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
    and TO through protect_from_queue before calling.
@@ -1463,13 +1475,18 @@ convert_modes (mode, oldmode, x, unsignedp)
    If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
    used to push FROM to the stack.
 
-   ALIGN is maximum stack alignment we can assume.  */
+   ALIGN is maximum stack alignment we can assume.
 
-void
-move_by_pieces (to, from, len, align)
+   If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
+   mempcpy, and if ENDP is 2 return memory the end minus one byte ala
+   stpcpy.  */
+
+rtx
+move_by_pieces (to, from, len, align, endp)
      rtx to, from;
      unsigned HOST_WIDE_INT len;
      unsigned int align;
+     int endp;
 {
   struct move_by_pieces data;
   rtx to_addr, from_addr = XEXP (from, 0);
@@ -1583,6 +1600,36 @@ move_by_pieces (to, from, len, align)
   /* The code above should have handled everything.  */
   if (data.len > 0)
     abort ();
+
+  if (endp)
+    {
+      rtx to1;
+
+      if (data.reverse)
+       abort ();
+      if (data.autinc_to)
+       {
+         if (endp == 2)
+           {
+             if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
+               emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
+             else
+               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+                                                               -1));
+           }
+         to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
+                                          data.offset);
+       }
+      else
+       {
+         if (endp == 2)
+           --data.offset;
+         to1 = adjust_address (data.to, QImode, data.offset);
+       }
+      return to1;
+    }
+  else
+    return data.to;
 }
 
 /* Return number of insns required to move L bytes by pieces.
@@ -1760,7 +1807,7 @@ emit_block_move (x, y, size, method)
     }
 
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
-    move_by_pieces (x, y, INTVAL (size), align);
+    move_by_pieces (x, y, INTVAL (size), align, 0);
   else if (emit_block_move_via_movstr (x, y, size, align))
     ;
   else if (may_use_call)
@@ -2014,7 +2061,7 @@ init_block_move_fn (asmspec)
 {
   if (!block_move_fn)
     {
-      tree fn, args;
+      tree args, fn;
 
       if (TARGET_MEM_FUNCTIONS)
        {
@@ -2738,15 +2785,19 @@ can_store_by_pieces (len, constfun, constfundata, align)
 /* Generate several move instructions to store LEN bytes generated by
    CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
    pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.  */
+   ALIGN is maximum alignment we can assume.
+   If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
+   mempcpy, and if ENDP is 2 return memory the end minus one byte ala
+   stpcpy.  */
 
-void
-store_by_pieces (to, len, constfun, constfundata, align)
+rtx
+store_by_pieces (to, len, constfun, constfundata, align, endp)
      rtx to;
      unsigned HOST_WIDE_INT len;
      rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
      PTR constfundata;
      unsigned int align;
+     int endp;
 {
   struct store_by_pieces data;
 
@@ -2758,6 +2809,35 @@ store_by_pieces (to, len, constfun, constfundata, align)
   data.len = len;
   data.to = to;
   store_by_pieces_1 (&data, align);
+  if (endp)
+    {
+      rtx to1;
+
+      if (data.reverse)
+       abort ();
+      if (data.autinc_to)
+       {
+         if (endp == 2)
+           {
+             if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
+               emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
+             else
+               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+                                                               -1));
+           }
+         to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
+                                          data.offset);
+       }
+      else
+       {
+         if (endp == 2)
+           --data.offset;
+         to1 = adjust_address (data.to, QImode, data.offset);
+       }
+      return to1;
+    }
+  else
+    return data.to;
 }
 
 /* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
@@ -3872,7 +3952,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
              && where_pad != none && where_pad != stack_direction)
            anti_adjust_stack (GEN_INT (extra));
 
-         move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
+         move_by_pieces (NULL, xinner, INTVAL (size) - used, align, 0);
        }
       else
 #endif /* PUSH_ROUNDING  */
index 8b6e36ac29102b67cd361667dc0be7680c5e5f4f..8cf5a8e5a6cf4030f39b2f44e92dba5a1b90d203 100644 (file)
@@ -450,6 +450,11 @@ extern void use_group_regs PARAMS ((rtx *, rtx));
    If OBJECT has BLKmode, SIZE is its length in bytes.  */
 extern rtx clear_storage PARAMS ((rtx, rtx));
 
+/* Determine whether the LEN bytes can be moved by using several move
+   instructions.  Return nonzero if a call to move_by_pieces should
+   succeed.  */
+extern int can_move_by_pieces PARAMS ((unsigned HOST_WIDE_INT, unsigned int));
+
 /* Return nonzero if it is desirable to store LEN bytes generated by
    CONSTFUN with several move instructions by store_by_pieces
    function.  CONSTFUNDATA is a pointer which will be passed as argument
@@ -463,11 +468,12 @@ extern int can_store_by_pieces PARAMS ((unsigned HOST_WIDE_INT,
 /* Generate several move instructions to store LEN bytes generated by
    CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
    pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.  */
-extern void store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
-                                    rtx (*) (PTR, HOST_WIDE_INT,
-                                             enum machine_mode),
-                                    PTR, unsigned int));
+   ALIGN is maximum alignment we can assume.
+   Returns TO + LEN.  */
+extern rtx store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
+                                   rtx (*) (PTR, HOST_WIDE_INT,
+                                            enum machine_mode),
+                                   PTR, unsigned int, int));
 
 /* Emit insns to set X from Y.  */
 extern rtx emit_move_insn PARAMS ((rtx, rtx));
index ea0c9b38d5d5495e99a8955ed8ee9ffbefaf8182..8a76fe2a2675676a6ab13eeec087d81fd4688f57 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2141,9 +2141,9 @@ extern void emit_jump                     PARAMS ((rtx));
 extern int preserve_subexpressions_p   PARAMS ((void));
 
 /* In expr.c */
-extern void move_by_pieces             PARAMS ((rtx, rtx,
+extern rtx move_by_pieces              PARAMS ((rtx, rtx,
                                                 unsigned HOST_WIDE_INT,
-                                                unsigned int));
+                                                unsigned int, int));
 
 /* In flow.c */
 extern void recompute_reg_usage                        PARAMS ((rtx, int));
index 67ba333fab3c21a70767dbc0ec42cb01a314c18e..5ab4e9a780709640a83598cbfe8da7e799a28d54 100644 (file)
@@ -1,3 +1,10 @@
+2003-06-03  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.c-torture/execute/builtins/string-4.c (main_test): Remove
+       mempcpy test with post-increments.
+       * gcc.c-torture/execute/string-opt-3.c: New test.
+       * gcc.dg/string-opt-1.c: New test.
+
 2003-06-03  David Billinghurst (David.Billinghurst@riotinto.com)
 
        PR fortran/10965
index 9c0ee5473fd963fe6caec99ea3ad58420657cc90..0d0544e3de2e6b86c428a2c692be61e8d0fabc30 100644 (file)
@@ -23,7 +23,6 @@ void
 main_test (void)
 {
   int i;
-  const char *s;
 
   if (stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6))
     abort ();
@@ -47,9 +46,8 @@ main_test (void)
   if (stpcpy ((i++, p + 20 + 1), "23") != (p + 20 + 1 + 2) || i != 9 || memcmp (p + 20, "q23\0u", 6))
     abort ();
 
-  s = s1; i = 3;
   memcpy (p + 25, "QRSTU", 6);
-  if (mempcpy (p + 25 + 1, s++, i++) != (p + 25 + 1 + 3) || i != 4 || s != s1 + 1 || memcmp (p + 25, "Q123U", 6))
+  if (mempcpy (p + 25 + 1, s1, 3) != (p + 25 + 1 + 3) || memcmp (p + 25, "Q123U", 6))
     abort ();
 
   if (stpcpy (stpcpy (p, "ABCD"), "EFG") != p + 7 || memcmp (p, "ABCDEFG", 8))
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c
new file mode 100644 (file)
index 0000000..71a41cd
--- /dev/null
@@ -0,0 +1,166 @@
+/* Copyright (C) 2003  Free Software Foundation.
+
+   Ensure that builtin mempcpy and stpcpy perform correctly.
+
+   Written by Jakub Jelinek, 21/05/2003.  */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern void *mempcpy (void *, const void *, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *stpcpy (char *, const char *);
+
+long buf1[64];
+char *buf2 = (char *) (buf1 + 32);
+long buf5[20];
+char buf7[20];
+
+int
+__attribute__((noinline))
+test (long *buf3, char *buf4, char *buf6, int n)
+{
+  int i = 0;
+
+  /* These should probably be handled by store_by_pieces on most arches.  */
+  if (mempcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + 9
+      || memcmp (buf1, "ABCDEFGHI\0", 11))
+    abort ();
+
+  if (mempcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + 17
+      || memcmp (buf1, "abcdefghijklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy (buf3, "ABCDEF", 6) != (char *) buf1 + 6
+      || memcmp (buf1, "ABCDEFghijklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy (buf3, "a", 1) != (char *) buf1 + 1
+      || memcmp (buf1, "aBCDEFghijklmnopq\0", 19))
+    abort ();
+
+  if (mempcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 4
+      || memcmp (buf1, "aBcdEFghijklmnopq\0", 19)
+      || i != 1)
+    abort ();
+
+  /* These should probably be handled by move_by_pieces on most arches.  */
+  if (mempcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 10
+      || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1)
+      != (char *) buf1 + 11
+      || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19)
+      || i != 2)
+    abort ();
+
+  if (mempcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 16
+      || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19))
+    abort ();
+
+  if (mempcpy (buf3, buf5, 8) != (char *) buf1 + 8
+      || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19))
+    abort ();
+
+  if (mempcpy (buf3, buf5, 17) != (char *) buf1 + 17
+      || memcmp (buf1, "RSTUVWXYZ01234567\0", 19))
+    abort ();
+
+  __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19);
+
+  /* These should be handled either by movstrendM or mempcpy
+     call.  */
+  if (mempcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 10
+      || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, n + 1)
+      != (char *) buf1 + 12
+      || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19)
+      || i != 3)
+    abort ();
+
+  if (mempcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 16
+      || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19))
+    abort ();
+
+  i = 1;
+
+  /* These might be handled by store_by_pieces.  */
+  if (mempcpy (buf2, "ABCDEFGHI", 9) != buf2 + 9
+      || memcmp (buf2, "ABCDEFGHI\0", 11))
+    abort ();
+
+  if (mempcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + 17
+      || memcmp (buf2, "abcdefghijklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy (buf4, "ABCDEF", 6) != buf2 + 6
+      || memcmp (buf2, "ABCDEFghijklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy (buf4, "a", 1) != buf2 + 1
+      || memcmp (buf2, "aBCDEFghijklmnopq\0", 19))
+    abort ();
+
+  if (mempcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 4
+      || memcmp (buf2, "aBcdEFghijklmnopq\0", 19)
+      || i != 2)
+    abort ();
+
+  /* These might be handled by move_by_pieces.  */
+  if (mempcpy (buf4 + 4, buf7, 6) != buf2 + 10
+      || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, 1)
+      != buf2 + 11
+      || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19)
+      || i != 3)
+    abort ();
+
+  if (mempcpy (buf4 + 14, buf6, 2) != buf2 + 16
+      || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19))
+    abort ();
+
+  __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19);
+
+  /* These should be handled either by movstrendM or mempcpy
+     call.  */
+  if (mempcpy (buf4 + 4, buf7, n + 6) != buf2 + 10
+      || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19))
+    abort ();
+
+  if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, n + 1)
+      != buf2 + 12
+      || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19)
+      || i != 4)
+    abort ();
+
+  if (mempcpy (buf4 + 14, buf6, n + 2) != buf2 + 16
+      || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19))
+    abort ();
+
+  /* Now stpcpy tests.  */
+  if (stpcpy ((char *) buf3, "abcdefghijklmnop") != (char *) buf1 + 16
+      || memcmp (buf1, "abcdefghijklmnop", 17))
+    abort ();
+
+  if (__builtin_stpcpy ((char *) buf3, "ABCDEFG") != (char *) buf1 + 7
+      || memcmp (buf1, "ABCDEFG\0ijklmnop", 17))
+    abort ();
+
+  if (stpcpy ((char *) buf3 + i++, "x") != (char *) buf1 + 5
+      || memcmp (buf1, "ABCDx\0G\0ijklmnop", 17))
+    abort ();
+
+  return 0;
+}
+
+int
+main ()
+{
+  __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20);
+  __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20);
+  return test (buf1, buf2, "rstuvwxyz", 0);
+}
diff --git a/gcc/testsuite/gcc.dg/string-opt-1.c b/gcc/testsuite/gcc.dg/string-opt-1.c
new file mode 100644 (file)
index 0000000..bc0f300
--- /dev/null
@@ -0,0 +1,11 @@
+/* Ensure mempcpy is not "optimized" into memcpy followed by addition.  */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+void *
+fn (char *x, char *y, int z)
+{
+  return __builtin_mempcpy (x, y, z);
+}
+
+/* { dg-final { scan-assembler-not "memcpy" } } */