OSDN Git Service

(__va_copy): New definition.
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 951bb22..a3f42d5 100644 (file)
@@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
+#include "except.h"
 #include "function.h"
 #include "insn-flags.h"
 #include "insn-config.h"
@@ -134,8 +135,6 @@ extern tree rtl_expr_chain;
    cleanup list whenever an empty list is required.  */
 static tree empty_cleanup_list;
 #endif
-
-extern void (*interim_eh_hook) PROTO((tree));
 \f
 /* Functions and data structures for expanding case statements.  */
 
@@ -222,7 +221,7 @@ struct nesting
             and no `else' has been seen yet.  */
          rtx endif_label;
          /* Label for the end of this alternative.
-            This may be the end of the if or the next else/elseif. */
+            This may be the end of the if or the next else/elseif.  */
          rtx next_label;
        } cond;
       /* For loops.  */
@@ -246,7 +245,7 @@ struct nesting
             in order of entry.  */
          int block_start_count;
          /* Nonzero => value to restore stack to on exit.  Complemented by
-            bc_stack_level (see below) when generating bytecodes. */
+            bc_stack_level (see below) when generating bytecodes.  */
          rtx stack_level;
          /* The NOTE that starts this contour.
             Used by expand_goto to check whether the destination
@@ -285,7 +284,7 @@ struct nesting
          rtx start;
          /* For bytecodes, the case table is in-lined right in the code.
             A label is needed for skipping over this block. It is only
-            used when generating bytecodes. */
+            used when generating bytecodes.  */
          rtx skip_label;
          /* A list of case labels; it is first built as an AVL tree.
             During expand_end_case, this is converted to a list, and may be
@@ -473,9 +472,7 @@ void
 init_stmt ()
 {
   gcc_obstack_init (&stmt_obstack);
-#if 0
-  empty_cleanup_list = build_tree_list (NULL_TREE, NULL_TREE);
-#endif
+  init_eh ();
 }
 
 void
@@ -498,6 +495,8 @@ init_stmt_for_function ()
   /* We are not processing a ({...}) grouping.  */
   expr_stmts_for_value = 0;
   last_expr_type = 0;
+
+  init_eh_for_function ();
 }
 
 void
@@ -518,6 +517,7 @@ save_stmt_status (p)
   p->emit_filename = emit_filename;
   p->emit_lineno = emit_lineno;
   p->goto_fixup_chain = goto_fixup_chain;
+  save_eh_status (p);
 }
 
 void
@@ -538,6 +538,7 @@ restore_stmt_status (p)
   emit_filename = p->emit_filename;
   emit_lineno = p->emit_lineno;
   goto_fixup_chain = p->goto_fixup_chain;
+  restore_eh_status (p);
 }
 \f
 /* Emit a no-op instruction.  */
@@ -773,7 +774,7 @@ expand_goto_internal (body, label, last_insn)
   /* NOTICE!  If a bytecode instruction other than `jump' is needed,
      then the caller has to call bc_expand_goto_internal()
      directly. This is rather an exceptional case, and there aren't
