diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 08d91dbf06c6c6ca7c93af2ffa6acb462da8373a..57de984bcc2bb0b539fd6d6fb9dcb70b111c7eee 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2010-12-16  Jan Hubicka  <jh@suse.cz>
+
+	PR middle-end/46939
+	* predic.c (predict_paths_leading_to_edge): New function.
+	(apply_return_prediction): Use it.
+	(predict_paths_for_bb): Do not special case abnormals.
+
 2010-12-16  Joseph Myers  <joseph@codesourcery.com>
 
 	* config.gcc (powerpc-*-lynxos*): Don't add lynx.opt to
diff --git a/gcc/predict.c b/gcc/predict.c
index c69199083161a45c3a9f8af2631b6b322351f930..a86708a5935174fa982ffb120b807e60248db29e 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -77,6 +77,7 @@ static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
 static void combine_predictions_for_insn (rtx, basic_block);
 static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int);
 static void predict_paths_leading_to (basic_block, enum br_predictor, enum prediction);
+static void predict_paths_leading_to_edge (edge, enum br_predictor, enum prediction);
 static bool can_predict_insn_p (const_rtx);
 
 /* Information we hold about each branch predictor.
@@ -1558,8 +1559,8 @@ apply_return_prediction (void)
       {
 	pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
 	if (pred != PRED_NO_PREDICTION)
-	  predict_paths_leading_to (gimple_phi_arg_edge (phi, i)->src, pred,
-				    direction);
+	  predict_paths_leading_to_edge (gimple_phi_arg_edge (phi, i), pred,
+				         direction);
       }
 }
 
@@ -1805,8 +1806,8 @@ predict_paths_for_bb (basic_block cur, basic_block bb,
       edge_iterator ei2;
       bool found = false;
 
-      /* Ignore abnormals, we predict them as not taken anyway.  */
-      if (e->flags & (EDGE_EH | EDGE_FAKE | EDGE_ABNORMAL))
+      /* Ignore fake edges and eh, we predict them as not taken anyway.  */
+      if (e->flags & (EDGE_EH | EDGE_FAKE))
 	continue;
       gcc_assert (bb == cur || dominated_by_p (CDI_POST_DOMINATORS, cur, bb));
 
@@ -1814,7 +1815,7 @@ predict_paths_for_bb (basic_block cur, basic_block bb,
 	 and does not lead to BB.  */
       FOR_EACH_EDGE (e2, ei2, e->src->succs)
 	if (e2 != e
-	    && !(e2->flags & (EDGE_EH | EDGE_FAKE | EDGE_ABNORMAL))
+	    && !(e2->flags & (EDGE_EH | EDGE_FAKE))
 	    && !dominated_by_p (CDI_POST_DOMINATORS, e2->dest, bb))
 	  {
 	    found = true;
@@ -1844,6 +1845,31 @@ predict_paths_leading_to (basic_block bb, enum br_predictor pred,
 {
   predict_paths_for_bb (bb, bb, pred, taken);
 }
+
+/* Like predict_paths_leading_to but take edge instead of basic block.  */
+
+static void
+predict_paths_leading_to_edge (edge e, enum br_predictor pred,
+			       enum prediction taken)
+{
+  bool has_nonloop_edge = false;
+  edge_iterator ei;
+  edge e2;
+
+  basic_block bb = e->src;
+  FOR_EACH_EDGE (e2, ei, bb->succs)
+    if (e2->dest != e->src && e2->dest != e->dest
+	&& !(e->flags & (EDGE_EH | EDGE_FAKE))
+	&& !dominated_by_p (CDI_POST_DOMINATORS, e->src, e2->dest))
+      {
+	has_nonloop_edge = true;
+	break;
+      }
+  if (!has_nonloop_edge)
+    predict_paths_for_bb (bb, bb, pred, taken);
+  else
+    predict_edge_def (e, pred, taken);
+}
 
 /* This is used to carry information about basic blocks.  It is
    attached to the AUX field of the standard CFG block.  */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c10535cb1a66fee9f71f33307d05e96e809e8ce6..8ca61f499182883b0a8902111e33ca04826d1e2f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-12-16  Jan Hubicka  <jh@suse.cz>
+
+	PR middle-end/46939
+	* gcc.target/i386/pr46939.c: New testcase.
+
 2010-12-15  Sebastian Pop  <sebastian.pop@amd.com>
 
 	PR tree-optimization/46404
diff --git a/gcc/testsuite/gcc.target/i386/pr46939.c b/gcc/testsuite/gcc.target/i386/pr46939.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f50e37ee017a3012d5f243387ec09ecb3652901
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr46939.c
@@ -0,0 +1,118 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+int
+php_filter_parse_int (char const *str, unsigned int str_len, long *ret)
+{
+  long ctx_value;
+  int sign;
+  int digit;
+  char const *end;
+  int tmp;
+  char const *tmp___0;
+  char const *tmp___1;
+
+  sign = 0;
+  digit = 0;
+  end = str + str_len;
+  switch ((int) *str)
+    {
+    case 45:
+      sign = 1;
+    case 43:
+      str++;
+    default:;
+      break;
+    }
+  if ((unsigned long) str < (unsigned long) end)
+    {
+      if ((int const) *str >= 49)
+	{
+	  if ((int const) *str <= 57)
+	    {
+	      if (sign)
+		{
+		  tmp = -1;
+		}
+	      else
+		{
+		  tmp = 1;
+		}
+	      tmp___0 = str;
+	      str++;
+	      ctx_value = (long) (tmp * (int) ((int const) *tmp___0 - 48));
+	    }
+	  else
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  return (-1);
+	}
+    }
+  else
+    {
+      return (-1);
+    }
+  if (end - str > 19)
+    {
+      return (-1);
+    }
+  while ((unsigned long) str < (unsigned long) end)
+    {
+      if ((int const) *str >= 48)
+	{
+	  if ((int const) *str <= 57)
+	    {
+	      tmp___1 = str;
+	      str++;
+	      digit = (int) ((int const) *tmp___1 - 48);
+	      if (!sign)
+		{
+		  if (ctx_value <=
+		      (9223372036854775807L - (long) digit) / 10L)
+		    {
+		      ctx_value = ctx_value * 10L + (long) digit;
+		    }
+		  else
+		    {
+		      goto _L;
+		    }
+		}
+	      else
+		{
+		_L:
+		  if (sign)
+		    {
+		      if (ctx_value >=
+			  ((-0x7FFFFFFFFFFFFFFF - 1) + (long) digit) / 10L)
+			{
+			  ctx_value = ctx_value * 10L - (long) digit;
+			}
+		      else
+			{
+			  return (-1);
+			}
+		    }
+		  else
+		    {
+		      return (-1);
+		    }
+		}
+	    }
+	  else
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  return (-1);
+	}
+    }
+  *ret = ctx_value;
+  return (1);
+}
+
+/* { dg-final { scan-assembler-not "idiv" } } */