OSDN Git Service

PR rtl-optimization/38245
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 15 Jan 2009 08:07:38 +0000 (08:07 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 15 Jan 2009 08:07:38 +0000 (08:07 +0000)
* calls.c (expand_call): Add stack arguments to
CALL_INSN_FUNCTION_USAGE even for pure calls (when
ACCUMULATE_OUTGOING_ARGS) and even for args partially passed
in regs and partially in memory or BLKmode arguments.
(emit_library_call_value_1): Add stack arguments to
CALL_INSN_FUNCTION_USAGE even for pure calls (when
ACCUMULATE_OUTGOING_ARGS).
* dce.c: Include tm_p.h.
(find_call_stack_args): New function.
(deletable_insn_p): Call it for CALL_P insns.  Add ARG_STORES
argument.
(mark_insn): Call find_call_stack_args for CALL_Ps.
(prescan_insns_for_dce): Walk insns backwards in bb rather than
forwards.  Allocate and free arg_stores bitmap if needed, pass it
down to deletable_insn_p, don't mark stores set in arg_stores
bitmap, clear the bitmap at the beginning of each bb.
* Makefile.in (dce.o): Depend on $(TM_P_H).

* gcc.dg/pr38245-3.c: New test.
* gcc.dg/pr38245-3.h: New file.
* gcc.dg/pr38245-4.c: New file.
* gcc.dg/pr38364.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@143387 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/calls.c
gcc/dce.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr38245-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr38245-3.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr38245-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr38364.c [new file with mode: 0644]

index dff3716..aeab680 100644 (file)
@@ -1,3 +1,24 @@
+2009-01-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/38245
+       * calls.c (expand_call): Add stack arguments to
+       CALL_INSN_FUNCTION_USAGE even for pure calls (when
+       ACCUMULATE_OUTGOING_ARGS) and even for args partially passed
+       in regs and partially in memory or BLKmode arguments.
+       (emit_library_call_value_1): Add stack arguments to
+       CALL_INSN_FUNCTION_USAGE even for pure calls (when
+       ACCUMULATE_OUTGOING_ARGS).
+       * dce.c: Include tm_p.h.
+       (find_call_stack_args): New function.
+       (deletable_insn_p): Call it for CALL_P insns.  Add ARG_STORES
+       argument.
+       (mark_insn): Call find_call_stack_args for CALL_Ps.
+       (prescan_insns_for_dce): Walk insns backwards in bb rather than
+       forwards.  Allocate and free arg_stores bitmap if needed, pass it
+       down to deletable_insn_p, don't mark stores set in arg_stores
+       bitmap, clear the bitmap at the beginning of each bb.
+       * Makefile.in (dce.o): Depend on $(TM_P_H).
+
 2009-01-14  Michael Meissner  <gnu@the-meissners.org>
 
        PR target/22599
index 75eeac9..2190d43 100644 (file)
@@ -2672,7 +2672,7 @@ cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
    $(DF_H) $(DBGCNT_H)
 dce.o : dce.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) $(DF_H) cselib.h \