-     that many places where this is necessary. */
+     that many places where this is necessary.  */
   if (output_bytecode)
     {
       expand_goto_internal (body, label, last_insn);
@@ -808,8 +809,9 @@ expand_goto_internal (body, label, last_insn)
 
       if (stack_level)
        {
-         /* Ensure stack adjust isn't done by emit_jump, as this would clobber
-            the stack pointer.  This one should be deleted as dead by flow. */
+         /* Ensure stack adjust isn't done by emit_jump, as this
+            would clobber the stack pointer.  This one should be
+            deleted as dead by flow.  */
          clear_pending_stack_adjust ();
          do_pending_stack_adjust ();
          emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
@@ -833,7 +835,7 @@ expand_goto_internal (body, label, last_insn)
 }
 \f
 /* Generate a jump with OPCODE to the given bytecode LABEL which is
-   found within BODY. */
+   found within BODY.  */
 
 static void
 bc_expand_goto_internal (opcode, label, body)
@@ -846,7 +848,7 @@ bc_expand_goto_internal (opcode, label, body)
 
   /* If the label is defined, adjust the stack as necessary.
      If it's not defined, we have to push the reference on the
-     fixup list. */
+     fixup list.  */
 
   if (label->defined)
     {
@@ -874,7 +876,7 @@ bc_expand_goto_internal (opcode, label, body)
         must do so after the jump, since the jump may depend on
         what's on the stack.  Thus, any stack-modifying conditional
         jumps (these are the only ones that rely on what's on the
-        stack) go into the fixup list. */
+        stack) go into the fixup list.  */
 
       if (stack_level >= 0
          && stack_depth != stack_level
@@ -1212,7 +1214,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
 
   /* For any still-undefined labels, do the cleanups for this block now.
      We must do this now since items in the cleanup list may go out
-     of scope when the block ends. */
+     of scope when the block ends.  */
   for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
     if (f->before_jump != 0
        && PREV_INSN (f->target_rtl) == 0
@@ -1242,8 +1244,9 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
              cleanup_insns = get_insns ();
              poplevel (1, 0, 0);
              end_sequence ();
-             f->before_jump
-               = emit_insns_after (cleanup_insns, f->before_jump);
+             if (cleanup_insns != 0)
+               f->before_jump
+                 = emit_insns_after (cleanup_insns, f->before_jump);
 
              f->cleanup_list_list = TREE_CHAIN (lists);
            }
@@ -1299,7 +1302,7 @@ bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
       bc_emit_bytecode_labeldef (f->label);
 
       /* Save stack_depth across call, since bc_adjust_stack () will alter
-         the perceived stack depth via the instructions generated. */
+         the perceived stack depth via the instructions generated.  */
 
       if (f->bc_stack_level >= 0)
        {
@@ -1367,11 +1370,15 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   rtx body;
   int ninputs = list_length (inputs);
   int noutputs = list_length (outputs);
+  int ninout = 0;
   int nclobbers;
   tree tail;
   register int i;
   /* Vector of RTX's of evaluated output operands.  */
   rtx *output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
+  int *inout_opnum = (int *) alloca (noutputs * sizeof (int));
+  enum machine_mode *inout_mode
+    = (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
   /* The insn we have emitted.  */
   rtx insn;
 
@@ -1403,6 +1410,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       tree val1;
       int j;
       int found_equal = 0;
+      int found_plus = 0;
       int allows_reg = 0;
 
       /* If there's an erroneous arg, emit no insn.  */
@@ -1418,8 +1426,17 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
        switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
          {
          case '+':
-           error ("output operand constraint contains `+'");
-           return;
+           /* Make sure we can specify the matching operand.  */
+           if (i > 9)
+             {
+               error ("output operand constraint %d contains `+'", i);
+               return;
+             }
+
+           /* Replace '+' with '='.  */
+           TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] = '=';
+           found_plus = 1;
+           break;
 
          case '=':
            found_equal = 1;
@@ -1436,19 +1453,18 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 #endif
            break;
 
-         case 'p':  case 'g':  case 'r':
-           /* Whether or not a numeric constraint allows a register is
-              decided by the matching constraint, and so there is no need
-              to do anything special with them.  We must handle them in
-              the default case, so that we don't unnecessarily force
-              operands to memory.  */
          case '0':  case '1':  case '2':  case '3':  case '4':
+         case '5':  case '6':  case '7':  case '8':  case '9':
+           error ("matching constraint not valid in output operand");
+           break;
+
+         case 'p':  case 'g':  case 'r':
          default:
            allows_reg = 1;
            break;
          }
 
-      if (! found_equal)
+      if (! found_equal && ! found_plus)
        {
          error ("output operand constraint lacks `='");
          return;
@@ -1463,7 +1479,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          || (TREE_CODE_CLASS (TREE_CODE (val)) == 'd'
              && ! (GET_CODE (DECL_RTL (val)) == REG
                    && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
-         || ! allows_reg)
+         || ! allows_reg
+         || found_plus)
        {
          if (! allows_reg)
            mark_addressable (TREE_VALUE (tail));
@@ -1479,8 +1496,15 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          output_rtx[i] = assign_temp (type, 0, 0, 0);
          TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
        }
+
+      if (found_plus)
+       {
+         inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
+         inout_opnum[ninout++] = i;
+       }
     }
 
+  ninputs += ninout;
   if (ninputs + noutputs > MAX_RECOG_OPERANDS)
     {
       error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
@@ -1539,13 +1563,20 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 #endif
            break;
 
-         case 'p':  case 'g':  case 'r':
            /* Whether or not a numeric constraint allows a register is
               decided by the matching constraint, and so there is no need
               to do anything special with them.  We must handle them in
               the default case, so that we don't unnecessarily force
               operands to memory.  */
          case '0':  case '1':  case '2':  case '3':  case '4':
+         case '5':  case '6':  case '7':  case '8':  case '9':
+           if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]
+               >= '0' + noutputs)
+             error ("matching constraint references invalid operand number");
+
+           /* ... fall through ... */
+
+         case 'p':  case 'g':  case 'r':
          default:
            allows_reg = 1;
            break;
@@ -1591,12 +1622,25 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   /* Protect all the operands from the queue,
      now that they have all been evaluated.  */
 
-  for (i = 0; i < ninputs; i++)
+  for (i = 0; i < ninputs - ninout; i++)
     XVECEXP (body, 3, i) = protect_from_queue (XVECEXP (body, 3, i), 0);
 
   for (i = 0; i < noutputs; i++)
     output_rtx[i] = protect_from_queue (output_rtx[i], 1);
 
+  /* For in-out operands, copy output rtx to input rtx. */
+  for (i = 0; i < ninout; i++)
+    {
+      static char match[9+1][2]
+       = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
+      int j = inout_opnum[i];
+
+      XVECEXP (body, 3, ninputs - ninout + i)      /* argvec */
+       = output_rtx[j];
+      XVECEXP (body, 4, ninputs - ninout + i)      /* constraints */
+       = gen_rtx (ASM_INPUT, inout_mode[j], match[j]);
+    }
+
   /* Now, for each output, construct an rtx
      (set OUTPUT (asm_operands INSN OUTPUTNUMBER OUTPUTCONSTRAINT
                               ARGVEC CONSTRAINTS))
@@ -1842,7 +1886,7 @@ warn_if_unused_value (exp)
         the user cannot control it.  */
       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
        return warn_if_unused_value (TREE_OPERAND (exp, 0));
-      /* ... fall through ... */
+      /* ... fall through ...  */
       
     default:
       /* Referencing a volatile value is a side effect, so don't warn.  */
@@ -1920,7 +1964,7 @@ expand_end_stmt_expr (t)
         of adding code to inhibit dropping the last expression value, it
         is here recovered by undoing the `drop'.  Since `drop' is
         equivalent to `adjustackSI [1]', it can be undone with `adjstackSI
-        [-1]'. */
+        [-1]'.  */
       
       bc_adjust_stack (-1);
       
@@ -2040,7 +2084,7 @@ expand_start_else ()
 
   emit_jump (cond_stack->data.cond.endif_label);
   emit_label (cond_stack->data.cond.next_label);
-  cond_stack->data.cond.next_label = 0;  /* No more _else or _elseif calls. */
+  cond_stack->data.cond.next_label = 0;  /* No more _else or _elseif calls.  */
 }
 
 /* After calling expand_start_else, turn this "else" into an "else if"
@@ -2081,7 +2125,7 @@ expand_end_cond ()
 /* Generate code for the start of an if-then.  COND is the expression
    whose truth is to be tested; if EXITFLAG is nonzero this conditional
    is to be visible to exit_something.  It is assumed that the caller
-   has pushed the previous context on the cond stack. */
+   has pushed the previous context on the cond stack.  */
 
 static void
 bc_expand_start_cond (cond, exitflag)
@@ -2529,6 +2573,21 @@ expand_value_return (val)
   if (GET_CODE (return_reg) == REG
       && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
     emit_insn (gen_rtx (USE, VOIDmode, return_reg));
+  /* Handle calls that return values in multiple non-contiguous locations.
+     The Irix 6 ABI has examples of this.  */
+  else if (GET_CODE (return_reg) == PARALLEL)
+    {
+      int i;
+
+      for (i = 0; i < XVECLEN (return_reg, 0); i++)
+       {
+         rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
+
+         if (GET_CODE (x) == REG
+             && REGNO (x) < FIRST_PSEUDO_REGISTER)
+           emit_insn (gen_rtx (USE, VOIDmode, x));
+       }
+    }
 
   /* Does any pending block have cleanups?  */
 
@@ -2605,7 +2664,7 @@ expand_return (retval)
   struct nesting *block;
 
   /* Bytecode returns are quite simple, just leave the result on the
-     arithmetic stack. */
+     arithmetic stack.  */
   if (output_bytecode)
     {
       bc_expand_expr (retval);
@@ -2664,14 +2723,14 @@ expand_return (retval)
       tree expr;
 
       do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
-      expr = build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
+      expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
                    DECL_RESULT (current_function_decl),
                    TREE_OPERAND (retval_rhs, 1));
       TREE_SIDE_EFFECTS (expr) = 1;
       expand_return (expr);
       emit_label (label);
 
-      expr = build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
+      expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
                    DECL_RESULT (current_function_decl),
                    TREE_OPERAND (retval_rhs, 2));
       TREE_SIDE_EFFECTS (expr) = 1;
@@ -2717,29 +2776,51 @@ expand_return (retval)
     {
       /* If this is  return x == y;  then generate
         if (x == y) return 1; else return 0;
-        if we can do it with explicit return insns and
-        branches are cheap.  */
+        if we can do it with explicit return insns and branches are cheap,
+        but not if we have the corresponding scc insn.  */
+      int has_scc = 0;
       if (retval_rhs)
        switch (TREE_CODE (retval_rhs))
          {
          case EQ_EXPR:
+#ifdef HAVE_seq
+           has_scc = HAVE_seq;
+#endif
          case NE_EXPR:
+#ifdef HAVE_sne
+           has_scc = HAVE_sne;
+#endif
          case GT_EXPR:
+#ifdef HAVE_sgt
+           has_scc = HAVE_sgt;
+#endif
          case GE_EXPR:
+#ifdef HAVE_sge
+           has_scc = HAVE_sge;
+#endif
          case LT_EXPR:
+#ifdef HAVE_slt
+           has_scc = HAVE_slt;
+#endif
          case LE_EXPR:
+#ifdef HAVE_sle
+           has_scc = HAVE_sle;
+#endif
          case TRUTH_ANDIF_EXPR:
          case TRUTH_ORIF_EXPR:
          case TRUTH_AND_EXPR:
          case TRUTH_OR_EXPR:
          case TRUTH_NOT_EXPR:
          case TRUTH_XOR_EXPR:
-           op0 = gen_label_rtx ();
-           jumpifnot (retval_rhs, op0);
-           expand_value_return (const1_rtx);
-           emit_label (op0);
-           expand_value_return (const0_rtx);
-           return;
+           if (! has_scc)
+             {
+               op0 = gen_label_rtx ();
+               jumpifnot (retval_rhs, op0);
+               expand_value_return (const1_rtx);
+               emit_label (op0);
+               expand_value_return (const0_rtx);
+               return;
+             }
          }
     }
 #endif /* HAVE_return */
@@ -2838,6 +2919,7 @@ expand_return (retval)
       result_reg = gen_reg_rtx (result_reg_mode);
 
       /* Now that the value is in pseudos, copy it to the result reg(s).  */
+      expand_cleanups_to (NULL_TREE);
       emit_queue ();
       free_temp_slots ();
       for (i = 0; i < n_regs; i++)
@@ -2855,7 +2937,10 @@ expand_return (retval)
       && GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)
     {
       /* Calculate the return value into a pseudo reg.  */
-      val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
+      val = gen_reg_rtx (DECL_MODE (DECL_RESULT (current_function_decl)));
+      val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
+      val = force_not_mem (val);
+      expand_cleanups_to (NULL_TREE);
       emit_queue ();
       /* All temporaries have now been used.  */
       free_temp_slots ();
@@ -2867,6 +2952,7 @@ expand_return (retval)
       /* No cleanups or no hard reg used;
         calculate value into hard return reg.  */
       expand_expr (retval, const0_rtx, VOIDmode, 0);
+      expand_cleanups_to (NULL_TREE);
       emit_queue ();
       free_temp_slots ();
       expand_value_return (DECL_RTL (DECL_RESULT (current_function_decl)));
@@ -3159,6 +3245,11 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
        }
 #endif
 
