expr.h (store_by_pieces): Add prototype.
authorJakub Jelinek <jakub@redhat.com>
Wed, 29 Nov 2000 18:24:50 +0000 (19:24 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 29 Nov 2000 18:24:50 +0000 (19:24 +0100)
* expr.h (store_by_pieces): Add prototype.
(can_store_by_pieces): Likewise.
* expr.c (struct store_by_pieces): Renamed from clear_by_pieces.
(can_store_by_pieces): New.
(store_by_pieces): New.
(clear_by_pieces): New.
(clear_by_pieces_1): New.
(store_by_pieces_1): Renamed from clear_by_pieces, handle storing
arbitrary compiler generated constants into memory block.
(store_by_pieces_2): Renamed from clear_by_pieces_1, likewise.
* builtins.c (c_readstr): New.
(builtin_memcpy_read_str): New.
(expand_builtin_memcpy): If src is string constant and
emit_block_move would move it by pieces, compute integer constants
from the string and store it into memory block instead.
(builtin_strncpy_read_str): New.
(expand_builtin_strncpy): If N is not constant zero and c_strlen does
not return INTEGER_CST, don't optimize.
If N is larger than strlen(src) + 1, try to copy the string
including padding with store_by_pieces.
(expand_builtin_strcmp): If both arguments have side effects, don't
optimize.
(expand_builtin_fputs): If STR has side effects, don't optimize.

* gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy
tests.
* gcc.c-torture/execute/string-opt-6.c: New test.

From-SVN: r37851

gcc/ChangeLog
gcc/builtins.c
gcc/expr.c
gcc/expr.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/string-opt-5.c
gcc/testsuite/gcc.c-torture/execute/string-opt-6.c [new file with mode: 0644]

index db00db23bc4175df79d62fbc6bfed01eb31d2ce1..be3164c4414af4d071b1124e2d576ed245097e6a 100644 (file)
@@ -1,3 +1,29 @@
+2000-11-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * expr.h (store_by_pieces): Add prototype.
+       (can_store_by_pieces): Likewise.
+       * expr.c (struct store_by_pieces): Renamed from clear_by_pieces.
+       (can_store_by_pieces): New.
+       (store_by_pieces): New.
+       (clear_by_pieces): New.
+       (clear_by_pieces_1): New.
+       (store_by_pieces_1): Renamed from clear_by_pieces, handle storing
+       arbitrary compiler generated constants into memory block.
+       (store_by_pieces_2): Renamed from clear_by_pieces_1, likewise.
+       * builtins.c (c_readstr): New.
+       (builtin_memcpy_read_str): New.
+       (expand_builtin_memcpy): If src is string constant and
+       emit_block_move would move it by pieces, compute integer constants
+       from the string and store it into memory block instead.
+       (builtin_strncpy_read_str): New.
+       (expand_builtin_strncpy): If N is not constant zero and c_strlen does
+       not return INTEGER_CST, don't optimize.
+       If N is larger than strlen(src) + 1, try to copy the string
+       including padding with store_by_pieces.
+       (expand_builtin_strcmp): If both arguments have side effects, don't
+       optimize.
+       (expand_builtin_fputs): If STR has side effects, don't optimize.
+
 2000-11-29  Richard Earnshaw  <rearnsha@arm.com>
 
        * arm.md (sibcall, sibcall_value, sibcall_insn, sibcall_value_insn):
index 7db9b2622a2632b4277b9d3ae323e9395e91c061..07d10adf446bc7e7fa477ab57d2a71e16939fd4e 100644 (file)
@@ -81,6 +81,8 @@ tree (*lang_type_promotes_to) PARAMS ((tree));
 static int get_pointer_alignment       PARAMS ((tree, unsigned));
 static tree c_strlen                   PARAMS ((tree));
 static const char *c_getstr            PARAMS ((tree));
+static rtx c_readstr                   PARAMS ((const char *,
+                                                enum machine_mode));
 static rtx get_memory_rtx              PARAMS ((tree));
 static int apply_args_size             PARAMS ((void));
 static int apply_result_size           PARAMS ((void));
@@ -106,8 +108,12 @@ static rtx expand_builtin_strcmp   PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_strncmp      PARAMS ((tree, rtx,
                                                 enum machine_mode));
+static rtx builtin_memcpy_read_str     PARAMS ((PTR, HOST_WIDE_INT,
+                                                enum machine_mode));
 static rtx expand_builtin_memcpy       PARAMS ((tree));
 static rtx expand_builtin_strcpy       PARAMS ((tree));
+static rtx builtin_strncpy_read_str    PARAMS ((PTR, HOST_WIDE_INT,
+                                                enum machine_mode));
 static rtx expand_builtin_strncpy      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_memset       PARAMS ((tree));
@@ -308,6 +314,41 @@ c_getstr (src)
   return ptr + offset;
 }
 
