This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix endless recursion in cse_cc_succs (PR target/36635, PR target/37290)


Hi!

If cse_main simplifies some stuff during cse2, cse_condition_code_reg
might be called with a cfg with some unreachable bbs.  While it will call
cleanup_cfg (0) before the end of the pass, unreachable blocks cause a
problem to cse_cc_succs.  It recurses through succs edges as long as the
target has exactly one predecessor, so for reachable blocks it will always
eventually stop, but if it is called on an unreachable block it might
recurse endlessly.  In one of the PRs there is a patch that adds a bitmap
of visited bb's, but that's IMHO an overkill - if we endlessly recurse,
we must call cse_cc_succs again on the original bb cse_condition_code_reg
called it, smaller loops aren't possible, as there would be some bb with
two or more preds edges.

Alternatively, we could
if (tem) delete_unreachable_blocks ();
before calling cse_condition_code_reg, or call
if (tem) find_unreachable_blocks ()
and in cse_condition_code_reg skip altogether unreachable bb's if tem.
But IMHO the version below is cheapest.

Ok if bootstrap/regtest passes on x86_64-linux?

2008-10-07  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/37341
	* cse.c (cse_cc_succs): Add ORIG_BB argument, don't follow edges
	to ORIG_BB, pass through ORIG_BB recursively.
	(cse_condition_code_reg): Adjust caller.

	* gcc.c-torture/compile/pr37341.c: New test.

--- gcc/cse.c.jj	2008-09-15 09:36:26.000000000 +0200
+++ gcc/cse.c	2008-10-07 18:22:06.000000000 +0200
@@ -1,6 +1,6 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 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
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -603,7 +603,8 @@ static bool set_live_p (rtx, rtx, int *)
 static int cse_change_cc_mode (rtx *, void *);
 static void cse_change_cc_mode_insn (rtx, rtx);
 static void cse_change_cc_mode_insns (rtx, rtx, rtx);
-static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool);
+static enum machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
+				       bool);
 
 
 #undef RTL_HOOKS_GEN_LOWPART
@@ -6587,13 +6588,17 @@ cse_change_cc_mode_insns (rtx start, rtx
    permitted to change the mode of CC_SRC to a compatible mode.  This
    returns VOIDmode if no equivalent assignments were found.
    Otherwise it returns the mode which CC_SRC should wind up with.
+   ORIG_BB should be the same as BB in the outermost cse_cc_succs call,
+   but is passed unmodified down to recursive calls in order to prevent
+   endless recursion.
 
    The main complexity in this function is handling the mode issues.
    We may have more than one duplicate which we can eliminate, and we
    try to find a mode which will work for multiple duplicates.  */
 
 static enum machine_mode
-cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
+cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
+	      bool can_change_mode)
 {
   bool found_equiv;
   enum machine_mode mode;
@@ -6624,7 +6629,9 @@ cse_cc_succs (basic_block bb, rtx cc_reg
 	continue;
 
       if (EDGE_COUNT (e->dest->preds) != 1
-	  || e->dest == EXIT_BLOCK_PTR)
+	  || e->dest == EXIT_BLOCK_PTR
+	  /* Avoid endless recursion on unreachable blocks.  */
+	  || e->dest == orig_bb)
 	continue;
 
       end = NEXT_INSN (BB_END (e->dest));
@@ -6729,7 +6736,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg
 	{
 	  enum machine_mode submode;
 
-	  submode = cse_cc_succs (e->dest, cc_reg, cc_src, false);
+	  submode = cse_cc_succs (e->dest, orig_bb, cc_reg, cc_src, false);
 	  if (submode != VOIDmode)
 	    {
 	      gcc_assert (submode == mode);
@@ -6857,7 +6864,7 @@ cse_condition_code_reg (void)
 	 the basic block.  */
 
       orig_mode = GET_MODE (cc_src);
-      mode = cse_cc_succs (bb, cc_reg, cc_src, true);
+      mode = cse_cc_succs (bb, bb, cc_reg, cc_src, true);
       if (mode != VOIDmode)
 	{
 	  gcc_assert (mode == GET_MODE (cc_src));
--- gcc/testsuite/gcc.c-torture/compile/pr37341.c.jj	2008-10-07 18:51:26.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/compile/pr37341.c	2008-10-07 18:57:26.000000000 +0200
@@ -0,0 +1,35 @@
+/* PR rtl-optimization/37341 */
+
+short int a;
+int b;
+
+static inline int
+f1 (int x, int y)
+{
+  if (x < 0 || y < 0 || y >= sizeof (int) * 8 || x > (1 >> y))
+    return x;
+}
+
+static inline unsigned int
+f2 (int x, int y)
+{
+  if (y <= 0 && x && y < __INT_MAX__ / x)
+    return x;
+  return x * y;
+}
+
+int
+f3 (void)
+{
+  return (signed char) 0xb6;
+}
+
+unsigned int
+f4 (unsigned int x)
+{
+  while (1)
+    {
+      if ((f2 (f3 (), (f1 (a, b)))) < x)
+	return 1;
+    }
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]