+#ifdef HAVE_nonlocal_goto_receiver
+      if (HAVE_nonlocal_goto_receiver)
+       emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+
       /* The handler expects the desired label address in the static chain
         register.  It tests the address and does an appropriate jump
         to whatever label is desired.  */
@@ -3368,30 +3459,15 @@ expand_decl (decl)
       enum machine_mode reg_mode
        = promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         rtx realpart, imagpart;
-         enum machine_mode partmode = TYPE_MODE (TREE_TYPE (type));
-
-         /* For a complex type variable, make a CONCAT of two pseudos
-            so that the real and imaginary parts
-            can be allocated separately.  */
-         realpart = gen_reg_rtx (partmode);
-         REG_USERVAR_P (realpart) = 1;
-         imagpart = gen_reg_rtx (partmode);
-         REG_USERVAR_P (imagpart) = 1;
-         DECL_RTL (decl) = gen_rtx (CONCAT, reg_mode, realpart, imagpart);
-       }
-      else
-       {
-         DECL_RTL (decl) = gen_reg_rtx (reg_mode);
-         if (TREE_CODE (type) == POINTER_TYPE)
-           mark_reg_pointer (DECL_RTL (decl),
-                             (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))
-                              / BITS_PER_UNIT));
-         REG_USERVAR_P (DECL_RTL (decl)) = 1;
-       }
+      DECL_RTL (decl) = gen_reg_rtx (reg_mode);
+      mark_user_reg (DECL_RTL (decl));
+
+      if (TREE_CODE (type) == POINTER_TYPE)
+       mark_reg_pointer (DECL_RTL (decl),
+                         (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))
+                          / BITS_PER_UNIT));
     }