+/* Return a CONST_INT or CONST_DOUBLE corresponding to target
+   reading GET_MODE_BITSIZE (MODE) bits from string constant
+   STR.  */
+static rtx
+c_readstr (str, mode)
+     const char *str;
+     enum machine_mode mode;
+{
+  HOST_WIDE_INT c[2];
+  HOST_WIDE_INT ch;
+  unsigned int i, j;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    abort ();
+  c[0] = 0;
+  c[1] = 0;
+  ch = 1;
+  for (i = 0; i < GET_MODE_SIZE (mode); i++)
+    {
+      j = i;
+      if (WORDS_BIG_ENDIAN)
+       j = GET_MODE_SIZE (mode) - i - 1;
+      if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
+         && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+       j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
+      j *= BITS_PER_UNIT;
+      if (j > 2 * HOST_BITS_PER_WIDE_INT)
+       abort ();
+      if (ch)
+       ch = (unsigned char) str[i];
+      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+    }
+  return immed_double_const (c[0], c[1], mode);
+}
+
 /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
    times to get the address of either a higher stack frame, or a return
    address located within it (depending on FNDECL_CODE).  */
@@ -1685,6 +1726,24 @@ expand_builtin_strpbrk (arglist, target, mode)
     }
 }
 
+/* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
+   bytes from constant string DATA + OFFSET and return it as target
+   constant.  */
+
+static rtx
+builtin_memcpy_read_str (data, offset, mode)
+     PTR data;
+     HOST_WIDE_INT offset;
+     enum machine_mode mode;
+{
+  const char *str = (const char *) data;
+
+  if (offset + GET_MODE_SIZE (mode) > strlen (str) + 1)
+    abort ();  /* Attempt to read past the end of constant string.  */
+
+  return c_readstr (str + offset, mode);
+}
+
 /* Expand a call to the memcpy builtin, with arguments in ARGLIST.  */
 static rtx
 expand_builtin_memcpy (arglist)
@@ -1706,6 +1765,7 @@ expand_builtin_memcpy (arglist)
       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;
 
       int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
@@ -1717,8 +1777,26 @@ expand_builtin_memcpy (arglist)
        return 0;
 
       dest_mem = get_memory_rtx (dest);
-      src_mem = get_memory_rtx (src);
       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+      src_str = c_getstr (src);
+
+      /* 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
+         && !current_function_check_memory_usage
+         && 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))
+       {
+         store_by_pieces (dest_mem, INTVAL (len_rtx),
+                          builtin_memcpy_read_str,
+                          (PTR) src_str, dest_align);
+         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       }
+
+      src_mem = get_memory_rtx (src);
 
       /* Just copy the rights of SRC to the rights of DEST.  */
       if (current_function_check_memory_usage)
@@ -1774,6 +1852,24 @@ expand_builtin_strcpy (exp)
   return result;
 }
 
+/* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
+   bytes from constant string DATA + OFFSET and return it as target
+   constant.  */
+
+static rtx
+builtin_strncpy_read_str (data, offset, mode)
+     PTR data;
+     HOST_WIDE_INT offset;
+     enum machine_mode mode;
+{
+  const char *str = (const char *) data;
+
+  if ((unsigned HOST_WIDE_INT) offset > strlen (str))
+    return const0_rtx;
+
+  return c_readstr (str + offset, mode);
+}
+
 /* Expand expression EXP, which is a call to the strncpy builtin.  Return 0
    if we failed the caller should emit a normal call.  */
 
@@ -1814,17 +1910,35 @@ expand_builtin_strncpy (arglist, target, mode)
          return expand_expr (TREE_VALUE (arglist), target, mode,
                              EXPAND_NORMAL);
        }
-      
+
       /* Now, we must be passed a constant src ptr parameter.  */
