--- gcc/builtins.c.jj	2012-11-19 14:41:14.000000000 +0100
+++ gcc/builtins.c	2012-11-19 18:21:30.324047247 +0100
@@ -4666,7 +4666,14 @@ expand_builtin_trap (void)
 {
 #ifdef HAVE_trap
   if (HAVE_trap)
-    emit_insn (gen_trap ());
+    {
+      rtx insn = emit_insn (gen_trap ());
+      /* For trap insns when not accumulating outgoing args force
+	 REG_ARGS_SIZE note to prevent crossjumping of calls with
+	 different args sizes.  */
+      if (!ACCUMULATE_OUTGOING_ARGS)
+	add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+    }
   else
 #endif
     emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
--- gcc/cfgcleanup.c.jj	2012-11-19 14:41:24.000000000 +0100
+++ gcc/cfgcleanup.c	2012-11-19 18:21:30.324047247 +0100
@@ -1702,9 +1702,15 @@ outgoing_edges_match (int mode, basic_bl
 	}
     }
 
+  rtx last1 = BB_END (bb1);
+  rtx last2 = BB_END (bb2);
+  if (DEBUG_INSN_P (last1))
+    last1 = prev_nondebug_insn (last1);
+  if (DEBUG_INSN_P (last2))
+    last2 = prev_nondebug_insn (last2);
   /* First ensure that the instructions match.  There may be many outgoing
      edges so this test is generally cheaper.  */
-  if (old_insns_match_p (mode, BB_END (bb1), BB_END (bb2)) != dir_both)
+  if (old_insns_match_p (mode, last1, last2) != dir_both)
     return false;
 
   /* Search the outgoing edges, ensure that the counts do match, find possible
@@ -1713,10 +1719,14 @@ outgoing_edges_match (int mode, basic_bl
   if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs))
     return false;
 
+  bool nonfakeedges = false;
   FOR_EACH_EDGE (e1, ei, bb1->succs)
     {
       e2 = EDGE_SUCC (bb2, ei.index);
 
+      if ((e1->flags & EDGE_FAKE) == 0)
+	nonfakeedges = true;
+
       if (e1->flags & EDGE_EH)
 	nehedges1++;
 
@@ -1734,6 +1744,18 @@ outgoing_edges_match (int mode, basic_bl
       || (fallthru1 != 0) != (fallthru2 != 0))
     return false;
 
+  /* If !ACCUMULATE_OUTGOING_ARGS, bb1 (and bb2) have no successors
+     and the last real insn doesn't have REG_ARGS_SIZE note, don't
+     attempt to optimize, as the two basic blocks might have different
+     REG_ARGS_SIZE depths.  For noreturn calls and unconditional
+     traps there should be REG_ARG_SIZE notes, they could be missing
+     for __builtin_unreachable () uses though.  */
+  if (!nonfakeedges
+      && !ACCUMULATE_OUTGOING_ARGS
+      && (!INSN_P (last1)
+          || !find_reg_note (last1, REG_ARGS_SIZE, NULL)))
+    return false;
+
   /* fallthru edges must be forwarded to the same destination.  */
   if (fallthru1)
     {
--- gcc/testsuite/gcc.dg/pr55094.c.jj	2012-11-19 18:21:56.120897505 +0100
+++ gcc/testsuite/gcc.dg/pr55094.c	2012-11-19 18:20:52.000000000 +0100
@@ -0,0 +1,45 @@
+/* PR middle-end/55094 */
+/* { dg-do compile } */
+/* { dg-options "-fcompare-debug -Os" } */
+/* { dg-additional-options "-fomit-frame-pointer -fno-asynchronous-unwind-tables -mpreferred-stack-boundary=2" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
+
+extern int fn (long);
+int v;
+
+int
+foo (int x, long *y)
+{
+  if (x)
+    {
+      fn (y[0]);
+      __builtin_trap ();
+    }
+  __builtin_trap ();
+}
+
+int
+bar (int x, long *y)
+{
+  if (x)
+    {
+      fn (y[0]);
+      v = 1;
+      __builtin_unreachable ();
+    }
+  v = 1;
+  __builtin_unreachable ();
+}
+
+int
+baz (int x, long *y)
+{
+  if (x)
+    {
+      fn (y[0]);
+      v = 1;
+      __builtin_unreachable ();
+    }
+  v = 1;
+  int w = 1;
+  __builtin_unreachable ();
+}