+
   else if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
     {
       /* Variable of fixed size that goes on the stack.  */
@@ -3463,9 +3539,12 @@ expand_decl (decl)
                          NULL_RTX, VOIDmode, 0);
       free_temp_slots ();
 
-      /* Allocate space on the stack for the variable.  */
+      /* Allocate space on the stack for the variable.  Note that
+        DECL_ALIGN says how the variable is to be aligned and we 
+        cannot use it to conclude anything about the alignment of
+        the size.  */
       address = allocate_dynamic_stack_space (size, NULL_RTX,
-                                             DECL_ALIGN (decl));
+                                             TYPE_ALIGN (TREE_TYPE (decl)));
 
       /* Reference the variable indirect through that rtx.  */
       DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), address);
@@ -3606,7 +3685,7 @@ expand_decl_init (decl)
 
 /* Expand initialization for variable-sized types. Allocate array
    using newlocalSI and set local variable, which is a pointer to the
-   storage. */
+   storage.  */
 
 static void
 bc_expand_variable_local_init (decl)
@@ -3630,7 +3709,7 @@ bc_expand_variable_local_init (decl)
      using expand_address() since that would cause the pointer to be
      pushed rather than its address. Hence the hard-coded reference;
      notice also that the variable is always local (no global
-     variable-size type variables). */
+     variable-size type variables).  */
 
   bc_load_localaddr (DECL_RTL (decl));
   bc_emit_instruction (storeP);