-      if (slen == 0)
+      if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
        return 0;
 
       slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
 
       /* We're required to pad with trailing zeros if the requested
-         len is greater than strlen(s2)+1, so in that case punt.  */
+         len is greater than strlen(s2)+1.  In that case try to
+        use store_by_pieces, if it fails, punt.  */
       if (tree_int_cst_lt (slen, len))
-       return 0;
+       {
+         tree dest = TREE_VALUE (arglist);
+         int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+         const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
+         rtx dest_mem;
+
+         if (!p || !dest_align || TREE_INT_CST_HIGH (len)
+             || !can_store_by_pieces (TREE_INT_CST_LOW (len),
+                                      builtin_strncpy_read_str,
+                                      (PTR) p, dest_align))
+           return 0;
+
+         dest_mem = get_memory_rtx (dest);
+         store_by_pieces (dest_mem, TREE_INT_CST_LOW (len),
+                          builtin_strncpy_read_str,
+                          (PTR) p, dest_align);
+         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       }
       
       /* OK transform into builtin memcpy.  */
       return expand_builtin_memcpy (arglist);
@@ -2081,7 +2195,8 @@ expand_builtin_strcmp (exp, target, mode)
     /* If we don't have a constant length for the first, use the length
        of the second, if we know it.  We don't require a constant for
        this case; some cost analysis could be done if both are available
-       but neither is constant.  For now, assume they're equally cheap.
+       but neither is constant.  For now, assume they're equally cheap
+       unless one has side effects.
 
        If both strings have constant lengths, use the smaller.  This
        could arise if optimization results in strcpy being called with
@@ -2091,7 +2206,7 @@ expand_builtin_strcmp (exp, target, mode)
 
     if (!len || TREE_CODE (len) != INTEGER_CST)
       {
-       if (len2)
+       if (len2 && !TREE_SIDE_EFFECTS (len2))
          len = len2;
        else if (len == 0)
          return 0;
@@ -2100,6 +2215,10 @@ expand_builtin_strcmp (exp, target, mode)
             && tree_int_cst_lt (len2, len))
       len = len2;
 
+    /* If both arguments have side effects, we cannot optimize.  */
+    if (TREE_SIDE_EFFECTS (len))
+      return 0;
+
     chainon (arglist, build_tree_list (NULL_TREE, len));
     result = expand_builtin_memcmp (exp, arglist, target);
     if (! result)
@@ -2760,7 +2879,8 @@ expand_builtin_fputs (arglist, ignore)
 
   /* Get the length of the string passed to fputs.  If the length
      can't be determined, punt.  */
-  if (!(len = c_strlen (TREE_VALUE (arglist))))
+  if (!(len = c_strlen (TREE_VALUE (arglist)))
+      || TREE_CODE (len) != INTEGER_CST)
     return 0;
 
   switch (compare_tree_int (len, 1))
index cbe46dd955802739ab4711d511de210aaaba842e..e520c6df7b4459e1fdc5357e0de3285ff19c3d0d 100644 (file)
@@ -127,10 +127,10 @@ struct move_by_pieces
   int reverse;
 };
 
-/* This structure is used by clear_by_pieces to describe the clear to
+/* This structure is used by store_by_pieces to describe the clear to
    be performed.  */
 
-struct clear_by_pieces
+struct store_by_pieces
 {
   rtx to;
   rtx to_addr;
@@ -138,6 +138,8 @@ struct clear_by_pieces
   int explicit_inc_to;
   unsigned HOST_WIDE_INT len;
   HOST_WIDE_INT offset;
+  rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+  PTR constfundata;
   int reverse;
 };
 
@@ -151,11 +153,15 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns
                                         unsigned int));
 static void move_by_pieces_1   PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
                                         struct move_by_pieces *));
+static rtx clear_by_pieces_1   PARAMS ((PTR, HOST_WIDE_INT,
+                                        enum machine_mode));
 static void clear_by_pieces    PARAMS ((rtx, unsigned HOST_WIDE_INT,
                                         unsigned int));
-static void clear_by_pieces_1  PARAMS ((rtx (*) (rtx, ...),
+static void store_by_pieces_1  PARAMS ((struct store_by_pieces *,
+                                        unsigned int));
+static void store_by_pieces_2  PARAMS ((rtx (*) (rtx, ...),
                                         enum machine_mode,
-                                        struct clear_by_pieces *));
+                                        struct store_by_pieces *));
 static rtx get_subtarget       PARAMS ((rtx));
 static int is_zeros_p          PARAMS ((tree));
 static int mostly_zeros_p      PARAMS ((tree));