-   $(DBGCNT_H) dce.h $(TIMEVAR_H) tree-pass.h $(DBGCNT_H)
+   $(DBGCNT_H) dce.h $(TIMEVAR_H) tree-pass.h $(DBGCNT_H) $(TM_P_H)
 dse.o : dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(TM_P_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \
    $(RECOG_H) $(EXPR_H) $(DF_H) cselib.h $(DBGCNT_H) $(TIMEVAR_H) tree-pass.h \
index f6bc970..a75e3b3 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -2705,26 +2705,28 @@ expand_call (tree exp, rtx target, int ignore)
         but we do preallocate space here if they want that.  */
 
       for (i = 0; i < num_actuals; i++)
-       if (args[i].reg == 0 || args[i].pass_on_stack)
-         {
-           rtx before_arg = get_last_insn ();
-
-           if (store_one_arg (&args[i], argblock, flags,
-                              adjusted_args_size.var != 0,
-                              reg_parm_stack_space)
-               || (pass == 0
-                   && check_sibcall_argument_overlap (before_arg,
-                                                      &args[i], 1)))
-             sibcall_failure = 1;
-
-           if (flags & ECF_CONST
-               && args[i].stack
-               && args[i].value == args[i].stack)
-             call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
-                                              gen_rtx_USE (VOIDmode,
-                                                           args[i].value),
-                                              call_fusage);
-         }
+       {
+         if (args[i].reg == 0 || args[i].pass_on_stack)
+           {
+             rtx before_arg = get_last_insn ();
+
+             if (store_one_arg (&args[i], argblock, flags,
+                                adjusted_args_size.var != 0,
+                                reg_parm_stack_space)
+                 || (pass == 0
+                     && check_sibcall_argument_overlap (before_arg,
+                                                        &args[i], 1)))
+               sibcall_failure = 1;
+             }
+
+         if (((flags & ECF_CONST)
+              || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
+             && args[i].stack)
+           call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
+                                            gen_rtx_USE (VOIDmode,
+                                                         args[i].stack),
+                                            call_fusage);
+       }
 
       /* If we have a parm that is passed in registers but not in memory
         and whose alignment does not permit a direct copy into registers,
@@ -3672,7 +3674,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
          NO_DEFER_POP;
 
-         if (flags & ECF_CONST)
+         if ((flags & ECF_CONST)
+             || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
            {
              rtx use;
 
index 08a0f50..75e148c 100644 (file)
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -1,5 +1,5 @@
 /* RTL dead code elimination.
-   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "tree-pass.h"
 #include "dbgcnt.h"
+#include "tm_p.h"
 
 DEF_VEC_I(int);
 DEF_VEC_ALLOC_I(int,heap);
@@ -57,6 +58,7 @@ static sbitmap marked;
 static bitmap_obstack dce_blocks_bitmap_obstack;
 static bitmap_obstack dce_tmp_bitmap_obstack;
 
+static bool find_call_stack_args (rtx, bool, bool, bitmap);
 
 /* A subroutine for which BODY is part of the instruction being tested;
    either the top-level pattern, or an element of a PARALLEL.  The
@@ -94,7 +96,7 @@ deletable_insn_p_1 (rtx body)
    the DCE pass.  */
 
 static bool