@@ -3655,7 +3734,7 @@ bc_expand_decl_init (decl)
 
   /* If the type is variable-size, we first create its space (we ASSUME
      it CAN'T be static).  We do this regardless of whether there's an
-     initializer assignment or not. */
+     initializer assignment or not.  */
 
   if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
     bc_expand_variable_local_init (decl);
@@ -3684,12 +3763,9 @@ bc_expand_decl_init (decl)
 /* CLEANUP is an expression to be executed at exit from this binding contour;
    for example, in C++, it might call the destructor for this variable.
 
-   If CLEANUP contains any SAVE_EXPRs, then you must preevaluate them
-   either before or after calling `expand_decl_cleanup' but before compiling
-   any subsequent expressions.  This is because CLEANUP may be expanded
-   more than once, on different branches of execution.
-   For the same reason, CLEANUP may not contain a CALL_EXPR
-   except as its topmost node--else `preexpand_calls' would get confused.
+   We wrap CLEANUP in an UNSAVE_EXPR node, so that we can expand the
+   CLEANUP multiple times, and have the correct semantics.  This
+   happens in exception handling, and for non-local gotos.
 
    If CLEANUP is nonzero and DECL is zero, we record a cleanup
    that is not associated with any particular variable.   */
@@ -3708,11 +3784,13 @@ expand_decl_cleanup (decl, cleanup)
 
   if (cleanup != 0)
     {
+      cleanup = unsave_expr (cleanup);
+
       thisblock->data.block.cleanups
        = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
       /* If this block has a cleanup, it belongs in stack_block_stack.  */
       stack_block_stack = thisblock;
-      (*interim_eh_hook) (NULL_TREE);
+      expand_eh_region_start ();
     }
   return 1;
 }