@@ -2249,6 +2255,105 @@ use_group_regs (call_fusage, regs)
     }
 }
 \f
+
+int
+can_store_by_pieces (len, constfun, constfundata, align)
+     unsigned HOST_WIDE_INT len;
+     rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+     PTR constfundata;
+     unsigned int align;
+{
+  unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1, l;
+  HOST_WIDE_INT offset = 0;
+  enum machine_mode mode, tmode;
+  enum insn_code icode;
+  int reverse;
+  rtx cst;
+
+  if (! MOVE_BY_PIECES_P (len, align))
+    return 0;
+
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+    align = MOVE_MAX * BITS_PER_UNIT;
+
+  /* We would first store what we can in the largest integer mode, then go to
+     successively smaller modes.  */
+
+  for (reverse = 0;
+       reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT);
+       reverse++)
+    {
+      l = len;
+      mode = VOIDmode;
+      while (max_size > 1)
+       {
+         for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+              tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
+           if (GET_MODE_SIZE (tmode) < max_size)
+             mode = tmode;
+
+         if (mode == VOIDmode)
+           break;
+
+         icode = mov_optab->handlers[(int) mode].insn_code;
+         if (icode != CODE_FOR_nothing
+             && align >= GET_MODE_ALIGNMENT (mode))
+           {
+             unsigned int size = GET_MODE_SIZE (mode);
+
+             while (l >= size)
+               {
+                 if (reverse)
+                   offset -= size;
+
+                 cst = (*constfun) (constfundata, offset, mode);
+                 if (!LEGITIMATE_CONSTANT_P (cst))
+                   return 0;
+
+                 if (!reverse)
+                   offset += size;
+
+                 l -= size;
+               }
+           }
+
+         max_size = GET_MODE_SIZE (mode);
+       }
+
+      /* The code above should have handled everything.  */
+      if (l != 0)
+       abort ();
+    }
+
+  return 1;
+}
+
+/* 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.  */
+
+void
+store_by_pieces (to, len, constfun, constfundata, align)
+     rtx to;
+     unsigned HOST_WIDE_INT len;
+     rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+     PTR constfundata;
+     unsigned int align;
+{
+  struct store_by_pieces data;
+
+  if (! MOVE_BY_PIECES_P (len, align))
+    abort ();
+  to = protect_from_queue (to, 1);
+  data.constfun = constfun;
+  data.constfundata = constfundata;
+  data.len = len;
+  data.to = to;
+  store_by_pieces_1 (&data, align);
+}
+
 /* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
    rtx with BLKmode).  The caller must pass TO through protect_from_queue
    before calling. ALIGN is maximum alignment we can assume.  */