-deletable_insn_p (rtx insn, bool fast)
+deletable_insn_p (rtx insn, bool fast, bitmap arg_stores)
 {
   rtx body, x;
   int i;
@@ -111,7 +113,7 @@ deletable_insn_p (rtx insn, bool fast)
          infinite loop.  */
       && (RTL_CONST_OR_PURE_CALL_P (insn)
          && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
-    return true;
+    return find_call_stack_args (insn, false, fast, arg_stores);
 
   if (!NONJUMP_INSN_P (insn))
     return false;
@@ -174,6 +176,12 @@ mark_insn (rtx insn, bool fast)
       SET_BIT (marked, INSN_UID (insn));
       if (dump_file)
        fprintf (dump_file, "  Adding insn %d to worklist\n", INSN_UID (insn));
+      if (CALL_P (insn)
+         && !df_in_progress
+         && !SIBLING_CALL_P (insn)
+         && (RTL_CONST_OR_PURE_CALL_P (insn)
+             && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
+       find_call_stack_args (insn, true, fast, NULL);
     }
 }
 
@@ -212,6 +220,254 @@ mark_nonreg_stores (rtx body, rtx insn, bool fast)
 }
 
 
+/* Try to find all stack stores of CALL_INSN arguments if
+   ACCUMULATE_OUTGOING_ARGS.  If all stack stores have been found
+   and it is therefore safe to eliminate the call, return true,
+   otherwise return false.  This function should be first called
+   with DO_MARK false, and only when the CALL_INSN is actually
+   going to be marked called again with DO_MARK true.  */
+
+static bool
+find_call_stack_args (rtx call_insn, bool do_mark, bool fast,
+                     bitmap arg_stores)
+{
+  rtx p, insn, prev_insn;
+  bool ret;
+  HOST_WIDE_INT min_sp_off, max_sp_off;
+  bitmap sp_bytes;
+
+  gcc_assert (CALL_P (call_insn));
+  if (!ACCUMULATE_OUTGOING_ARGS)
+    return true;
+
+  if (!do_mark)
+    {
+      gcc_assert (arg_stores);
+      bitmap_clear (arg_stores);
+    }
+
+  min_sp_off = INTTYPE_MAXIMUM (HOST_WIDE_INT);
+  max_sp_off = 0;
+
+  /* First determine the minimum and maximum offset from sp for
+     stored arguments.  */
+  for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
+    if (GET_CODE (XEXP (p, 0)) == USE
+       && MEM_P (XEXP (XEXP (p, 0), 0)))
+      {
+       rtx mem = XEXP (XEXP (p, 0), 0), addr, size;
+       HOST_WIDE_INT off = 0;
+       size = MEM_SIZE (mem);
+       if (size == NULL_RTX)
+         return false;
+       addr = XEXP (mem, 0);
+       if (GET_CODE (addr) == PLUS
+           && REG_P (XEXP (addr, 0))
+           && CONST_INT_P (XEXP (addr, 1)))
+         {
+           off = INTVAL (XEXP (addr, 1));
+           addr = XEXP (addr, 0);
+         }
+       if (addr != stack_pointer_rtx)
+         {
+           if (!REG_P (addr))
+             return false;
+           /* If not fast, use chains to see if addr wasn't set to
+              sp + offset.  */
+           if (!fast)
+             {
+               df_ref *use_rec;
+               struct df_link *defs;
+               rtx set;
+
+               for (use_rec = DF_INSN_USES (call_insn); *use_rec; use_rec++)
+                 if (rtx_equal_p (addr, DF_REF_REG (*use_rec)))
+                   break;
+
+               if (*use_rec == NULL)
+                 return false;
+
+               for (defs = DF_REF_CHAIN (*use_rec); defs; defs = defs->next)
+                 if (! DF_REF_IS_ARTIFICIAL (defs->ref))
+                   break;
+
+               if (defs == NULL)
+                 return false;
+
+               set = single_set (DF_REF_INSN (defs->ref));
+               if (!set)
+                 return false;
+
+               if (GET_CODE (SET_SRC (set)) != PLUS
+                   || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
+                   || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
+                 return false;
+
+               off += INTVAL (XEXP (SET_SRC (set), 1));
+             }
+           else
+             return false;
+         }
+       min_sp_off = MIN (min_sp_off, off);
+       max_sp_off = MAX (max_sp_off, off + INTVAL (size));
+      }
+
+  if (min_sp_off >= max_sp_off)
+    return true;
+  sp_bytes = BITMAP_ALLOC (NULL);
+
+  /* Set bits in SP_BYTES bitmap for bytes relative to sp + min_sp_off
+     which contain arguments.  Checking has been done in the previous
+     loop.  */
+  for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
+    if (GET_CODE (XEXP (p, 0)) == USE
+       && MEM_P (XEXP (XEXP (p, 0), 0)))
+      {
+       rtx mem = XEXP (XEXP (p, 0), 0), addr;
+       HOST_WIDE_INT off = 0, byte;
+       addr = XEXP (mem, 0);
+       if (GET_CODE (addr) == PLUS
+           && REG_P (XEXP (addr, 0))
+           && CONST_INT_P (XEXP (addr, 1)))
+         {
+           off = INTVAL (XEXP (addr, 1));
+           addr = XEXP (addr, 0);
+         }
+       if (addr != stack_pointer_rtx)
+         {
+           df_ref *use_rec;
+           struct df_link *defs;
+           rtx set;
+
+           for (use_rec = DF_INSN_USES (call_insn); *use_rec; use_rec++)
+             if (rtx_equal_p (addr, DF_REF_REG (*use_rec)))
+               break;
+
+           for (defs = DF_REF_CHAIN (*use_rec); defs; defs = defs->next)
+             if (! DF_REF_IS_ARTIFICIAL (defs->ref))
+               break;
+
+           set = single_set (DF_REF_INSN (defs->ref));
+           off += INTVAL (XEXP (SET_SRC (set), 1));
+         }
+       for (byte = off; byte < off + INTVAL (MEM_SIZE (mem)); byte++)
+         {
+           gcc_assert (!bitmap_bit_p (sp_bytes, byte - min_sp_off));
+           bitmap_set_bit (sp_bytes, byte - min_sp_off);
+         }
+      }
+
+  /* Walk backwards, looking for argument stores.  The search stops
+     when seeting another call, sp adjustment or memory store other than
+     argument store.  */
+  ret = false;
+  for (insn = PREV_INSN (call_insn); insn; insn = prev_insn)
+    {
+      rtx set, mem, addr;
+      HOST_WIDE_INT off, byte;
+
+      if (insn == BB_HEAD (BLOCK_FOR_INSN (call_insn)))
+       prev_insn = NULL_RTX;
+      else
+       prev_insn = PREV_INSN (insn);
+
+      if (CALL_P (insn))
+       break;
+
+      if (!INSN_P (insn))
+       continue;
+
+      set = single_set (insn);
+      if (!set || SET_DEST (set) == stack_pointer_rtx)
+       break;
+
+      if (!MEM_P (SET_DEST (set)))
+       continue;
+
+      mem = SET_DEST (set);
+      addr = XEXP (mem, 0);
+      off = 0;
+      if (GET_CODE (addr) == PLUS
+         && REG_P (XEXP (addr, 0))
+         && CONST_INT_P (XEXP (addr, 1)))
+       {
+         off = INTVAL (XEXP (addr, 1));
+         addr = XEXP (addr, 0);
+       }
+      if (addr != stack_pointer_rtx)
+       {
+         if (!REG_P (addr))
+           break;
+         if (!fast)
+           {
+             df_ref *use_rec;
+             struct df_link *defs;
+             rtx set;
+
+             for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+               if (rtx_equal_p (addr, DF_REF_REG (*use_rec)))
+                 break;
+
+             if (*use_rec == NULL)
+               break;
+
+             for (defs = DF_REF_CHAIN (*use_rec); defs; defs = defs->next)
+               if (! DF_REF_IS_ARTIFICIAL (defs->ref))
+                 break;
+
+             if (defs == NULL)
+               break;
+
+             set = single_set (DF_REF_INSN (defs->ref));
+             if (!set)
+               break;
+
+             if (GET_CODE (SET_SRC (set)) != PLUS
+                 || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
+                 || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
+               break;
+
+             off += INTVAL (XEXP (SET_SRC (set), 1));
+           }
+         else
+           break;
+       }
+
+      if (GET_MODE_SIZE (GET_MODE (mem)) == 0)
+       break;
+
+      for (byte = off; byte < off + GET_MODE_SIZE (GET_MODE (mem)); byte++)
+       {
+         if (byte < min_sp_off
+             || byte >= max_sp_off
+             || !bitmap_bit_p (sp_bytes, byte - min_sp_off))
+           break;
+         bitmap_clear_bit (sp_bytes, byte - min_sp_off);
+       }
+
+      if (!deletable_insn_p (insn, fast, NULL))
+       break;
+
+      if (do_mark)
+       mark_insn (insn, fast);
+      else
+       bitmap_set_bit (arg_stores, INSN_UID (insn));
+
+      if (bitmap_empty_p (sp_bytes))
+       {
+         ret = true;
+         break;
+       }
+    }
+
+  BITMAP_FREE (sp_bytes);
+  if (!ret && arg_stores)
+    bitmap_clear (arg_stores);
+
+  return ret;
+}
+
+
 /* Delete all REG_EQUAL notes of the registers INSN writes, to prevent
    bad dangling REG_EQUAL notes. */
 
@@ -266,6 +522,9 @@ delete_unmarked_insns (void)
          else if (marked_insn_p (insn))
            continue;
 
+         /* Beware that reaching a dbg counter limit here can easily result
+            in miscompiled file, whenever some insn is eliminated, but
+            insn that depends on it is not.  */
          if (!dbg_cnt (dce))
            continue;
 
@@ -300,20 +559,37 @@ static void
 prescan_insns_for_dce (bool fast)
 {
   basic_block bb;
-  rtx insn, next;
-  
+  rtx insn, prev;
+  bitmap arg_stores = NULL;
+
   if (dump_file)
     fprintf (dump_file, "Finding needed instructions:\n");
-  
+
+  if (!df_in_progress && ACCUMULATE_OUTGOING_ARGS)
+    arg_stores = BITMAP_ALLOC (NULL);
+
   FOR_EACH_BB (bb)
-    FOR_BB_INSNS_SAFE (bb, insn, next)
-      if (INSN_P (insn))
-       {
-         if (deletable_insn_p (insn, fast))
-           mark_nonreg_stores (PATTERN (insn), insn, fast);
-         else
-           mark_insn (insn, fast);
-       }
+    {
+      FOR_BB_INSNS_REVERSE_SAFE (bb, insn, prev)
+       if (INSN_P (insn))
+         {
+           /* Don't mark argument stores now.  They will be marked
+              if needed when the associated CALL is marked.  */
+           if (arg_stores && bitmap_bit_p (arg_stores, INSN_UID (insn)))
+             continue;
+           if (deletable_insn_p (insn, fast, arg_stores))
+             mark_nonreg_stores (PATTERN (insn), insn, fast);
+           else
+             mark_insn (insn, fast);
+         }
+      /* find_call_stack_args only looks at argument stores in the
+        same bb.  */
+      if (arg_stores)
+       bitmap_clear (arg_stores);
+    }
+
+  if (arg_stores)
+    BITMAP_FREE (arg_stores);
 
   if (dump_file)
     fprintf (dump_file, "Finished finding needed instructions:\n");
index 4d8c384..fae2df8 100644 (file)
@@ -1,3 +1,11 @@
+2009-01-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/38245
+       * gcc.dg/pr38245-3.c: New test.
+       * gcc.dg/pr38245-3.h: New file.
+       * gcc.dg/pr38245-4.c: New file.
+       * gcc.dg/pr38364.c: New test.
+
 2009-01-14  Adam Nemet  <anemet@caviumnetworks.com>
 
        * gcc.target/mips/mips.exp (mips_option_tests(-mips16)): Make the
diff --git a/gcc/testsuite/gcc.dg/pr38245-3.c b/gcc/testsuite/gcc.dg/pr38245-3.c
new file mode 100644 (file)
index 0000000..6ef8372
--- /dev/null
@@ -0,0 +1,112 @@
+/* PR rtl-optimization/38245 */
+/* { dg-do run } */
+/* { dg-additional-sources "pr38245-4.c" } */
+/* { dg-options "-O2" } */
+
+#include "pr38245-3.h"
+
+extern void abort (void);
+
+struct A { int i, j; union { short s[4]; long long l; }; char pad[512]; } a;
+int globv = 6;
+
+void __attribute__((noinline))
+f1 (void)
+{
+  a.s[2] = b1 (6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+              6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f2 (void)
+{
+  a.s[2] = b2 (6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+              6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f3 (void)
+{
+  struct B b = { 30, 31, { 32, 33 } };
+  a.s[2] = b3 (6, 7, 8, 9, 10, 11, 12, b, 14, b, 16, b, 18, 19, 20, 21,
+              6, b, 8, b, 10, 11, 12, 13, 14, b, 16, b, 18, 19, 20, 21);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f4 (void)
+{
+  struct B b = { 30, 31, { 32, 33 } };
+  a.s[2] = b4 (6, 7, 8, 9, 10, 11, 12, b, 14, b, 16, b, 18, 19, 20, 21,
+              6, b, 8, b, 10, 11, 12, 13, 14, b, 16, b, 18, 19, 20, 21);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f5 (void)
+{
+  a.s[2] = b5 (6.0, 7, 8, 9, 10, 11, 21.0, 22.0, 23.0);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f6 (void)
+{
+  a.s[2] = b6 (6.0, 7, 8, 9, 10, 11, 21.0, 22.0, 23.0);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f7 (void)
+{
+  a.s[2] = b7 (6, 7);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f8 (void)
+{
+  a.s[2] = b8 (6, 7);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f9 (void)
+{
+  a.s[2] = b9 (6, 7, 8, 9, 10, 11, 12);
+  a.l = 6;
+}
+
+void __attribute__((noinline))
+f10 (void)
+{
+  a.s[2] = b10 (6, 7, 8, 9, 10, 11, 12);
+  a.l = 6;
+}
+
+int
+main (void)
+{
+  char buf[256];
+  int i;
+  for (i = 0; i < (int) sizeof buf; i++)
+    buf[i] = i;
+  asm volatile ("" : : "r" (buf) : "memory");
+  f1 ();
+  f2 ();
+  f3 ();
+  f4 ();
+  f5 ();
+  f6 ();
+  f7 ();
+  f8 ();
+  f9 ();
+  f10 ();
+  asm volatile ("" : : "r" (buf) : "memory");
+  for (i = 0; i < (int) sizeof buf; i++)
+    if (buf[i] != (char) i)
+      abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr38245-3.h b/gcc/testsuite/gcc.dg/pr38245-3.h
new file mode 100644 (file)
index 0000000..b1c2a0f
--- /dev/null
@@ -0,0 +1,35 @@
+/* PR rtl-optimization/38245 */
+
+struct B { long a, b; char p[32]; };
+extern int globv;
+
+extern int b1 (long long, long, long, long, long, long, long, long,
+              long long, long, long, long, long, long, long, long,
+              long long, long, long, long, long, long, long, long,
+              long long, long, long, long, long, long, long, long)
+     __attribute__((pure, noinline));
+extern int b2 (long long, long, long, long, long, long, long, long,
+              long long, long, long, long, long, long, long, long,
+              long long, long, long, long, long, long, long, long,
+              long long, long, long, long, long, long, long, long)
+     __attribute__((const, noinline));
+extern int b3 (long long, long, long, long, long, long, long, struct B,
+              long long, struct B, long, struct B, long, long, long, long,
+              long long, struct B, long, struct B, long, long, long, long,
+              long long, struct B, long, struct B, long, long, long, long)
+     __attribute__((pure, noinline));
+extern int b4 (long long, long, long, long, long, long, long, struct B,
+              long long, struct B, long, struct B, long, long, long, long,
+              long long, struct B, long, struct B, long, long, long, long,
+              long long, struct B, long, struct B, long, long, long, long)
+     __attribute__((const, noinline));
+extern int b5 () __attribute__((pure, noinline));
+extern int b6 () __attribute__((const, noinline));
+extern int b7 (int, int)
+     __attribute__((pure, noinline));
+extern int b8 (int, int)
+     __attribute__((const, noinline));
+extern int b9 (int, int, int, int, int, int, int)
+     __attribute__((pure, noinline));
+extern int b10 (int, int, int, int, int, int, int)
+     __attribute__((const, noinline));
diff --git a/gcc/testsuite/gcc.dg/pr38245-4.c b/gcc/testsuite/gcc.dg/pr38245-4.c
new file mode 100644 (file)
index 0000000..c9b3d2d
--- /dev/null
@@ -0,0 +1,107 @@
+/* PR rtl-optimization/38245 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include "pr38245-3.h"
+
+int
+b1 (long long a1, long a2, long a3, long a4,
+    long a5, long a6, long a7, long a8,
+    long long a9, long a10, long a11, long a12,
+    long a13, long a14, long a15, long a16,
+    long long a17, long a18, long a19, long a20,
+    long a21, long a22, long a23, long a24,
+    long long a25, long a26, long a27, long a28,
+    long a29, long a30, long a31, long a32)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10
+        + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20
+        + a21 + a22 + a23 + a24 + a25 + a26 + a27 + a28 + a29 + a30
+        + a31 + a32 + globv;
+}
+
+int
+b2 (long long a1, long a2, long a3, long a4,
+    long a5, long a6, long a7, long a8,
+    long long a9, long a10, long a11, long a12,
+    long a13, long a14, long a15, long a16,
+    long long a17, long a18, long a19, long a20,
+    long a21, long a22, long a23, long a24,
+    long long a25, long a26, long a27, long a28,
+    long a29, long a30, long a31, long a32)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10
+        + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20
+        + a21 + a22 + a23 + a24 + a25 + a26 + a27 + a28 + a29 + a30
+        + a31 + a32;
+}
+
+int
+b3 (long long a1, long a2, long a3, long a4,
+    long a5, long a6, long a7, struct B a8,
+    long long a9, struct B a10, long a11, struct B a12,
+    long a13, long a14, long a15, long a16,
+    long long a17, struct B a18, long a19, struct B a20,
+    long a21, long a22, long a23, long a24,
+    long long a25, struct B a26, long a27, struct B a28,
+    long a29, long a30, long a31, long a32)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8.a + a9 + a10.a
+        + a11 + a12.a + a13 + a14 + a15 + a16 + a17 + a18.a + a19 + a20.a
+        + a21 + a22 + a23 + a24 + a25 + a26.a + a27 + a28.a + a29 + a30
+        + a31 + a32 + globv;
+}
+
+int
+b4 (long long a1, long a2, long a3, long a4,
+    long a5, long a6, long a7, struct B a8,
+    long long a9, struct B a10, long a11, struct B a12,
+    long a13, long a14, long a15, long a16,
+    long long a17, struct B a18, long a19, struct B a20,
+    long a21, long a22, long a23, long a24,
+    long long a25, struct B a26, long a27, struct B a28,
+    long a29, long a30, long a31, long a32)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8.a + a9 + a10.a
+        + a11 + a12.a + a13 + a14 + a15 + a16 + a17 + a18.a + a19 + a20.a
+        + a21 + a22 + a23 + a24 + a25 + a26.a + a27 + a28.a + a29 + a30
+        + a31 + a32;
+}
+
+int
+b5 (double a1, int a2, int a3, int a4, int a5, int a6, double a7,
+    double a8, double a9)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + globv;
+}
+
+int
+b6 (double a1, int a2, int a3, int a4, int a5, int a6, double a7,
+    double a8, double a9)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9;
+}
+
+int
+b7 (int a1, int a2)
+{
+  return a1 + a2 + globv;
+}
+
+int
+b8 (int a1, int a2)
+{
+  return a1 + a2;
+}
+
+int
+b9 (int a1, int a2, int a3, int a4, int a5, int a6, int a7)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7 + globv;
+}
+
+int
+b10 (int a1, int a2, int a3, int a4, int a5, int a6, int a7)
+{
+  return a1 + a2 + a3 + a4 + a5 + a6 + a7;
+}
diff --git a/gcc/testsuite/gcc.dg/pr38364.c b/gcc/testsuite/gcc.dg/pr38364.c
new file mode 100644 (file)
index 0000000..23f72de
--- /dev/null
@@ -0,0 +1,79 @@
+/* PR middle-end/38364 */
+/* { dg-do run } */
+/* { dg-options "-O2 -ftrapv" } */
+
+extern void abort (void);
+
+static inline short
+f1 (short x, short y)
+{
+  if (x > 0)
+    {
+      if (y > 0)
+       {
+         if (x > __SHRT_MAX__ / y)
+           return x;
+       }
+      else if (y < (-__SHRT_MAX__ - 1) / x)
+       return x;
+    }
+  else
+    {
+      if (y > 0)
+       {
+         if (x < (-__SHRT_MAX__ - 1) / y)
+           return x;
+       }
+      else if (x != 0 && y < __SHRT_MAX__ / x)
+       return x;
+    }
+  return x * y;
+}
+
+static inline signed char
+f2 (signed char x, signed char y)
+{
+  if (((x ^ y) & (((x ^ ((x ^ y) & (1 << (__CHAR_BIT__ - 1)))) - y) ^ y)) < 0)
+    return x;
+  return x - y;
+}
+
+unsigned int v;
+
+int
+f3 (int x, unsigned int y)
+{
+  f1 (1, 1);
+  return 1;
+}
+
+int
+f4 (unsigned short x)
+{
+  v = x;
+  return 1;
+}
+
+int
+f5 (int x)
+{
+  if (f2 (x, 1))
+    f1 (1, f4 (1));
+  return x;
+}
+
+int
+f6 (unsigned int x)
+{
+  f4 (x < (1 != f5 (0)));
+  return x;
+}
+
+int
+main (void)
+{
+  f6 (1);
+  if (v != 0)
+    abort ();
+  return 0;
+}