@@ -3813,7 +3891,7 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
        else
          {
            if (! in_fixup)
-             (*interim_eh_hook) (TREE_VALUE (tail));
+             expand_eh_region_end (TREE_VALUE (tail));
 
            if (reachable)
              {
@@ -3944,7 +4022,7 @@ expand_start_case (exit_flag, expr, type, printname)
 
 
 /* Enter a case statement. It is assumed that the caller has pushed
-   the current context onto the case stack. */
+   the current context onto the case stack.  */
 
 static void
 bc_expand_start_case (thiscase, expr, type, printname)
@@ -4160,11 +4238,11 @@ pushcase_range (value1, value2, converter, label, duplicate)
   case_stack->data.case_stmt.seenlabel = 1;
 
   /* Convert VALUEs to type in which the comparisons are nominally done.  */
-  if (value1 == 0)  /* Negative infinity. */
+  if (value1 == 0)  /* Negative infinity.  */
     value1 = TYPE_MIN_VALUE(index_type);
   value1 = (*converter) (nominal_type, value1);
 
-  if (value2 == 0)  /* Positive infinity. */
+  if (value2 == 0)  /* Positive infinity.  */
     value2 = TYPE_MAX_VALUE(index_type);
   value2 = (*converter) (nominal_type, value2);
 
@@ -4418,7 +4496,7 @@ add_case_node (low, high, label, duplicate)
    2 and do nothing.  If VALUE is out of range, return 3 and do nothing.
    Return 0 on success.  This function is a leftover from the earlier
    bytecode compiler, which was based on gcc 1.37.  It should be
-   merged into pushcase. */
+   merged into pushcase.  */
 
 static int
 bc_pushcase (value, label)
@@ -4502,7 +4580,7 @@ all_cases_count (type, spareness)
          /* count
             = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
             - TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + 1
-            but with overflow checking. */
+            but with overflow checking.  */
          tree mint = TYPE_MIN_VALUE (type);
          tree maxt = TYPE_MAX_VALUE (type);
          HOST_WIDE_INT lo, hi;
@@ -4547,11 +4625,11 @@ all_cases_count (type, spareness)
 
 
 #define BITARRAY_TEST(ARRAY, INDEX) \
-  ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
-                         & (1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR)))
+  ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\
+                         & (1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR)))
 #define BITARRAY_SET(ARRAY, INDEX) \