@@ -2259,31 +2364,59 @@ clear_by_pieces (to, len, align)
      unsigned HOST_WIDE_INT len;
      unsigned int align;
 {
-  struct clear_by_pieces data;
-  rtx to_addr = XEXP (to, 0);
+  struct store_by_pieces data;
+
+  data.constfun = clear_by_pieces_1;
+  data.constfundata = NULL_PTR;
+  data.len = len;
+  data.to = to;
+  store_by_pieces_1 (&data, align);
+}
+
+/* Callback routine for clear_by_pieces.
+   Return const0_rtx unconditionally.  */
+
+static rtx
+clear_by_pieces_1 (data, offset, mode)
+     PTR data ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return const0_rtx;
+}
+
+/* Subroutine of clear_by_pieces and store_by_pieces.
+   Generate several move instructions to store LEN bytes of block TO.  (A MEM
+   rtx with BLKmode).  The caller must pass TO through protect_from_queue
+   before calling.  ALIGN is maximum alignment we can assume.  */
+
+static void
+store_by_pieces_1 (data, align)
+     struct store_by_pieces *data;
+     unsigned int align;
+{
+  rtx to_addr = XEXP (data->to, 0);
   unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
-  data.offset = 0;
-  data.to_addr = to_addr;
-  data.to = to;
-  data.autinc_to
+  data->offset = 0;
+  data->to_addr = to_addr;
+  data->autinc_to
     = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
        || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
 
-  data.explicit_inc_to = 0;
-  data.reverse
+  data->explicit_inc_to = 0;
+  data->reverse
     = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
-  if (data.reverse)
-    data.offset = len;
-  data.len = len;
+  if (data->reverse)
+    data->offset = data->len;
 
-  /* If copying requires more than two move insns,
+  /* If storing requires more than two move insns,
      copy addresses to registers (to make displacements shorter)
      and use post-increment if available.  */
-  if (!data.autinc_to
-      && move_by_pieces_ninsns (len, align) > 2)
+  if (!data->autinc_to
+      && move_by_pieces_ninsns (data->len, align) > 2)
     {
       /* Determine the main mode we'll be using.  */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -2291,30 +2424,30 @@ clear_by_pieces (to, len, align)
        if (GET_MODE_SIZE (tmode) < max_size)
          mode = tmode;
 
-      if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
+      if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
        {
-         data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
-         data.autinc_to = 1;
-         data.explicit_inc_to = -1;
+         data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
+         data->autinc_to = 1;
+         data->explicit_inc_to = -1;
        }
 
-      if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse
-         && ! data.autinc_to)
+      if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
+         && ! data->autinc_to)
        {
-         data.to_addr = copy_addr_to_reg (to_addr);
-         data.autinc_to = 1;
-         data.explicit_inc_to = 1;
+         data->to_addr = copy_addr_to_reg (to_addr);
+         data->autinc_to = 1;
+         data->explicit_inc_to = 1;
        }
 
-      if ( !data.autinc_to && CONSTANT_P (to_addr))
-       data.to_addr = copy_addr_to_reg (to_addr);
+      if ( !data->autinc_to && CONSTANT_P (to_addr))
+       data->to_addr = copy_addr_to_reg (to_addr);
     }
 
   if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
       || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
     align = MOVE_MAX * BITS_PER_UNIT;
 
-  /* First move what we can in the largest integer mode, then go to
+  /* First store what we can in the largest integer mode, then go to
      successively smaller modes.  */
 
   while (max_size > 1)
@@ -2329,28 +2462,28 @@ clear_by_pieces (to, len, align)
 
       icode = mov_optab->handlers[(int) mode].insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
-       clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
+       store_by_pieces_2 (GEN_FCN (icode), mode, data);
 
       max_size = GET_MODE_SIZE (mode);
     }
 
   /* The code above should have handled everything.  */
-  if (data.len != 0)
+  if (data->len != 0)
     abort ();
 }
 
-/* Subroutine of clear_by_pieces.  Clear as many bytes as appropriate
+/* Subroutine of store_by_pieces_1.  Store as many bytes as appropriate
    with move instructions for mode MODE.  GENFUN is the gen_... function
    to make a move insn for that mode.  DATA has all the other info.  */
 
 static void
-clear_by_pieces_1 (genfun, mode, data)
+store_by_pieces_2 (genfun, mode, data)
      rtx (*genfun) PARAMS ((rtx, ...));
      enum machine_mode mode;
