aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2009-01-15 09:07:38 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2009-01-15 09:07:38 +0100
commit0196c95ed418b0cd0f6c648018da34f947a76e90 (patch)
treedf30f7de379a5cadc80eb495456de5a3b9f9d10b /gcc
parent6df6bcfa0fde9cc6413088d609f799188444f51b (diff)
downloadgcc-0196c95ed418b0cd0f6c648018da34f947a76e90.zip
gcc-0196c95ed418b0cd0f6c648018da34f947a76e90.tar.gz
gcc-0196c95ed418b0cd0f6c648018da34f947a76e90.tar.bz2
re PR rtl-optimization/38245 (stack corruption when a call is removed but not the outgoing argument pushes)
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). * 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. From-SVN: r143387
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog21
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/calls.c47
-rw-r--r--gcc/dce.c304
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.dg/pr38245-3.c112
-rw-r--r--gcc/testsuite/gcc.dg/pr38245-3.h35
-rw-r--r--gcc/testsuite/gcc.dg/pr38245-4.c107
-rw-r--r--gcc/testsuite/gcc.dg/pr38364.c79
9 files changed, 678 insertions, 37 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dff3716..aeab680 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 75eeac9..2190d43 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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 \
diff --git a/gcc/calls.c b/gcc/calls.c
index f6bc970..a75e3b3 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -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;
diff --git a/gcc/dce.c b/gcc/dce.c
index 08a0f50..75e148c 100644
--- 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");
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4d8c384..fae2df8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..6ef8372
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr38245-3.c
@@ -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
index 0000000..b1c2a0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr38245-3.h
@@ -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
index 0000000..c9b3d2d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr38245-4.c
@@ -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
index 0000000..23f72de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr38364.c
@@ -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;
+}