-  ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
-                         |= 1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR))
+  ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\
+                         |= 1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR))
 
 /* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
    with the case values we have seen, assuming the case expression
@@ -4701,17 +4779,17 @@ check_for_full_enumeration_handling (type)
   register tree chain;
   int all_values = 1;
 
-  /* True iff the selector type is a numbered set mode. */
+  /* True iff the selector type is a numbered set mode.  */
   int sparseness = 0;
 
-  /* The number of possible selector values. */
+  /* The number of possible selector values.  */
   HOST_WIDE_INT size;
 
   /* For each possible selector value. a one iff it has been matched
-     by a case value alternative. */
+     by a case value alternative.  */
   unsigned char *cases_seen;
 
-  /* The allocated size of cases_seen, in chars. */
+  /* The allocated size of cases_seen, in chars.  */
   long bytes_needed;
   tree t;
 
@@ -4728,7 +4806,7 @@ check_for_full_enumeration_handling (type)
   bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
 
   if (size > 0 && size < 600000
-      /* We deliberately use malloc here - not xmalloc. */
+      /* We deliberately use malloc here - not xmalloc.  */
       && (cases_seen = (unsigned char *) malloc (bytes_needed)) != NULL)
     {
       long i;
@@ -4738,7 +4816,7 @@ check_for_full_enumeration_handling (type)
       /* The time complexity of this code is normally O(N), where
         N being the number of members in the enumerated type.
         However, if type is a ENUMERAL_TYPE whose values do not
-        increase monotonically, O(N*log(N)) time may be needed. */
+        increase monotonically, O(N*log(N)) time may be needed.  */
 
       mark_seen_cases (type, cases_seen, size, sparseness);
 
@@ -4755,7 +4833,7 @@ check_for_full_enumeration_handling (type)
   /* Now we go the other way around; we warn if there are case
      expressions that don't correspond to enumerators.  This can
      occur since C and C++ don't enforce type-checking of
-     assignments to enumeration variables. */
+     assignments to enumeration variables.  */
 
   if (case_stack->data.case_stmt.case_list
       && case_stack->data.case_stmt.case_list->left)
@@ -5385,7 +5463,7 @@ bc_expand_end_case (expr)
 }
 
 
-/* Return unique bytecode ID. */
+/* Return unique bytecode ID.  */
 
 int 
 bc_new_uid ()
@@ -5512,12 +5590,18 @@ group_case_nodes (head)
   while (node)
     {
       rtx lb = next_real_insn (label_rtx (node->code_label));
+      rtx lb2;
       case_node_ptr np = node;
 
       /* Try to group the successors of NODE with NODE.  */
       while (((np = np->right) != 0)
             /* Do they jump to the same place?  */
-            && next_real_insn (label_rtx (np->code_label)) == lb
+            && ((lb2 = next_real_insn (label_rtx (np->code_label))) == lb
+                || (lb != 0 && lb2 != 0
+                    && simplejump_p (lb)
+                    && simplejump_p (lb2)
+                    && rtx_equal_p (SET_SRC (PATTERN (lb)),
+                                    SET_SRC (PATTERN (lb2)))))
             /* Are their ranges consecutive?  */
             && tree_int_cst_equal (np->low,
                                    fold (build (PLUS_EXPR,
@@ -5826,7 +5910,7 @@ emit_case_nodes (index, node, default_label, index_type)
   else if (tree_int_cst_equal (node->low, node->high))
     {
       /* Node is single valued.  First see if the index expression matches
-        this node and then check our children, if any. */
+        this node and then check our children, if any.  */
 
       do_jump_if_equal (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
                        label_rtx (node->code_label), unsignedp);