-     struct clear_by_pieces *data;
+     struct store_by_pieces *data;
 {
   unsigned int size = GET_MODE_SIZE (mode);
-  rtx to1;
+  rtx to1, cst;
 
   while (data->len >= size)
     {
@@ -2367,9 +2500,11 @@ clear_by_pieces_1 (genfun, mode, data)
                              plus_constant (data->to_addr, data->offset));
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
-       emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
+       emit_insn (gen_add2_insn (data->to_addr,
+                                 GEN_INT (-(HOST_WIDE_INT) size)));
 
-      emit_insn ((*genfun) (to1, const0_rtx));
+      cst = (*data->constfun) (data->constfundata, data->offset, mode);
+      emit_insn ((*genfun) (to1, cst));
 
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
index 8cb283610381283b41eede2d8f20e316db633e31..74af2d9957fec1857d1db33da387d5cbe5975e75 100644 (file)
@@ -1010,6 +1010,25 @@ extern void use_group_regs PARAMS ((rtx *, rtx));
    alignment.  */
 extern rtx clear_storage PARAMS ((rtx, rtx, unsigned int));
 
+/* Return non-zero 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
+   in every CONSTFUN call.
+   ALIGN is maximum alignment we can assume.  */
+extern int can_store_by_pieces PARAMS ((unsigned HOST_WIDE_INT,
+                                       rtx (*) (PTR, HOST_WIDE_INT,
+                                                enum machine_mode),
+                                       PTR, unsigned 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));
+
 /* Emit insns to set X from Y.  */
 extern rtx emit_move_insn PARAMS ((rtx, rtx));
 
index 6079e4a3bf67e0d9c97316bd57f600e09db566a9..d957093118e3a5b86802182f9f97544008343ac9 100644 (file)
@@ -1,3 +1,9 @@
+2000-11-29  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy
+       tests.
+       * gcc.c-torture/execute/string-opt-6.c: New test.
+
 2000-11-28  Geoffrey Keating  <geoffk@redhat.com>
 
        * gcc.dg/noncompile/940510-1.c: Update to test c89 functionality.
index 79b451d7f79d3dccf8748aec0f389d3e48de5130..108c3ed4773889d7efdbb187bfee8824bae7f703 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (C) 2000  Free Software Foundation.
 
-   Ensure builtin strlen, strcmp, strchr and strrchr perform correctly.
+   Ensure builtin strlen, strcmp, strchr, strrchr and strncpy
+   perform correctly.
 
    Written by Jakub Jelinek, 11/7/2000.  */
 
@@ -9,13 +10,18 @@ extern __SIZE_TYPE__ strlen (const char *);
 extern int strcmp (const char *, const char *);
 extern char *strchr (const char *, int);
 extern char *strrchr (const char *, int);
+extern char *strncpy (char *, const char *, __SIZE_TYPE__);
+extern void *memset (void *, int, __SIZE_TYPE__);
+extern int memcmp (const void *, const void *, __SIZE_TYPE__);
 
 int x = 6;
+int y = 1;
 char *bar = "hi world";
 
 int main()
 {
   const char *const foo = "hello world";
+  char dst [64];
 
   if (strlen (bar) != 8)
     abort ();
@@ -53,6 +59,27 @@ int main()
     abort ();
   if (strrchr (bar, 'o') != bar + 4)
     abort ();
+  if (strcmp (foo + (x++ & 1), "ello world" + (--y & 1)))
+    abort ();
+  if (x != 6 || y != 0)
+    abort ();
+  dst[5] = ' ';
+  dst[6] = '\0';
+  x = 5;
+  y = 1;
+  if (strncpy (dst + 1, foo + (x++ & 3), 4) != dst + 1
+      || x != 6
+      || strcmp (dst + 1, "ello "))
+    abort ();
+  memset (dst, ' ', sizeof dst);
+  if (strncpy (dst + (++x & 1), (y++ & 3) + "foo", 10) != dst + 1
+      || x != 7
+      || y != 2
+      || memcmp (dst, " oo\0\0\0\0\0\0\0\0 ", 12))
+    abort ();
+  memset (dst, ' ', sizeof dst);
+  if (strncpy (dst, "hello", 8) != dst || memcmp (dst, "hello\0\0\0 ", 9))
+    abort();
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-6.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-6.c
new file mode 100644 (file)
index 0000000..781d96f
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000  Free Software Foundation.
+
+   Ensure builtin memcpy and strcpy perform correctly.
+
+   Written by Jakub Jelinek, 11/24/2000.  */
+
+extern void abort (void);
+extern char *strcpy (char *, const char *);
+typedef __SIZE_TYPE__ size_t;
+extern void *memcpy (void *, const void *, size_t);
+extern int memcmp (const void *, const void *, size_t);
+
+char p[32] = "";
+
+int main()
+{
+  if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6))
+    abort ();
+  if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5))
+    abort ();
+  if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6))
+    abort ();  
+  if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9))
+    abort ();
+  if (memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6))
+    abort ();
+  if (memcpy (p + 16, "VWX" + 1, 2) != p + 16 || memcmp (p + 16, "WXyz", 5))
+    abort ();
+  if (memcpy (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6))
+    abort ();  
+  if (memcpy (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHIj", 9))
+    abort ();
+
+  return 0;
+}
+
+#ifdef __OPTIMIZE__
+/* When optimizing, all the above cases should be transformed into
+   something else.  So any remaining calls to the original function
+   should abort.  */
+static char *
+strcpy (char *d, const char *s)
+{
+  abort ();
+}
+#endif