OSDN Git Service

Remove CYGNUS LOCAL tags.
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 72fa814..d9551f6 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file handles the generation of rtl code from tree structure
@@ -49,6 +50,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "loop.h"
 #include "recog.h"
+#include "machmode.h"
+
+#include "bytecode.h"
+#include "bc-typecd.h"
+#include "bc-opcode.h"
+#include "bc-optab.h"
+#include "bc-emit.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -98,10 +106,6 @@ extern rtx cleanup_label;
 
 extern rtx return_label;
 
-/* List (chain of EXPR_LISTs) of pseudo-regs of SAVE_EXPRs.
-   So we can mark them all live at the end of the function, if nonopt.  */
-extern rtx save_expr_regs;
-
 /* Offset to end of allocated area of stack frame.
    If stack grows down, this is the address of the last stack slot allocated.
    If stack grows up, this is the address for the next slot.  */
@@ -130,6 +134,8 @@ 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.  */
 
@@ -137,8 +143,9 @@ static tree empty_cleanup_list;
    statements.  We handle "range" labels; for a single-value label
    as in C, the high and low limits are the same.
 
-   A chain of case nodes is initially maintained via the RIGHT fields
-   in the nodes.  Nodes with higher case values are later in the list.
+   An AVL tree of case nodes is initially created, and later transformed
+   to a list linked via the RIGHT fields in the nodes.  Nodes with
+   higher case values are later in the list.
 
    Switch statements can be output in one of two forms.  A branch table
    is used if there are more than a few labels and the labels are dense
@@ -162,6 +169,7 @@ struct case_node
   tree                 low;    /* Lowest index value for this label */
   tree                 high;   /* Highest index value for this label */
   tree                 code_label; /* Label to jump to when node matches */
+  int                  balance;
 };
 
 typedef struct case_node case_node;
@@ -172,22 +180,6 @@ typedef struct case_node *case_node_ptr;
 /* This must be a signed type, and non-ANSI compilers lack signed char.  */
 static short *cost_table;
 static int use_cost_table;
-
-static int estimate_case_costs ();
-static void balance_case_nodes ();
-static void emit_case_nodes ();
-static void group_case_nodes ();
-static void emit_jump_if_reachable ();
-
-static int warn_if_unused_value ();
-static void expand_goto_internal ();
-static int expand_fixup ();
-void fixup_gotos ();
-void free_temp_slots ();
-static void expand_cleanups ();
-static void expand_null_return_1 ();
-static int tail_recursion_args ();
-static void do_jump_if_equal ();
 \f
 /* Stack of control and binding constructs we are currently inside.
 
@@ -240,6 +232,9 @@ struct nesting
          rtx start_label;
          /* Label at the end of the whole construct.  */
          rtx end_label;
+         /* Label before a jump that branches to the end of the whole
+            construct.  This is where destructors go if any.  */
+         rtx alt_end_label;
          /* Label for `continue' statement to jump to;
             this is in front of the stepper of the loop.  */
          rtx continue_label;
@@ -250,7 +245,8 @@ struct nesting
          /* Sequence number of this binding contour within the function,
             in order of entry.  */
          int block_start_count;
-         /* Nonzero => value to restore stack to on exit.  */
+         /* Nonzero => value to restore stack to on exit.  Complemented by
+            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
@@ -277,6 +273,8 @@ struct nesting
          struct label_chain *label_chain;
          /* Number of function calls seen, as of start of this block.  */
          int function_call_count;
+         /* Bytecode specific: stack level to restore stack to on exit.  */
+         int bc_stack_level;
        } block;
       /* For switch (C) or case (Pascal) statements,
         and also for dummies (see `expand_start_case_dummy').  */
@@ -285,10 +283,13 @@ struct nesting
          /* The insn after which the case dispatch should finally
             be emitted.  Zero for a dummy.  */
          rtx start;
-         /* A list of case labels, kept in ascending order by value
-            as the list is built.
-            During expand_end_case, this list may be rearranged into a
-            nearly balanced binary tree.  */
+         /* 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. */
+         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
+            rearranged into a nearly balanced binary tree.  */
          struct case_node *case_list;
          /* Label to jump to if no case matches.  */
          tree default_label;
@@ -303,29 +304,6 @@ struct nesting
          /* Nonzero if a case label has been seen in this case stmt.  */
          char seenlabel;
        } case_stmt;
-      /* For exception contours.  */
-      struct
-       {
-         /* List of exceptions raised.  This is a TREE_LIST
-            of whatever you want.  */
-         tree raised;
-         /* List of exceptions caught.  This is also a TREE_LIST
-            of whatever you want.  As a special case, it has the
-            value `void_type_node' if it handles default exceptions.  */
-         tree handled;
-
-         /* First insn of TRY block, in case resumptive model is needed.  */
-         rtx first_insn;
-         /* Label for the catch clauses.  */
-         rtx except_label;
-         /* Label for unhandled exceptions.  */
-         rtx unhandled_label;
-         /* Label at the end of whole construct.  */
-         rtx after_label;
-         /* Label which "escapes" the exception construct.
-            Like EXIT_LABEL for BREAK construct, but for exceptions.  */
-         rtx escape_label;
-       } except_stmt;
     } data;
 };
 
@@ -347,9 +325,6 @@ struct nesting *loop_stack;
 /* Chain of all pending case or switch statements.  */
 struct nesting *case_stack;
 
-/* Chain of all pending exception contours.  */
-struct nesting *except_stack;
-
 /* Separate chain including all of the above,
    chained through the `all' field.  */
 struct nesting *nesting_stack;
@@ -381,8 +356,6 @@ do { struct nesting *target = STACK;                        \
            stack_block_stack = stack_block_stack->next; \
          if (case_stack == this)                       \
            case_stack = case_stack->next;              \
-         if (except_stack == this)                     \
-           except_stack = except_stack->next;          \
          nesting_depth = nesting_stack->depth - 1;     \
          nesting_stack = this->all;                    \
          obstack_free (&stmt_obstack, this); }         \
@@ -425,6 +398,21 @@ struct goto_fixup
      time this goto was seen.
      The TREE_ADDRESSABLE flag is 1 for a block that has been exited.  */
   tree cleanup_list_list;
+
+  /* Bytecode specific members follow */
+
+  /* The label that this jump is jumping to, or 0 for break, continue
+     or return.  */
+  struct bc_label *bc_target;
+
+  /* The label we use for the fixup patch */
+  struct bc_label *label;
+
+  /* True (non-0) if fixup has been handled */
+  int bc_handled:1;
+
+  /* Like stack_level above, except refers to the interpreter stack */
+  int bc_stack_level;
 };
 
 static struct goto_fixup *goto_fixup_chain;
@@ -438,6 +426,48 @@ struct label_chain
   struct label_chain *next;
   tree label;
 };
+static void expand_goto_internal       PROTO((tree, rtx, rtx));
+static void bc_expand_goto_internal    PROTO((enum bytecode_opcode,
+                                              struct bc_label *, tree));
+static int expand_fixup                        PROTO((tree, rtx, rtx));
+static void bc_expand_fixup            PROTO((enum bytecode_opcode,
+                                              struct bc_label *, int));
+static void fixup_gotos                        PROTO((struct nesting *, rtx, tree,
+                                              rtx, int));
+static void bc_fixup_gotos             PROTO((struct nesting *, int, tree,
+                                              rtx, int));
+static void bc_expand_start_cond       PROTO((tree, int));
+static void bc_expand_end_cond         PROTO((void));
+static void bc_expand_start_else       PROTO((void));
+static void bc_expand_end_loop         PROTO((void));
+static void bc_expand_end_bindings     PROTO((tree, int, int));
+static void bc_expand_decl             PROTO((tree, tree));
+static void bc_expand_variable_local_init PROTO((tree));
+static void bc_expand_decl_init                PROTO((tree));
+static void expand_null_return_1       PROTO((rtx, int));
+static void expand_value_return                PROTO((rtx));
+static int tail_recursion_args         PROTO((tree, tree));
+static void expand_cleanups            PROTO((tree, tree, int, int));
+static void bc_expand_start_case       PROTO((struct nesting *, tree,
+                                              tree, char *));
+static int bc_pushcase                 PROTO((tree, tree));
+static void bc_check_for_full_enumeration_handling PROTO((tree));
+static void bc_expand_end_case         PROTO((tree));
+static void do_jump_if_equal           PROTO((rtx, rtx, rtx, int));
+static int estimate_case_costs         PROTO((case_node_ptr));
+static void group_case_nodes           PROTO((case_node_ptr));
+static void balance_case_nodes         PROTO((case_node_ptr *,
+                                              case_node_ptr));
+static int node_has_low_bound          PROTO((case_node_ptr, tree));
+static int node_has_high_bound         PROTO((case_node_ptr, tree));
+static int node_is_bounded             PROTO((case_node_ptr, tree));
+static void emit_jump_if_reachable     PROTO((rtx));
+static void emit_case_nodes            PROTO((rtx, case_node_ptr, rtx, tree));
+static int add_case_node               PROTO((tree, tree, tree, tree *));
+static struct case_node *case_tree2list        PROTO((case_node *, case_node *));
+
+extern rtx bc_allocate_local ();
+extern rtx bc_allocate_variable_array ();
 \f
 void
 init_stmt ()
@@ -453,6 +483,7 @@ init_stmt_for_function ()
 {
   /* We are not currently within any block, conditional, loop or case.  */
   block_stack = 0;
+  stack_block_stack = 0;
   loop_stack = 0;
   case_stack = 0;
   cond_stack = 0;
@@ -514,11 +545,17 @@ restore_stmt_status (p)
 void
 emit_nop ()
 {
-  rtx last_insn = get_last_insn ();
-  if (!optimize
-      && (GET_CODE (last_insn) == CODE_LABEL
-         || prev_real_insn (last_insn) == 0))
-    emit_insn (gen_nop ());
+  rtx last_insn;
+
+  if (!output_bytecode)
+    {
+      last_insn = get_last_insn ();
+      if (!optimize
+         && (GET_CODE (last_insn) == CODE_LABEL
+             || (GET_CODE (last_insn) == NOTE
+                 && prev_real_insn (last_insn) == 0)))
+       emit_insn (gen_nop ());
+    }
 }
 \f
 /* Return the rtx-label that corresponds to a LABEL_DECL,
@@ -555,9 +592,23 @@ void
 expand_computed_goto (exp)
      tree exp;
 {
-  rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
-  emit_queue ();
-  emit_indirect_jump (x);
+  if (output_bytecode)
+    {
+      bc_expand_expr (exp);
+      bc_emit_instruction (jumpP);
+    }
+  else
+    {
+      rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      x = convert_memory_address (Pmode, x);
+#endif
+
+      emit_queue ();
+      do_pending_stack_adjust ();
+      emit_indirect_jump (x);
+    }
 }
 \f
 /* Handle goto statements and the labels that they can go to.  */
@@ -579,6 +630,15 @@ expand_label (label)
 {
   struct label_chain *p;
 
+  if (output_bytecode)
+    {
+      if (! DECL_RTL (label))
+       DECL_RTL (label) = bc_gen_rtx ((char *) 0, 0, bc_get_bytecode_label ());
+      if (! bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (DECL_RTL (label))))
+       error ("multiply defined label");
+      return;
+    }
+
   do_pending_stack_adjust ();
   emit_label (label_rtx (label));
   if (DECL_NAME (label))
@@ -620,8 +680,16 @@ void
 expand_goto (label)
      tree label;
 {
+  tree context;
+
+  if (output_bytecode)
+    {
+      expand_goto_internal (label, label_rtx (label), NULL_RTX);
+      return;
+    }
+
   /* Check for a nonlocal goto to a containing function.  */
-  tree context = decl_function_context (label);
+  context = decl_function_context (label);
   if (context != 0 && context != current_function_decl)
     {
       struct function *p = find_function_data (context);
@@ -629,6 +697,7 @@ expand_goto (label)
       rtx temp;
 
       p->has_nonlocal_label = 1;
+      current_function_has_nonlocal_goto = 1;
       LABEL_REF_NONLOCAL_P (label_ref) = 1;
 
       /* Copy the rtl for the slots so that they won't be shared in
@@ -651,7 +720,7 @@ expand_goto (label)
             to the location of the function's incoming static chain info.
             The non-local goto handler will then adjust it to contain the
             proper value and reload the argument pointer, if needed.  */
-         emit_move_insn (frame_pointer_rtx, lookup_static_chain (label));
+         emit_move_insn (hard_frame_pointer_rtx, lookup_static_chain (label));
 
          /* We have now loaded the frame pointer hardware register with
             the address of that corresponds to the start of the virtual
@@ -662,21 +731,22 @@ expand_goto (label)
             which will do any cleanups and then jump to the label.  */
          addr = copy_rtx (p->nonlocal_goto_handler_slot);
          temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx,
-                                          frame_pointer_rtx));
+                                          hard_frame_pointer_rtx));
          
          /* Restore the stack pointer.  Note this uses fp just restored.  */
          addr = p->nonlocal_goto_stack_level;
          if (addr)
            addr = replace_rtx (copy_rtx (addr),
-                               virtual_stack_vars_rtx, frame_pointer_rtx);
+                               virtual_stack_vars_rtx,
+                               hard_frame_pointer_rtx);
 
          emit_stack_restore (SAVE_NONLOCAL, addr, NULL_RTX);
 
          /* Put in the static chain register the nonlocal label address.  */
          emit_move_insn (static_chain_rtx, label_ref);
-         /* USE of frame_pointer_rtx added for consistency; not clear if
+         /* USE of hard_frame_pointer_rtx added for consistency; not clear if
             really needed.  */
-         emit_insn (gen_rtx (USE, VOIDmode, frame_pointer_rtx));
+         emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
          emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx));
          emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx));
          emit_indirect_jump (temp);
@@ -700,6 +770,16 @@ expand_goto_internal (body, label, last_insn)
   struct nesting *block;
   rtx stack_level = 0;
 
+  /* 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. */
+  if (output_bytecode)
+    {
+      expand_goto_internal (body, label, last_insn);
+      return;
+    }
+
   if (GET_CODE (label) != CODE_LABEL)
     abort ();
 
@@ -721,7 +801,7 @@ expand_goto_internal (body, label, last_insn)
          /* Execute the cleanups for blocks we are exiting.  */
          if (block->data.block.cleanups != 0)
            {
-             expand_cleanups (block->data.block.cleanups, NULL_TREE);
+             expand_cleanups (block->data.block.cleanups, NULL_TREE, 1, 1);
              do_pending_stack_adjust ();
            }
        }
@@ -752,6 +832,78 @@ expand_goto_internal (body, label, last_insn)
   emit_jump (label);
 }
 \f
+/* Generate a jump with OPCODE to the given bytecode LABEL which is
+   found within BODY. */
+
+static void
+bc_expand_goto_internal (opcode, label, body)
+     enum bytecode_opcode opcode;
+     struct bc_label *label;
+     tree body;
+{
+  struct nesting *block;
+  int stack_level = -1;
+
+  /* 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. */
+
+  if (label->defined)
+    {
+
+      /* Find the innermost pending block that contains the label.
+        (Check containment by comparing bytecode uids.)  Then restore the
+        outermost stack level within that block.  */
+
+      for (block = block_stack; block; block = block->next)
+       {
+         if (BYTECODE_BC_LABEL (block->data.block.first_insn)->uid < label->uid)
+           break;
+         if (block->data.block.bc_stack_level)
+           stack_level = block->data.block.bc_stack_level;
+
+         /* Execute the cleanups for blocks we are exiting.  */
+         if (block->data.block.cleanups != 0)
+           {
+             expand_cleanups (block->data.block.cleanups, NULL_TREE, 1, 1);
+             do_pending_stack_adjust ();
+           }
+       }
+
+      /* Restore the stack level. If we need to adjust the stack, we
+        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. */
+
+      if (stack_level >= 0
+         && stack_depth != stack_level
+         && opcode != jump)
+
+       bc_expand_fixup (opcode, label, stack_level);
+      else
+       {
+         if (stack_level >= 0)
+           bc_adjust_stack (stack_depth - stack_level);
+
+         if (body && DECL_BIT_FIELD (body))
+           error ("jump to `%s' invalidly jumps into binding contour",
+                  IDENTIFIER_POINTER (DECL_NAME (body)));
+         
+         /* Emit immediate jump */
+         bc_emit_bytecode (opcode);
+         bc_emit_bytecode_labelref (label);
+         
+#ifdef DEBUG_PRINT_CODE
+         fputc ('\n', stderr);
+#endif
+       }
+    }
+  else
+    /* Put goto in the fixup list */
+    bc_expand_fixup (opcode, label, stack_level);
+}
+\f
 /* Generate if necessary a fixup for a goto
    whose target label in tree structure (if any) is TREE_LABEL
    and whose target in rtl is RTL_LABEL.
@@ -883,6 +1035,46 @@ expand_fixup (tree_label, rtl_label, last_insn)
   return block != 0;
 }
 
+
+/* Generate bytecode jump with OPCODE to a fixup routine that links to LABEL.
+   Make the fixup restore the stack level to STACK_LEVEL.  */
+
+static void
+bc_expand_fixup (opcode, label, stack_level)
+     enum bytecode_opcode opcode;
+     struct bc_label *label;
+     int stack_level;
+{
+  struct goto_fixup *fixup
+    = (struct goto_fixup *) oballoc (sizeof (struct goto_fixup));
+
+  fixup->label  = bc_get_bytecode_label ();
+  fixup->bc_target = label;
+  fixup->bc_stack_level = stack_level;
+  fixup->bc_handled = FALSE;
+
+  fixup->next = goto_fixup_chain;
+  goto_fixup_chain = fixup;
+
+  /* Insert a jump to the fixup code */
+  bc_emit_bytecode (opcode);
+  bc_emit_bytecode_labelref (fixup->label);
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+}
+\f
+/* Expand any needed fixups in the outputmost binding level of the
+   function.  FIRST_INSN is the first insn in the function.  */
+
+void
+expand_fixups (first_insn)
+     rtx first_insn;
+{
+  fixup_gotos (NULL_PTR, NULL_RTX, NULL_TREE, first_insn, 0);
+}
+
 /* When exiting a binding contour, process all pending gotos requiring fixups.
    THISBLOCK is the structure that describes the block being exited.
    STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
@@ -896,7 +1088,7 @@ expand_fixup (tree_label, rtl_label, last_insn)
    contour from before the beginning of the contour.
    This is also done if STACK_LEVEL is nonzero.  */
 
-void
+static void
 fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
      struct nesting *thisblock;
      rtx stack_level;
@@ -906,6 +1098,15 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
 {
   register struct goto_fixup *f, *prev;
 
+  if (output_bytecode)
+    {
+      /* ??? The second arg is the bc stack level, which is not the same
+        as STACK_LEVEL.  I have no idea what should go here, so I'll
+        just pass 0.  */
+      bc_fixup_gotos (thisblock, 0, cleanup_list, first_insn, dont_jump_in);
+      return;
+    }
+
   /* F is the fixup we are considering; PREV is the previous one.  */
   /* We run this loop in two passes so that cleanups of exited blocks
      are run first, and blocks that are exited are marked so
@@ -946,12 +1147,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
              && (after_label == 0
                  || INSN_UID (first_insn) < INSN_UID (after_label))
              && INSN_UID (first_insn) > INSN_UID (f->before_jump)
-             && ! DECL_REGISTER (f->target))
+             && ! DECL_ERROR_ISSUED (f->target))
            {
              error_with_decl (f->target,
                               "label `%s' used before containing binding contour");
              /* Prevent multiple errors for one label.  */
-             DECL_REGISTER (f->target) = 1;
+             DECL_ERROR_ISSUED (f->target) = 1;
            }
 
          /* We will expand the cleanups into a sequence of their own and
@@ -977,7 +1178,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
                if (TREE_ADDRESSABLE (lists)
                    && TREE_VALUE (lists) != 0)
                  {
-                   expand_cleanups (TREE_VALUE (lists), 0);
+                   expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1);
                    /* Pop any pushes done in the cleanups,
                       in case function is about to return.  */
                    do_pending_stack_adjust ();
@@ -1009,35 +1210,114 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
        }
     }
 
-  /* Mark the cleanups of exited blocks so that they are executed
-     by the code above.  */
+  /* 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. */
   for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
     if (f->before_jump != 0
        && PREV_INSN (f->target_rtl) == 0
        /* Label has still not appeared.  If we are exiting a block with
           a stack level to restore, that started before the fixup,
           mark this stack level as needing restoration
-          when the fixup is later finalized.
-          Also mark the cleanup_list_list element for F
-          that corresponds to this block, so that ultimately
-          this block's cleanups will be executed by the code above.  */
+          when the fixup is later finalized.   */
        && thisblock != 0
-       /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared,
-          it means the label is undefined.  That's erroneous, but possible.  */
+       /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it
+          means the label is undefined.  That's erroneous, but possible.  */
        && (thisblock->data.block.block_start_count
            <= f->block_start_count))
       {
        tree lists = f->cleanup_list_list;
+       rtx cleanup_insns;
+
        for (; lists; lists = TREE_CHAIN (lists))
          /* If the following elt. corresponds to our containing block
             then the elt. must be for this block.  */
          if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups)
-           TREE_ADDRESSABLE (lists) = 1;
+           {
+             start_sequence ();
+             pushlevel (0);
+             set_block (f->context);
+             expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1);
+             do_pending_stack_adjust ();
+             cleanup_insns = get_insns ();
+             poplevel (1, 0, 0);
+             end_sequence ();
+             f->before_jump
+               = emit_insns_after (cleanup_insns, f->before_jump);
+
+             f->cleanup_list_list = TREE_CHAIN (lists);
+           }
 
        if (stack_level)
          f->stack_level = stack_level;
       }
 }
+
+
+/* When exiting a binding contour, process all pending gotos requiring fixups.
+   Note: STACK_DEPTH is not altered.
+
+   The arguments are currently not used in the bytecode compiler, but we may
+   need them one day for languages other than C.
+
+   THISBLOCK is the structure that describes the block being exited.
+   STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
+   CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
+   FIRST_INSN is the insn that began this contour.
+
+   Gotos that jump out of this contour must restore the
+   stack level and do the cleanups before actually jumping.
+
+   DONT_JUMP_IN nonzero means report error there is a jump into this
+   contour from before the beginning of the contour.
+   This is also done if STACK_LEVEL is nonzero.  */
+
+static void
+bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
+     struct nesting *thisblock;
+     int stack_level;
+     tree cleanup_list;
+     rtx first_insn;
+     int dont_jump_in;
+{
+  register struct goto_fixup *f, *prev;
+  int saved_stack_depth;
+
+  /* F is the fixup we are considering; PREV is the previous one.  */
+
+  for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
+    {
+      /* Test for a fixup that is inactive because it is already handled.  */
+      if (f->before_jump == 0)
+       {
+         /* Delete inactive fixup from the chain, if that is easy to do.  */
+         if (prev)
+           prev->next = f->next;
+       }
+
+      /* Emit code to restore the stack and continue */
+      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. */
+
+      if (f->bc_stack_level >= 0)
+       {
+         saved_stack_depth = stack_depth;
+         bc_adjust_stack (stack_depth - f->bc_stack_level);
+         stack_depth = saved_stack_depth;
+       }
+
+      bc_emit_bytecode (jump);
+      bc_emit_bytecode_labelref (f->bc_target);
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+    }
+
+  goto_fixup_chain = NULL;
+}
 \f
 /* Generate RTL for an asm statement (explicit assembler code).
    BODY is a STRING_CST node containing the assembler code text,
@@ -1047,6 +1327,12 @@ void
 expand_asm (body)
      tree body;
 {
+  if (output_bytecode)
+    {
+      error ("`asm' is invalid when generating bytecode");
+      return;
+    }
+
   if (TREE_CODE (body) == ADDR_EXPR)
     body = TREE_OPERAND (body, 0);
 
@@ -1089,6 +1375,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   /* The insn we have emitted.  */
   rtx insn;
 
+  if (output_bytecode)
+    {
+      error ("`asm' is invalid when generating bytecode");
+      return;
+    }
+
   /* Count the number of meaningful clobbered registers, ignoring what
      we would ignore later.  */
   nclobbers = 0;
@@ -1098,6 +1390,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       i = decode_reg_name (regname);
       if (i >= 0 || i == -4)
        ++nclobbers;
+      else if (i == -2)
+       error ("unknown register name `%s' in `asm'", regname);
     }
 
   last_expr_type = 0;
@@ -1105,58 +1399,86 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
     {
       tree val = TREE_VALUE (tail);
+      tree type = TREE_TYPE (val);
       tree val1;
       int j;
-      int found_equal;
+      int found_equal = 0;
+      int allows_reg = 0;
 
       /* If there's an erroneous arg, emit no insn.  */
       if (TREE_TYPE (val) == error_mark_node)
        return;
 
-      /* Make sure constraint has `=' and does not have `+'.  */
+      /* Make sure constraint has `=' and does not have `+'.  Also, see
+        if it allows any register.  Be liberal on the latter test, since
+        the worst that happens if we get it wrong is we issue an error
+        message.  */
 
-      found_equal = 0;
-      for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)); j++)
-       {
-         if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '+')
-           {
-             error ("output operand constraint contains `+'");
-             return;
-           }
-         if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '=')
+      for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
+       switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
+         {
+         case '+':
+           error ("output operand constraint contains `+'");
+           return;
+
+         case '=':
            found_equal = 1;
-       }
+           break;
+
+         case '?':  case '!':  case '*':  case '%':  case '&':
+         case 'V':  case 'm':  case 'o':  case '<':  case '>':
+         case 'E':  case 'F':  case 'G':  case 'H':  case 'X':
+         case 's':  case 'i':  case 'n':
+         case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
+         case 'N':  case 'O':  case 'P':  case ',':
+#ifdef EXTRA_CONSTRAINT
+         case 'Q':  case 'R':  case 'S':  case 'T':  case 'U':
+#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':
+         default:
+           allows_reg = 1;
+           break;
+         }
+
       if (! found_equal)
        {
          error ("output operand constraint lacks `='");
          return;
        }
 
-      /* If an output operand is not a variable or indirect ref,
-        or a part of one,
-        create a SAVE_EXPR which is a pseudo-reg
-        to act as an intermediate temporary.
-        Make the asm insn write into that, then copy it to
-        the real output operand.  */
+      /* If an output operand is not a decl or indirect ref and our constraint
+        allows a register, make a temporary to act as an intermediate.
+        Make the asm insn write into that, then our caller will copy it to
+        the real output operand.  Likewise for promoted variables.  */
+
+      if (TREE_CODE (val) == INDIRECT_REF
+         || (TREE_CODE_CLASS (TREE_CODE (val)) == 'd'
+             && ! (GET_CODE (DECL_RTL (val)) == REG
+                   && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
+         || ! allows_reg)
+       {
+         if (! allows_reg)
+           mark_addressable (TREE_VALUE (tail));
 
-      while (TREE_CODE (val) == COMPONENT_REF
-            || TREE_CODE (val) == ARRAY_REF)
-       val = TREE_OPERAND (val, 0);
+         output_rtx[i]
+           = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
 
-      if (TREE_CODE (val) != VAR_DECL
-         && TREE_CODE (val) != PARM_DECL
-         && TREE_CODE (val) != INDIRECT_REF)
+         if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
+           error ("output number %d not directly addressable", i);
+       }
+      else
        {
-         TREE_VALUE (tail) = save_expr (TREE_VALUE (tail));
-         /* If it's a constant, print error now so don't crash later.  */
-         if (TREE_CODE (TREE_VALUE (tail)) != SAVE_EXPR)
-           {
-             error ("invalid output in `asm'");
-             return;
-           }
+         output_rtx[i] = assign_temp (type, 0, 0, 0);
+         TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
        }
-
-      output_rtx[i] = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
     }
 
   if (ninputs + noutputs > MAX_RECOG_OPERANDS)
@@ -1182,6 +1504,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   for (tail = inputs; tail; tail = TREE_CHAIN (tail))
     {
       int j;
+      int allows_reg = 0;
 
       /* If there's an erroneous arg, emit no insn,
         because the ASM_INPUT would get VOIDmode
@@ -1197,17 +1520,68 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       /* Make sure constraint has neither `=' nor `+'.  */
 
-      for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)); j++)
-       if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '='
-           || TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '+')
+      for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
+       switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
          {
+         case '+':   case '=':
            error ("input operand constraint contains `%c'",
                   TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]);
            return;
+
+         case '?':  case '!':  case '*':  case '%':  case '&':
+         case 'V':  case 'm':  case 'o':  case '<':  case '>':
+         case 'E':  case 'F':  case 'G':  case 'H':  case 'X':
+         case 's':  case 'i':  case 'n':
+         case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
+         case 'N':  case 'O':  case 'P':  case ',':
+#ifdef EXTRA_CONSTRAINT
+         case 'Q':  case 'R':  case 'S':  case 'T':  case 'U':
+#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':
+         default:
+           allows_reg = 1;
+           break;
          }
 
+      if (! allows_reg)
+       mark_addressable (TREE_VALUE (tail));
+
       XVECEXP (body, 3, i)      /* argvec */
        = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
+      if (CONSTANT_P (XVECEXP (body, 3, i))
+         && ! general_operand (XVECEXP (body, 3, i),
+                               TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)))))
+       {
+         if (allows_reg)
+           XVECEXP (body, 3, i)
+             = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
+                          XVECEXP (body, 3, i));
+         else
+           XVECEXP (body, 3, i)
+             = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
+                                XVECEXP (body, 3, i));
+       }
+
+      if (! allows_reg
+         && (GET_CODE (XVECEXP (body, 3, i)) == REG
+             || GET_CODE (XVECEXP (body, 3, i)) == SUBREG
+             || GET_CODE (XVECEXP (body, 3, i)) == CONCAT))
+       {
+         tree type = TREE_TYPE (TREE_VALUE (tail));
+         rtx memloc = assign_temp (type, 1, 1, 1);
+
+         emit_move_insn (memloc, XVECEXP (body, 3, i));
+         XVECEXP (body, 3, i) = memloc;
+       }
+         
       XVECEXP (body, 4, i)      /* constraints */
        = gen_rtx (ASM_INPUT, TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
                   TREE_STRING_POINTER (TREE_PURPOSE (tail)));
@@ -1282,13 +1656,13 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
                {
                  XVECEXP (body, 0, i++)
                    = gen_rtx (CLOBBER, VOIDmode,
-                              gen_rtx (MEM, QImode,
+                              gen_rtx (MEM, BLKmode,
                                        gen_rtx (SCRATCH, VOIDmode, 0)));
                  continue;
                }
 
-             error ("unknown register name `%s' in `asm'", regname);
-             return;
+             /* Ignore unknown register, error already signalled.  */
+             continue;
            }
 
          /* Use QImode since that's guaranteed to clobber just one reg.  */
@@ -1309,6 +1683,22 @@ void
 expand_expr_stmt (exp)
      tree exp;
 {
+  if (output_bytecode)
+    {
+      int org_stack_depth = stack_depth;
+
+      bc_expand_expr (exp);
+
+      /* Restore stack depth */
+      if (stack_depth < org_stack_depth)
+       abort ();
+      
+      bc_emit_instruction (drop);
+
+      last_expr_type = TREE_TYPE (exp);
+      return;
+    }
+
   /* If -W, warn about statements with no side effects,
      except for an explicit cast to void (e.g. for assert()), and
      except inside a ({...}) where they may be useful.  */
@@ -1322,6 +1712,12 @@ expand_expr_stmt (exp)
       else if (warn_unused)
        warn_if_unused_value (exp);
     }
+
+  /* If EXP is of function type and we are expanding statements for
+     value, convert it to pointer-to-function.  */
+  if (expr_stmts_for_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
+    exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
+
   last_expr_type = TREE_TYPE (exp);
   if (! flag_syntax_only)
     last_expr_value = expand_expr (exp,
@@ -1368,7 +1764,7 @@ expand_expr_stmt (exp)
 /* Warn if EXP contains any computations whose results are not used.
    Return 1 if a warning is printed; 0 otherwise.  */
 
-static int
+int
 warn_if_unused_value (exp)
      tree exp;
 {
@@ -1398,12 +1794,17 @@ warn_if_unused_value (exp)
       /* For a binding, warn if no side effect within it.  */
       return warn_if_unused_value (TREE_OPERAND (exp, 1));
 
+    case SAVE_EXPR:
+      return warn_if_unused_value (TREE_OPERAND (exp, 1));
+
     case TRUTH_ORIF_EXPR:
     case TRUTH_ANDIF_EXPR:
       /* In && or ||, warn if 2nd operand has no side effect.  */
       return warn_if_unused_value (TREE_OPERAND (exp, 1));
 
     case COMPOUND_EXPR:
+      if (TREE_NO_UNUSED_WARNING (exp))
+       return 0;
       if (warn_if_unused_value (TREE_OPERAND (exp, 0)))
        return 1;
       /* Let people do `(foo (), 0)' without a warning.  */
@@ -1421,22 +1822,35 @@ warn_if_unused_value (exp)
       if (TREE_NO_UNUSED_WARNING (exp))
        return 0;
       /* Assignment to a cast usually results in a cast of a modify.
-        Don't complain about that.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == MODIFY_EXPR)
-       return 0;
-      /* Sometimes it results in a cast of a cast of a modify.
-        Don't complain about that.  */
-      if ((TREE_CODE (TREE_OPERAND (exp, 0)) == CONVERT_EXPR
-          || TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR)
-         && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == MODIFY_EXPR)
-       return 0;
+        Don't complain about that.  There can be an arbitrary number of
+        casts before the modify, so we must loop until we find the first
+        non-cast expression and then test to see if that is a modify.  */
+      {
+       tree tem = TREE_OPERAND (exp, 0);
+
+       while (TREE_CODE (tem) == CONVERT_EXPR || TREE_CODE (tem) == NOP_EXPR)
+         tem = TREE_OPERAND (tem, 0);
 
+       if (TREE_CODE (tem) == MODIFY_EXPR || TREE_CODE (tem) == INIT_EXPR
+           || TREE_CODE (tem) == CALL_EXPR)
+         return 0;
+      }
+      goto warn;
+
+    case INDIRECT_REF:
+      /* Don't warn about automatic dereferencing of references, since
+        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 ... */
+      
     default:
       /* Referencing a volatile value is a side effect, so don't warn.  */
       if ((TREE_CODE_CLASS (TREE_CODE (exp)) == 'd'
           || TREE_CODE_CLASS (TREE_CODE (exp)) == 'r')
          && TREE_THIS_VOLATILE (exp))
        return 0;
+    warn:
       warning_with_file_and_line (emit_filename, emit_lineno,
                                  "value computed is not used");
       return 1;
@@ -1458,12 +1872,20 @@ clear_last_expr ()
 tree
 expand_start_stmt_expr ()
 {
+  int momentary;
+  tree t;
+
+  /* When generating bytecode just note down the stack depth */
+  if (output_bytecode)
+    return (build_int_2 (stack_depth, 0));
+
   /* Make the RTL_EXPR node temporary, not momentary,
      so that rtl_expr_chain doesn't become garbage.  */
-  int momentary = suspend_momentary ();
-  tree t = make_node (RTL_EXPR);
+  momentary = suspend_momentary ();
+  t = make_node (RTL_EXPR);
   resume_momentary (momentary);
-  start_sequence ();
+  do_pending_stack_adjust ();
+  start_sequence_for_rtl_expr (t);
   NO_DEFER_POP;
   expr_stmts_for_value++;
   return t;
@@ -1485,6 +1907,38 @@ tree
 expand_end_stmt_expr (t)
      tree t;
 {
+  if (output_bytecode)
+    {
+      int i;
+      tree t;
+      
+      
+      /* At this point, all expressions have been evaluated in order.
+        However, all expression values have been popped when evaluated,
+        which means we have to recover the last expression value.  This is
+        the last value removed by means of a `drop' instruction.  Instead
+        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]'. */
+      
+      bc_adjust_stack (-1);
+      
+      if (!last_expr_type)
+       last_expr_type = void_type_node;
+      
+      t = make_node (RTL_EXPR);
+      TREE_TYPE (t) = last_expr_type;
+      RTL_EXPR_RTL (t) = NULL;
+      RTL_EXPR_SEQUENCE (t) = NULL;
+      
+      /* Don't consider deleting this expr or containing exprs at tree level.  */
+      TREE_THIS_VOLATILE (t) = 1;
+      
+      last_expr_type = 0;
+      return t;
+    }
+
   OK_DEFER_POP;
 
   if (last_expr_type == 0)
@@ -1521,380 +1975,162 @@ expand_end_stmt_expr (t)
   return t;
 }
 \f
-/* The exception handling nesting looks like this:
-
-               <-- Level N-1
-    {          <-- exception handler block
-               <-- Level N
-               <-- in an exception handler
-       {       <-- try block
-       :       <-- in a TRY block
-       :       <-- in an exception handler
-       :
-       }
+/* Generate RTL for the start of an if-then.  COND is the expression
+   whose truth should be tested.
 
-       {       <-- except block
-       :       <-- in an except block
-       :       <-- in an exception handler
-       :
-       }
+   If EXITFLAG is nonzero, this conditional is visible to
+   `exit_something'.  */
 
-    }
-*/
+void
+expand_start_cond (cond, exitflag)
+     tree cond;
+     int exitflag;
+{
+  struct nesting *thiscond = ALLOC_NESTING ();
 
-/* Return nonzero iff in a try block at level LEVEL.  */
+  /* Make an entry on cond_stack for the cond we are entering.  */
 
-int
-in_try_block (level)
-     int level;
-{
-  struct nesting *n = except_stack;
-  while (1)
-    {
-      while (n && n->data.except_stmt.after_label != 0)
-       n = n->next;
-      if (n == 0)
-       return 0;
-      if (level == 0)
-       return n != 0;
-      level--;
-      n = n->next;
-    }
+  thiscond->next = cond_stack;
+  thiscond->all = nesting_stack;
+  thiscond->depth = ++nesting_depth;
+  thiscond->data.cond.next_label = gen_label_rtx ();
+  /* Before we encounter an `else', we don't need a separate exit label
+     unless there are supposed to be exit statements
+     to exit this conditional.  */
+  thiscond->exit_label = exitflag ? gen_label_rtx () : 0;
+  thiscond->data.cond.endif_label = thiscond->exit_label;
+  cond_stack = thiscond;
+  nesting_stack = thiscond;
+
+  if (output_bytecode)
+    bc_expand_start_cond (cond, exitflag);
+  else
+    do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
 }
 
-/* Return nonzero iff in an except block at level LEVEL.  */
-
-int
-in_except_block (level)
-     int level;
-{
-  struct nesting *n = except_stack;
-  while (1)
-    {
-      while (n && n->data.except_stmt.after_label == 0)
-       n = n->next;
-      if (n == 0)
-       return 0;
-      if (level == 0)
-       return n != 0;
-      level--;
-      n = n->next;
-    }
-}
-
-/* Return nonzero iff in an exception handler at level LEVEL.  */
-
-int
-in_exception_handler (level)
-     int level;
-{
-  struct nesting *n = except_stack;
-  while (n && level--)
-    n = n->next;
-  return n != 0;
-}
-
-/* Record the fact that the current exception nesting raises
-   exception EX.  If not in an exception handler, return 0.  */
-int
-expand_raise (ex)
-     tree ex;
-{
-  tree *raises_ptr;
-
-  if (except_stack == 0)
-    return 0;
-  raises_ptr = &except_stack->data.except_stmt.raised;
-  if (! value_member (ex, *raises_ptr))
-    *raises_ptr = tree_cons (NULL_TREE, ex, *raises_ptr);
-  return 1;
-}
-
-/* Generate RTL for the start of a try block.
-
-   TRY_CLAUSE is the condition to test to enter the try block.  */
+/* Generate RTL between then-clause and the elseif-clause
+   of an if-then-elseif-....  */
 
 void
-expand_start_try (try_clause, exitflag, escapeflag)
-     tree try_clause;
-     int exitflag;
-     int escapeflag;
+expand_start_elseif (cond)
+     tree cond;
 {
-  struct nesting *thishandler = ALLOC_NESTING ();
-
-  /* Make an entry on cond_stack for the cond we are entering.  */
-
-  thishandler->next = except_stack;
-  thishandler->all = nesting_stack;
-  thishandler->depth = ++nesting_depth;
-  thishandler->data.except_stmt.raised = 0;
-  thishandler->data.except_stmt.handled = 0;
-  thishandler->data.except_stmt.first_insn = get_insns ();
-  thishandler->data.except_stmt.except_label = gen_label_rtx ();
-  thishandler->data.except_stmt.unhandled_label = 0;
-  thishandler->data.except_stmt.after_label = 0;
-  thishandler->data.except_stmt.escape_label
-    = escapeflag ? thishandler->data.except_stmt.except_label : 0;
-  thishandler->exit_label = exitflag ? gen_label_rtx () : 0;
-  except_stack = thishandler;
-  nesting_stack = thishandler;
-
-  do_jump (try_clause, thishandler->data.except_stmt.except_label, NULL_RTX);
+  if (cond_stack->data.cond.endif_label == 0)
+    cond_stack->data.cond.endif_label = gen_label_rtx ();
+  emit_jump (cond_stack->data.cond.endif_label);
+  emit_label (cond_stack->data.cond.next_label);
+  cond_stack->data.cond.next_label = gen_label_rtx ();
+  do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
 }
 
-/* End of a TRY block.  Nothing to do for now.  */
+/* Generate RTL between the then-clause and the else-clause
+   of an if-then-else.  */
 
 void
-expand_end_try ()
+expand_start_else ()
 {
-  except_stack->data.except_stmt.after_label = gen_label_rtx ();
-  expand_goto_internal (NULL_TREE, except_stack->data.except_stmt.after_label,
-                       NULL_RTX);
-}
-
-/* Start an `except' nesting contour.
-   EXITFLAG says whether this contour should be able to `exit' something.
-   ESCAPEFLAG says whether this contour should be escapable.  */
+  if (cond_stack->data.cond.endif_label == 0)
+    cond_stack->data.cond.endif_label = gen_label_rtx ();
 
-void
-expand_start_except (exitflag, escapeflag)
-     int exitflag;
-     int escapeflag;
-{
-  if (exitflag)
-    {
-      struct nesting *n;
-      /* An `exit' from catch clauses goes out to next exit level,
-        if there is one.  Otherwise, it just goes to the end
-        of the construct.  */
-      for (n = except_stack->next; n; n = n->next)
-       if (n->exit_label != 0)
-         {
-           except_stack->exit_label = n->exit_label;
-           break;
-         }
-      if (n == 0)
-       except_stack->exit_label = except_stack->data.except_stmt.after_label;
-    }
-  if (escapeflag)
+  if (output_bytecode)
     {
-      struct nesting *n;
-      /* An `escape' from catch clauses goes out to next escape level,
-        if there is one.  Otherwise, it just goes to the end
-        of the construct.  */
-      for (n = except_stack->next; n; n = n->next)
-       if (n->data.except_stmt.escape_label != 0)
-         {
-           except_stack->data.except_stmt.escape_label
-             = n->data.except_stmt.escape_label;
-           break;
-         }
-      if (n == 0)
-       except_stack->data.except_stmt.escape_label
-         = except_stack->data.except_stmt.after_label;
+      bc_expand_start_else ();
+      return;
     }
-  do_pending_stack_adjust ();
-  emit_label (except_stack->data.except_stmt.except_label);
+
+  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. */
 }
 
-/* Generate code to `escape' from an exception contour.  This
-   is like `exiting', but does not conflict with constructs which
-   use `exit_label'.
+/* After calling expand_start_else, turn this "else" into an "else if"
+   by providing another condition.  */
 
-   Return nonzero if this contour is escapable, otherwise
-   return zero, and language-specific code will emit the
-   appropriate error message.  */
-int
-expand_escape_except ()
+void
+expand_elseif (cond)
+     tree cond;
 {
-  struct nesting *n;
-  last_expr_type = 0;
-  for (n = except_stack; n; n = n->next)
-    if (n->data.except_stmt.escape_label != 0)
-      {
-       expand_goto_internal (NULL_TREE,
-                             n->data.except_stmt.escape_label, NULL_RTX);
-       return 1;
-      }
-
-  return 0;
+  cond_stack->data.cond.next_label = gen_label_rtx ();
+  do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
 }
 
-/* Finish processing and `except' contour.
-   Culls out all exceptions which might be raise but not
-   handled, and returns the list to the caller.
-   Language-specific code is responsible for dealing with these
-   exceptions.  */
+/* Generate RTL for the end of an if-then.
+   Pop the record for it off of cond_stack.  */
 
-tree
-expand_end_except ()
+void
+expand_end_cond ()
 {
-  struct nesting *n;
-  tree raised = NULL_TREE;
-
-  do_pending_stack_adjust ();
-  emit_label (except_stack->data.except_stmt.after_label);
+  struct nesting *thiscond = cond_stack;
 
-  n = except_stack->next;
-  if (n)
+  if (output_bytecode)
+    bc_expand_end_cond ();
+  else
     {
-      /* Propagate exceptions raised but not handled to next
-        highest level.  */
-      tree handled = except_stack->data.except_stmt.raised;
-      if (handled != void_type_node)
-       {
-         tree prev = NULL_TREE;
-         raised = except_stack->data.except_stmt.raised;
-         while (handled)
-           {
-             tree this_raise;
-             for (this_raise = raised, prev = 0; this_raise;
-                  this_raise = TREE_CHAIN (this_raise))
-               {
-                 if (value_member (TREE_VALUE (this_raise), handled))
-                   {
-                     if (prev)
-                       TREE_CHAIN (prev) = TREE_CHAIN (this_raise);
-                     else
-                       {
-                         raised = TREE_CHAIN (raised);
-                         if (raised == NULL_TREE)
-                           goto nada;
-                       }
-                   }
-                 else
-                   prev = this_raise;
-               }
-             handled = TREE_CHAIN (handled);
-           }
-         if (prev == NULL_TREE)
-           prev = raised;
-         if (prev)
-           TREE_CHAIN (prev) = n->data.except_stmt.raised;
-       nada:
-         n->data.except_stmt.raised = raised;
-       }
+      do_pending_stack_adjust ();
+      if (thiscond->data.cond.next_label)
+       emit_label (thiscond->data.cond.next_label);
+      if (thiscond->data.cond.endif_label)
+       emit_label (thiscond->data.cond.endif_label);
     }
 
-  POPSTACK (except_stack);
+  POPSTACK (cond_stack);
   last_expr_type = 0;
-  return raised;
-}
-
-/* Record that exception EX is caught by this exception handler.
-   Return nonzero if in exception handling construct, otherwise return 0.  */
-int
-expand_catch (ex)
-     tree ex;
-{
-  tree *raises_ptr;
-
-  if (except_stack == 0)
-    return 0;
-  raises_ptr = &except_stack->data.except_stmt.handled;
-  if (*raises_ptr != void_type_node
-      && ex != NULL_TREE
-      && ! value_member (ex, *raises_ptr))
-    *raises_ptr = tree_cons (NULL_TREE, ex, *raises_ptr);
-  return 1;
 }
 
-/* Record that this exception handler catches all exceptions.
-   Return nonzero if in exception handling construct, otherwise return 0.  */
-
-int
-expand_catch_default ()
-{
-  if (except_stack == 0)
-    return 0;
-  except_stack->data.except_stmt.handled = void_type_node;
-  return 1;
-}
-
-int
-expand_end_catch ()
-{
-  if (except_stack == 0 || except_stack->data.except_stmt.after_label == 0)
-    return 0;
-  expand_goto_internal (NULL_TREE, except_stack->data.except_stmt.after_label,
-                       NULL_RTX);
-  return 1;
-}
-\f
-/* Generate RTL for the start of an if-then.  COND is the expression
-   whose truth should be tested.
 
-   If EXITFLAG is nonzero, this conditional is visible to
-   `exit_something'.  */
+/* 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. */
 
-void
-expand_start_cond (cond, exitflag)
+static void
+bc_expand_start_cond (cond, exitflag)
      tree cond;
      int exitflag;
 {
-  struct nesting *thiscond = ALLOC_NESTING ();
-
-  /* Make an entry on cond_stack for the cond we are entering.  */
+  struct nesting *thiscond = cond_stack;
 
-  thiscond->next = cond_stack;
-  thiscond->all = nesting_stack;
-  thiscond->depth = ++nesting_depth;
-  thiscond->data.cond.next_label = gen_label_rtx ();
-  /* Before we encounter an `else', we don't need a separate exit label
-     unless there are supposed to be exit statements
-     to exit this conditional.  */
-  thiscond->exit_label = exitflag ? gen_label_rtx () : 0;
-  thiscond->data.cond.endif_label = thiscond->exit_label;
-  cond_stack = thiscond;
-  nesting_stack = thiscond;
+  thiscond->data.case_stmt.nominal_type = cond;
+  if (! exitflag)
+    thiscond->exit_label = gen_label_rtx ();
+  bc_expand_expr (cond);
+  bc_emit_bytecode (xjumpifnot);
+  bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscond->exit_label));
 
-  do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
 }
 
-/* Generate RTL between then-clause and the elseif-clause
-   of an if-then-elseif-....  */
+/* Generate the label for the end of an if with
+   no else- clause.  */
 
-void
-expand_start_elseif (cond)
-     tree cond;
+static void
+bc_expand_end_cond ()
 {
-  if (cond_stack->data.cond.endif_label == 0)
-    cond_stack->data.cond.endif_label = gen_label_rtx ();
-  emit_jump (cond_stack->data.cond.endif_label);
-  emit_label (cond_stack->data.cond.next_label);
-  cond_stack->data.cond.next_label = gen_label_rtx ();
-  do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
-}
-
-/* Generate RTL between the then-clause and the else-clause
-   of an if-then-else.  */
+  struct nesting *thiscond = cond_stack;
 
-void
-expand_start_else ()
-{
-  if (cond_stack->data.cond.endif_label == 0)
-    cond_stack->data.cond.endif_label = gen_label_rtx ();
-  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. */
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->exit_label));
 }
 
-/* Generate RTL for the end of an if-then.
-   Pop the record for it off of cond_stack.  */
+/* Generate code for the start of the else- clause of
+   an if-then-else.  */
 
-void
-expand_end_cond ()
+static void
+bc_expand_start_else ()
 {
   struct nesting *thiscond = cond_stack;
 
-  do_pending_stack_adjust ();
-  if (thiscond->data.cond.next_label)
-    emit_label (thiscond->data.cond.next_label);
-  if (thiscond->data.cond.endif_label)
-    emit_label (thiscond->data.cond.endif_label);
+  thiscond->data.cond.endif_label = thiscond->exit_label;
+  thiscond->exit_label = gen_label_rtx ();
+  bc_emit_bytecode (jump);
+  bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscond->exit_label));
 
-  POPSTACK (cond_stack);
-  last_expr_type = 0;
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->data.cond.endif_label));
 }
 \f
 /* Generate RTL for the start of a loop.  EXIT_FLAG is nonzero if this
@@ -1917,11 +2153,18 @@ expand_start_loop (exit_flag)
   thisloop->depth = ++nesting_depth;
   thisloop->data.loop.start_label = gen_label_rtx ();
   thisloop->data.loop.end_label = gen_label_rtx ();
+  thisloop->data.loop.alt_end_label = 0;
   thisloop->data.loop.continue_label = thisloop->data.loop.start_label;
   thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0;
   loop_stack = thisloop;
   nesting_stack = thisloop;
 
+  if (output_bytecode)
+    {
+      bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisloop->data.loop.start_label));
+      return thisloop;
+    }
+
   do_pending_stack_adjust ();
   emit_queue ();
   emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
@@ -1950,21 +2193,55 @@ expand_start_loop_continue_elsewhere (exit_flag)
 void
 expand_loop_continue_here ()
 {
+  if (output_bytecode)
+    {
+      bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (loop_stack->data.loop.continue_label));
+      return;
+    }
   do_pending_stack_adjust ();
   emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
   emit_label (loop_stack->data.loop.continue_label);
 }
 
+/* End a loop.  */
+
+static void
+bc_expand_end_loop ()
+{
+  struct nesting *thisloop = loop_stack;
+
+  bc_emit_bytecode (jump);
+  bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thisloop->data.loop.start_label));
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisloop->exit_label));
+  POPSTACK (loop_stack);
+  last_expr_type = 0;
+}
+
+
 /* Finish a loop.  Generate a jump back to the top and the loop-exit label.
    Pop the block off of loop_stack.  */
 
 void
 expand_end_loop ()
 {
-  register rtx insn = get_last_insn ();
-  register rtx start_label = loop_stack->data.loop.start_label;
+  register rtx insn;
+  register rtx start_label;
   rtx last_test_insn = 0;
   int num_insns = 0;
+    
+  if (output_bytecode)
+    {
+      bc_expand_end_loop ();
+      return;
+    }
+
+  insn = get_last_insn ();
+  start_label = loop_stack->data.loop.start_label;
 
   /* Mark the continue-point at the top of the loop if none elsewhere.  */
   if (start_label == loop_stack->data.loop.continue_label)
@@ -2013,19 +2290,25 @@ expand_end_loop ()
              && SET_DEST (PATTERN (insn)) == pc_rtx
              && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
              && ((GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == LABEL_REF
-                  && (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0)
-                      == loop_stack->data.loop.end_label))
+                  && ((XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0)
+                       == loop_stack->data.loop.end_label)
+                      || (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0)
+                          == loop_stack->data.loop.alt_end_label)))
                  || (GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 2)) == LABEL_REF
-                     && (XEXP (XEXP (SET_SRC (PATTERN (insn)), 2), 0)
-                         == loop_stack->data.loop.end_label))))
+                     && ((XEXP (XEXP (SET_SRC (PATTERN (insn)), 2), 0)
+                          == loop_stack->data.loop.end_label)
+                         || (XEXP (XEXP (SET_SRC (PATTERN (insn)), 2), 0)
+                             == loop_stack->data.loop.alt_end_label)))))
            last_test_insn = insn;
 
          if (last_test_insn == 0 && GET_CODE (insn) == JUMP_INSN
              && GET_CODE (PATTERN (insn)) == SET
              && SET_DEST (PATTERN (insn)) == pc_rtx
              && GET_CODE (SET_SRC (PATTERN (insn))) == LABEL_REF
-             && (XEXP (SET_SRC (PATTERN (insn)), 0)
-                 == loop_stack->data.loop.end_label))
+             && ((XEXP (SET_SRC (PATTERN (insn)), 0)
+                  == loop_stack->data.loop.end_label)
+                 || (XEXP (SET_SRC (PATTERN (insn)), 0)
+                     == loop_stack->data.loop.alt_end_label)))
            /* Include BARRIER.  */
            last_test_insn = NEXT_INSN (insn);
        }
@@ -2112,7 +2395,31 @@ expand_exit_loop_if_false (whichloop, cond)
     whichloop = loop_stack;
   if (whichloop == 0)
     return 0;
-  do_jump (cond, whichloop->data.loop.end_label, NULL_RTX);
+  if (output_bytecode)
+    {
+      bc_expand_expr (cond);
+      bc_expand_goto_internal (xjumpifnot,
+                              BYTECODE_BC_LABEL (whichloop->exit_label),
+                              NULL_TREE);
+    }
+  else
+    {
+      /* In order to handle fixups, we actually create a conditional jump
+        around a unconditional branch to exit the loop.  If fixups are
+        necessary, they go before the unconditional branch.  */
+
+      rtx label = gen_label_rtx ();
+      rtx last_insn;
+
+      do_jump (cond, NULL_RTX, label);
+      last_insn = get_last_insn ();
+      if (GET_CODE (last_insn) == CODE_LABEL)
+       whichloop->data.loop.alt_end_label = last_insn;
+      expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
+                           NULL_RTX);
+      emit_label (label);
+    }
+
   return 1;
 }
 
@@ -2175,6 +2482,12 @@ expand_null_return ()
   struct nesting *block = block_stack;
   rtx last_insn = 0;
 
+  if (output_bytecode)
+    {
+      bc_emit_instruction (ret);
+      return;
+    }
+
   /* Does any pending block have cleanups?  */
 
   while (block && block->data.block.cleanups == 0)
@@ -2187,7 +2500,7 @@ expand_null_return ()
 
 /* Generate RTL to return from the current function, with value VAL.  */
 
-void
+static void
 expand_value_return (val)
      rtx val;
 {
@@ -2201,17 +2514,11 @@ expand_value_return (val)
   if (return_reg != val)
     {
 #ifdef PROMOTE_FUNCTION_RETURN
-      enum machine_mode mode = DECL_MODE (DECL_RESULT (current_function_decl));
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
       int unsignedp = TREE_UNSIGNED (type);
-
-      if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE
-         || TREE_CODE (type) == BOOLEAN_TYPE || TREE_CODE (type) == CHAR_TYPE
-         || TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == POINTER_TYPE
-         || TREE_CODE (type) == OFFSET_TYPE)
-       {
-         PROMOTE_MODE (mode, unsignedp, type);
-       }
+      enum machine_mode mode
+       = promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)),
+                       &unsignedp, 1);
 
       if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
        convert_move (return_reg, val, unsignedp);
@@ -2297,6 +2604,15 @@ expand_return (retval)
   int cleanups;
   struct nesting *block;
 
+  /* Bytecode returns are quite simple, just leave the result on the
+     arithmetic stack. */
+  if (output_bytecode)
+    {
+      bc_expand_expr (retval);
+      bc_emit_instruction (ret);
+      return;
+    }
+  
   /* If function wants no value, give it none.  */
   if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
     {
@@ -2307,7 +2623,15 @@ expand_return (retval)
     }
 
   /* Are any cleanups needed?  E.g. C++ destructors to be run?  */
+  /* This is not sufficient.  We also need to watch for cleanups of the
+     expression we are about to expand.  Unfortunately, we cannot know
+     if it has cleanups until we expand it, and we want to change how we
+     expand it depending upon if we need cleanups.  We can't win.  */
+#if 0
   cleanups = any_pending_cleanups (1);
+#else
+  cleanups = 1;
+#endif
 
   if (TREE_CODE (retval) == RESULT_DECL)
     retval_rhs = retval;
@@ -2337,14 +2661,21 @@ expand_return (retval)
          || TREE_CODE (TREE_OPERAND (retval_rhs, 2)) == CALL_EXPR))
     {
       rtx label = gen_label_rtx ();
+      tree expr;
+
       do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
-      expand_return (build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
-                           DECL_RESULT (current_function_decl),
-                           TREE_OPERAND (retval_rhs, 1)));
+      expr = build (MODIFY_EXPR, 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);
-      expand_return (build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
-                           DECL_RESULT (current_function_decl),
-                           TREE_OPERAND (retval_rhs, 2)));
+
+      expr = build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
+                   DECL_RESULT (current_function_decl),
+                   TREE_OPERAND (retval_rhs, 2));
+      TREE_SIDE_EFFECTS (expr) = 1;
+      expand_return (expr);
       return;
     }
 
@@ -2381,11 +2712,13 @@ expand_return (retval)
      because expand_null_return takes care of them, too.
      Any reason why not?  */
   if (HAVE_return && cleanup_label == 0
-      && ! current_function_returns_pcc_struct)
+      && ! current_function_returns_pcc_struct
+      && BRANCH_COST <= 1)
     {
       /* 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.  */
+        if we can do it with explicit return insns and
+        branches are cheap.  */
       if (retval_rhs)
        switch (TREE_CODE (retval_rhs))
          {
@@ -2411,7 +2744,112 @@ expand_return (retval)
     }
 #endif /* HAVE_return */
 
-  if (cleanups
+  /* If the result is an aggregate that is being returned in one (or more)
+     registers, load the registers here.  The compiler currently can't handle
+     copying a BLKmode value into registers.  We could put this code in a
+     more general area (for use by everyone instead of just function
+     call/return), but until this feature is generally usable it is kept here
+     (and in expand_call).  The value must go into a pseudo in case there
+     are cleanups that will clobber the real return register.  */
+
+  if (retval_rhs != 0
+      && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
+      && GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)
+    {
+      int i, bitpos, xbitpos;
+      int big_endian_correction = 0;
+      int bytes = int_size_in_bytes (TREE_TYPE (retval_rhs));
+      int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+      int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)),BITS_PER_WORD);
+      rtx *result_pseudos = (rtx *) alloca (sizeof (rtx) * n_regs);
+      rtx result_reg, src, dst;
+      rtx result_val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
+      enum machine_mode tmpmode, result_reg_mode;
+
+      /* Structures whose size is not a multiple of a word are aligned
+        to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
+        machine, this means we must skip the empty high order bytes when
+        calculating the bit offset.  */
+      if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
+       big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
+                                                 * BITS_PER_UNIT));
+
+      /* Copy the structure BITSIZE bits at a time.  */ 
+      for (bitpos = 0, xbitpos = big_endian_correction;
+          bitpos < bytes * BITS_PER_UNIT;
+          bitpos += bitsize, xbitpos += bitsize)
+       {
+         /* We need a new destination pseudo each time xbitpos is
+            on a word boundary and when xbitpos == big_endian_correction
+            (the first time through).  */
+         if (xbitpos % BITS_PER_WORD == 0
+             || xbitpos == big_endian_correction)
+           {
+             /* Generate an appropriate register.  */
+             dst = gen_reg_rtx (word_mode);
+             result_pseudos[xbitpos / BITS_PER_WORD] = dst;
+
+             /* Clobber the destination before we move anything into it.  */
+             emit_insn (gen_rtx (CLOBBER, VOIDmode, dst));
+           }
+
+         /* We need a new source operand each time bitpos is on a word
+            boundary.  */
+         if (bitpos % BITS_PER_WORD == 0)
+           src = operand_subword_force (result_val,
+                                        bitpos / BITS_PER_WORD,
+                                        BLKmode);
+
+         /* Use bitpos for the source extraction (left justified) and
+            xbitpos for the destination store (right justified).  */
+         store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode,
+                          extract_bit_field (src, bitsize,
+                                             bitpos % BITS_PER_WORD, 1,
+                                             NULL_RTX, word_mode,
+                                             word_mode,
+                                             bitsize / BITS_PER_UNIT,
+                                             BITS_PER_WORD),
+                          bitsize / BITS_PER_UNIT, BITS_PER_WORD);
+       }
+
+      /* Find the smallest integer mode large enough to hold the
+        entire structure and use that mode instead of BLKmode
+        on the USE insn for the return register.   */
+      bytes = int_size_in_bytes (TREE_TYPE (retval_rhs));
+      for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+          tmpmode != MAX_MACHINE_MODE;
+          tmpmode = GET_MODE_WIDER_MODE (tmpmode))
+       {
+         /* Have we found a large enough mode?  */
+         if (GET_MODE_SIZE (tmpmode) >= bytes)
+           break;
+       }
+
+      /* No suitable mode found.  */
+      if (tmpmode == MAX_MACHINE_MODE)
+       abort ();
+
+      PUT_MODE (DECL_RTL (DECL_RESULT (current_function_decl)), tmpmode);
+
+      if (GET_MODE_SIZE (tmpmode) < GET_MODE_SIZE (word_mode))
+       result_reg_mode = word_mode;
+      else
+       result_reg_mode = tmpmode;
+      result_reg = gen_reg_rtx (result_reg_mode);
+
+      /* Now that the value is in pseudos, copy it to the result reg(s).  */
+      emit_queue ();
+      free_temp_slots ();
+      for (i = 0; i < n_regs; i++)
+       emit_move_insn (operand_subword (result_reg, i, 0, result_reg_mode),
+                       result_pseudos[i]);
+
+      if (tmpmode != result_reg_mode)
+       result_reg = gen_lowpart (tmpmode, result_reg);
+
+      expand_value_return (result_reg);
+    }
+  else if (cleanups
       && retval_rhs != 0
       && TREE_TYPE (retval_rhs) != void_type_node
       && GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)
@@ -2428,7 +2866,7 @@ expand_return (retval)
     {
       /* No cleanups or no hard reg used;
         calculate value into hard return reg.  */
-      expand_expr (retval, NULL_RTX, VOIDmode, 0);
+      expand_expr (retval, const0_rtx, VOIDmode, 0);
       emit_queue ();
       free_temp_slots ();
       expand_value_return (DECL_RTL (DECL_RESULT (current_function_decl)));
@@ -2470,7 +2908,8 @@ tail_recursion_args (actuals, formals)
 
   for (a = actuals, f = formals, i = 0; a && f; a = TREE_CHAIN (a), f = TREE_CHAIN (f), i++)
     {
-      if (TREE_TYPE (TREE_VALUE (a)) != TREE_TYPE (f))
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (a)))
+         != TYPE_MAIN_VARIANT (TREE_TYPE (f)))
        return 0;
       if (GET_CODE (DECL_RTL (f)) != REG || DECL_MODE (f) == BLKmode)
        return 0;
@@ -2526,8 +2965,7 @@ expand_start_bindings (exit_flag)
      int exit_flag;
 {
   struct nesting *thisblock = ALLOC_NESTING ();
-
-  rtx note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+  rtx note = output_bytecode ? 0 : emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
 
   /* Make an entry on block_stack for the block we are entering.  */
 
@@ -2570,8 +3008,11 @@ expand_start_bindings (exit_flag)
   block_stack = thisblock;
   nesting_stack = thisblock;
 
-  /* Make a new level for allocating stack slots.  */
-  push_temp_slots ();
+  if (!output_bytecode)
+    {
+      /* Make a new level for allocating stack slots.  */
+      push_temp_slots ();
+    }
 }
 
 /* Given a pointer to a BLOCK node, save a pointer to the most recently
@@ -2604,9 +3045,15 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
   register struct nesting *thisblock = block_stack;
   register tree decl;
 
-  if (warn_unused)
-    for (decl = vars; decl; decl = TREE_CHAIN (decl))
-      if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
+  if (output_bytecode)
+    {
+      bc_expand_end_bindings (vars, mark_ends, dont_jump_in);
+      return;
+    }
+
+  if (warn_unused)
+    for (decl = vars; decl; decl = TREE_CHAIN (decl))
+      if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
          && ! DECL_IN_SYSTEM_HEADER (decl))
        warning_with_decl (decl, "unused variable `%s'");
 
@@ -2632,6 +3079,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       rtx afterward = gen_label_rtx ();
       rtx handler_label = gen_label_rtx ();
       rtx save_receiver = gen_reg_rtx (Pmode);
+      rtx insns;
 
       /* Don't let jump_optimize delete the handler.  */
       LABEL_PRESERVE_P (handler_label) = 1;
@@ -2641,14 +3089,20 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       if (thisblock->next != 0)
        {
          emit_move_insn (nonlocal_goto_handler_slot, save_receiver);
-         emit_insn_before (gen_move_insn (save_receiver,
-                                          nonlocal_goto_handler_slot),
-                           thisblock->data.block.first_insn);
+
+         start_sequence ();
+         emit_move_insn (save_receiver, nonlocal_goto_handler_slot);
+         insns = get_insns ();
+         end_sequence ();
+         emit_insns_before (insns, thisblock->data.block.first_insn);
        }
-      emit_insn_before (gen_move_insn (nonlocal_goto_handler_slot,
-                                      gen_rtx (LABEL_REF, Pmode,
-                                               handler_label)),
-                       thisblock->data.block.first_insn);
+
+      start_sequence ();
+      emit_move_insn (nonlocal_goto_handler_slot,
+                     gen_rtx (LABEL_REF, Pmode, handler_label));
+      insns = get_insns ();
+      end_sequence ();
+      emit_insns_before (insns, thisblock->data.block.first_insn);
 
       /* Jump around the handler; it runs only when specially invoked.  */
       emit_jump (afterward);
@@ -2668,9 +3122,9 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
           the original assignment true.
           So the following insn will actually be
           decrementing fp by STARTING_FRAME_OFFSET.  */
-       emit_move_insn (virtual_stack_vars_rtx, frame_pointer_rtx);
+       emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
 
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
       if (fixed_regs[ARG_POINTER_REGNUM])
        {
 #ifdef ELIMINABLE_REGS
@@ -2684,7 +3138,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
 
          for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
            if (elim_regs[i].from == ARG_POINTER_REGNUM
-               && elim_regs[i].to == FRAME_POINTER_REGNUM)
+               && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
              break;
 
          if (i == sizeof elim_regs / sizeof elim_regs [0])
@@ -2725,6 +3179,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       /* If label is not recognized, abort.  */
       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "abort"), 0,
                         VOIDmode, 0);
+      emit_barrier ();
       emit_label (afterward);
     }
 
@@ -2756,6 +3211,9 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
   if (thisblock->data.block.stack_level != 0
       || thisblock->data.block.cleanups != 0)
     {
+      /* Only clean up here if this point can actually be reached.  */
+      int reachable = GET_CODE (get_last_insn ()) != BARRIER;
+
       /* Don't let cleanups affect ({...}) constructs.  */
       int old_expr_stmts_for_value = expr_stmts_for_value;
       rtx old_last_expr_value = last_expr_value;
@@ -2763,8 +3221,9 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       expr_stmts_for_value = 0;
 
       /* Do the cleanups.  */
-      expand_cleanups (thisblock->data.block.cleanups, NULL_TREE);
-      do_pending_stack_adjust ();
+      expand_cleanups (thisblock->data.block.cleanups, NULL_TREE, 0, reachable);
+      if (reachable)
+       do_pending_stack_adjust ();
 
       expr_stmts_for_value = old_expr_stmts_for_value;
       last_expr_value = old_last_expr_value;
@@ -2772,7 +3231,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
 
       /* Restore the stack level.  */
 
-      if (thisblock->data.block.stack_level != 0)
+      if (reachable && thisblock->data.block.stack_level != 0)
        {
          emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
                              thisblock->data.block.stack_level, NULL_RTX);
@@ -2820,31 +3279,53 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
   /* Pop the stack slot nesting and free any slots at this level.  */
   pop_temp_slots ();
 }
-\f
-/* Generate RTL for the automatic variable declaration DECL.
-   (Other kinds of declarations are simply ignored if seen here.)
-   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' 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.
 
-   If CLEANUP is nonzero and DECL is zero, we record a cleanup
-   that is not associated with any particular variable.
+/* End a binding contour.
+   VARS is the chain of VAR_DECL nodes for the variables bound
+   in this contour.  MARK_ENDS is nonzer if we should put a note
+   at the beginning and end of this binding contour.
+   DONT_JUMP_IN is nonzero if it is not valid to jump into this
+   contour.  */
 
-   There is no special support here for C++ constructors.
-   They should be handled by the proper code in DECL_INITIAL.  */
+static void
+bc_expand_end_bindings (vars, mark_ends, dont_jump_in)
+     tree vars;
+     int mark_ends;
+     int dont_jump_in;
+{
+  struct nesting *thisbind = nesting_stack;
+  tree decl;
+
+  if (warn_unused)
+    for (decl = vars; decl; decl = TREE_CHAIN (decl))
+      if (! TREE_USED (TREE_VALUE (decl)) && TREE_CODE (TREE_VALUE (decl)) == VAR_DECL)
+       warning_with_decl (decl, "unused variable `%s'");
+
+  if (thisbind->exit_label)
+    bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisbind->exit_label));
+
+  /* Pop block/bindings off stack */
+  POPSTACK (block_stack);
+}
+\f
+/* Generate RTL for the automatic variable declaration DECL.
+   (Other kinds of declarations are simply ignored if seen here.)  */
 
 void
 expand_decl (decl)
      register tree decl;
 {
   struct nesting *thisblock = block_stack;
-  tree type = TREE_TYPE (decl);
+  tree type;
+
+  if (output_bytecode)
+    {
+      bc_expand_decl (decl, 0);
+      return;
+    }
+
+  type = TREE_TYPE (decl);
 
   /* Only automatic variables need any expansion done.
      Static and external variables, and external functions,
@@ -2871,6 +3352,7 @@ expand_decl (decl)
        /* An initializer is going to decide the size of this array.
           Until we know the size, represent its address with a reg.  */
        DECL_RTL (decl) = gen_rtx (MEM, BLKmode, gen_reg_rtx (Pmode));
+      MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (type);
     }
   else if (DECL_MODE (decl) != BLKmode
           /* If -ffloat-store, don't put explicit float vars
@@ -2882,21 +3364,33 @@ expand_decl (decl)
           && (DECL_REGISTER (decl) || ! obey_regdecls))
     {
       /* Automatic variable that can go in a register.  */
-      enum machine_mode reg_mode = DECL_MODE (decl);
       int unsignedp = TREE_UNSIGNED (type);
+      enum machine_mode reg_mode
+       = promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
 
-      if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE
-         || TREE_CODE (type) == BOOLEAN_TYPE || TREE_CODE (type) == CHAR_TYPE
-         || TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == POINTER_TYPE
-         || TREE_CODE (type) == OFFSET_TYPE)
+      if (TREE_CODE (type) == COMPLEX_TYPE)
        {
-         PROMOTE_MODE (reg_mode, unsignedp, 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);
-      if (TREE_CODE (type) == POINTER_TYPE)
-       mark_reg_pointer (DECL_RTL (decl));
-      REG_USERVAR_P (DECL_RTL (decl)) = 1;
     }
   else if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
     {
@@ -2922,6 +3416,7 @@ expand_decl (decl)
                               + BITS_PER_UNIT - 1)
                              / BITS_PER_UNIT),
                             1);
+      MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
 
       /* Set alignment we actually gave this decl.  */
       DECL_ALIGN (decl) = (DECL_MODE (decl) == BLKmode ? BIGGEST_ALIGNMENT
@@ -2936,11 +3431,7 @@ expand_decl (decl)
 
       /* If this is a memory ref that contains aggregate components,
         mark it as such for cse and loop optimize.  */
-      MEM_IN_STRUCT_P (DECL_RTL (decl))
-       = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-          || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
-          || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
-          || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE);
+      MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
 #if 0
       /* If this is in memory because of -ffloat-store,
         set the volatile bit, to prevent optimizations from
@@ -2972,26 +3463,19 @@ expand_decl (decl)
                          NULL_RTX, VOIDmode, 0);
       free_temp_slots ();
 
-      /* This is equivalent to calling alloca.  */
-      current_function_calls_alloca = 1;
-
-      /* 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));
-
-      if (nonlocal_goto_handler_slot != 0)
-       emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
+                                             TYPE_ALIGN (TREE_TYPE (decl)));
 
       /* Reference the variable indirect through that rtx.  */
       DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), address);
 
       /* If this is a memory ref that contains aggregate components,
         mark it as such for cse and loop optimize.  */
-      MEM_IN_STRUCT_P (DECL_RTL (decl))
-       = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-          || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
-          || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
-          || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE);
+      MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
 
       /* Indicate the alignment we actually gave this variable.  */
 #ifdef STACK_BOUNDARY
@@ -3019,6 +3503,52 @@ expand_decl (decl)
   if (obey_regdecls)
     use_variable (DECL_RTL (decl));
 }
+
+
+/* Generate code for the automatic variable declaration DECL.  For
+   most variables this just means we give it a stack offset.  The
+   compiler sometimes emits cleanups without variables and we will
+   have to deal with those too.  */
+
+static void
+bc_expand_decl (decl, cleanup)
+     tree decl;
+     tree cleanup;
+{
+  tree type;
+
+  if (!decl)
+    {
+      /* A cleanup with no variable.  */
+      if (!cleanup)
+       abort ();
+
+      return;
+    }
+
+  /* Only auto variables need any work.  */
+  if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+    return;
+
+  type = TREE_TYPE (decl);
+
+  if (type == error_mark_node)
+    DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
+
+  else if (DECL_SIZE (decl) == 0)
+
+    /* Variable with incomplete type.  The stack offset herein will be
+       fixed later in expand_decl_init ().  */
+    DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
+
+  else if (TREE_CONSTANT (DECL_SIZE (decl)))
+    {
+      DECL_RTL (decl) = bc_allocate_local (TREE_INT_CST_LOW (DECL_SIZE (decl)) / BITS_PER_UNIT,
+                                          DECL_ALIGN (decl));
+    }
+  else
+    DECL_RTL (decl) = bc_allocate_variable_array (DECL_SIZE (decl));
+}
 \f
 /* Emit code to perform the initialization of a declaration DECL.  */
 
@@ -3028,6 +3558,26 @@ expand_decl_init (decl)
 {
   int was_used = TREE_USED (decl);
 
+  if (output_bytecode)
+    {
+      bc_expand_decl_init (decl);
+      return;
+    }
+
+  /* If this is a CONST_DECL, we don't have to generate any code, but
+     if DECL_INITIAL is a constant, call expand_expr to force TREE_CST_RTL
+     to be set while in the obstack containing the constant.  If we don't
+     do this, we can lose if we have functions nested three deep and the middle
+     function makes a CONST_DECL whose DECL_INITIAL is a STRING_CST while
+     the innermost function is the first to expand that STRING_CST.  */
+  if (TREE_CODE (decl) == CONST_DECL)
+    {
+      if (DECL_INITIAL (decl) && TREE_CONSTANT (DECL_INITIAL (decl)))
+       expand_expr (DECL_INITIAL (decl), NULL_RTX, VOIDmode,
+                    EXPAND_INITIALIZER);
+      return;
+    }
+
   if (TREE_STATIC (decl))
     return;
 
@@ -3053,18 +3603,93 @@ expand_decl_init (decl)
   TREE_USED (decl) = was_used;
 
   /* Free any temporaries we made while initializing the decl.  */
+  preserve_temp_slots (NULL_RTX);
   free_temp_slots ();
 }
 
+/* Expand initialization for variable-sized types. Allocate array
+   using newlocalSI and set local variable, which is a pointer to the
+   storage. */
+
+static void
+bc_expand_variable_local_init (decl)
+     tree decl;
+{
+  /* Evaluate size expression and coerce to SI */
+  bc_expand_expr (DECL_SIZE (decl));
+
+  /* Type sizes are always (?) of TREE_CODE INTEGER_CST, so
+     no coercion is necessary (?) */
+
+/*  emit_typecode_conversion (preferred_typecode (TYPE_MODE (DECL_SIZE (decl)),
+                                               TREE_UNSIGNED (DECL_SIZE (decl))), SIcode); */
+
+  /* Emit code to allocate array */
+  bc_emit_instruction (newlocalSI);
+
+  /* Store array pointer in local variable. This is the only instance
+     where we actually want the address of the pointer to the
+     variable-size block, rather than the pointer itself.  We avoid
+     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). */
+
+  bc_load_localaddr (DECL_RTL (decl));
+  bc_emit_instruction (storeP);
+}
+
+
+/* Emit code to initialize a declaration.  */
+
+static void
+bc_expand_decl_init (decl)
+     tree decl;
+{
+  int org_stack_depth;
+
+  /* Statical initializers are handled elsewhere */
+
+  if (TREE_STATIC (decl))
+    return;
+
+  /* Memory original stack depth */
+  org_stack_depth = stack_depth;
+
+  /* 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. */
+
+  if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+    bc_expand_variable_local_init (decl);
+
+  /* Expand initializer assignment */
+  if (DECL_INITIAL (decl) == error_mark_node)
+    {
+      enum tree_code code = TREE_CODE (TREE_TYPE (decl));
+
+      if (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
+         || code == POINTER_TYPE)
+
+       expand_assignment (TREE_TYPE (decl), decl, 0, 0);
+    }
+  else if (DECL_INITIAL (decl))
+    expand_assignment (TREE_TYPE (decl), decl, 0, 0);
+
+  /* Restore stack depth */
+  if (org_stack_depth > stack_depth)
+    abort ();
+
+  bc_adjust_stack (stack_depth - org_stack_depth);
+}
+
 /* 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' 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.   */
@@ -3083,10 +3708,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);
     }
   return 1;
 }
@@ -3102,7 +3730,8 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
   struct nesting *thisblock = block_stack;
   rtx x;
 
-  expand_decl (decl, cleanup);
+  expand_decl (decl);
+  expand_decl_cleanup (decl, cleanup);
   x = DECL_RTL (decl);
 
   while (decl_elts)
@@ -3111,6 +3740,17 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
       tree cleanup_elt = TREE_PURPOSE (decl_elts);
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
 
+      /* Propagate the union's alignment to the elements.  */
+      DECL_ALIGN (decl_elt) = DECL_ALIGN (decl);
+
+      /* If the element has BLKmode and the union doesn't, the union is
+         aligned such that the element doesn't need to have BLKmode, so
+         change the element's mode to the appropriate one for its size.  */
+      if (mode == BLKmode && DECL_MODE (decl) != BLKmode)
+       DECL_MODE (decl_elt) = mode
+         = mode_for_size (TREE_INT_CST_LOW (DECL_SIZE (decl_elt)),
+                          MODE_INT, 1);
+
       /* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
          instead create a new MEM rtx with the proper mode.  */
       if (GET_CODE (x) == MEM)
@@ -3151,31 +3791,45 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
    If DONT_DO is nonnull, then any list-element
    whose TREE_PURPOSE matches DONT_DO is omitted.
    This is sometimes used to avoid a cleanup associated with
-   a value that is being returned out of the scope.  */
+   a value that is being returned out of the scope.
+
+   If IN_FIXUP is non-zero, we are generating this cleanup for a fixup
+   goto and handle protection regions specially in that case.
+
+   If REACHABLE, we emit code, otherwise just inform the exception handling
+   code about this finalization.  */
 
 static void
-expand_cleanups (list, dont_do)
+expand_cleanups (list, dont_do, in_fixup, reachable)
      tree list;
      tree dont_do;
+     int in_fixup;
+     int reachable;
 {
   tree tail;
   for (tail = list; tail; tail = TREE_CHAIN (tail))
     if (dont_do == 0 || TREE_PURPOSE (tail) != dont_do)
       {
        if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-         expand_cleanups (TREE_VALUE (tail), dont_do);
+         expand_cleanups (TREE_VALUE (tail), dont_do, in_fixup, reachable);
        else
          {
-           /* Cleanups may be run multiple times.  For example,
-              when exiting a binding contour, we expand the
-              cleanups associated with that contour.  When a goto
-              within that binding contour has a target outside that
-              contour, it will expand all cleanups from its scope to
-              the target.  Though the cleanups are expanded multiple
-              times, the control paths are non-overlapping so the
-              cleanups will not be executed twice.  */
-           expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-           free_temp_slots ();
+           if (! in_fixup)
+             (*interim_eh_hook) (TREE_VALUE (tail));
+
+           if (reachable)
+             {
+               /* Cleanups may be run multiple times.  For example,
+                  when exiting a binding contour, we expand the
+                  cleanups associated with that contour.  When a goto
+                  within that binding contour has a target outside that
+                  contour, it will expand all cleanups from its scope to
+                  the target.  Though the cleanups are expanded multiple
+                  times, the control paths are non-overlapping so the
+                  cleanups will not be executed twice.  */
+               expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
+               free_temp_slots ();
+             }
          }
       }
 }
@@ -3274,6 +3928,12 @@ expand_start_case (exit_flag, expr, type, printname)
   case_stack = thiscase;
   nesting_stack = thiscase;
 
+  if (output_bytecode)
+    {
+      bc_expand_start_case (thiscase, expr, type, printname);
+      return;
+    }
+
   do_pending_stack_adjust ();
 
   /* Make sure case_stmt.start points to something that won't
@@ -3284,6 +3944,33 @@ expand_start_case (exit_flag, expr, type, printname)
   thiscase->data.case_stmt.start = get_last_insn ();
 }
 
+
+/* Enter a case statement. It is assumed that the caller has pushed
+   the current context onto the case stack. */
+
+static void
+bc_expand_start_case (thiscase, expr, type, printname)
+     struct nesting *thiscase;
+     tree expr;
+     tree type;
+     char *printname;
+{
+  bc_expand_expr (expr);
+  bc_expand_conversion (TREE_TYPE (expr), type);
+
+  /* For cases, the skip is a place we jump to that's emitted after
+     the size of the jump table is known.  */
+
+  thiscase->data.case_stmt.skip_label = gen_label_rtx ();
+  bc_emit_bytecode (jump);
+  bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->data.case_stmt.skip_label));
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+}
+
+
 /* Start a "dummy case statement" within which case labels are invalid
    and are not connected to any larger real case statement.
    This can be used if you don't want to let a case statement jump
@@ -3330,6 +4017,8 @@ case_index_expr_type ()
 \f
 /* Accumulate one case or default label inside a case or switch statement.
    VALUE is the value of the case (a null pointer, for a default label).
+   The function CONVERTER, when applied to arguments T and V,
+   converts the value V to the type T.
 
    If not currently inside a case or switch statement, return 1 and do
    nothing.  The caller will print a language-specific error message.
@@ -3342,8 +4031,9 @@ case_index_expr_type ()
    Extended to handle range statements.  */
 
 int
-pushcase (value, label, duplicate)
+pushcase (value, converter, label, duplicate)
      register tree value;
+     tree (*converter) PROTO((tree, tree));
      register tree label;
      tree *duplicate;
 {
@@ -3352,6 +4042,9 @@ pushcase (value, label, duplicate)
   tree index_type;
   tree nominal_type;
 
+  if (output_bytecode)
+    return bc_pushcase (value, label);
+
   /* Fail if not inside a real case statement.  */
   if (! (case_stack && case_stack->data.case_stmt.start))
     return 1;
@@ -3369,7 +4062,7 @@ pushcase (value, label, duplicate)
 
   /* Convert VALUE to the type in which the comparisons are nominally done.  */
   if (value != 0)
-    value = convert (nominal_type, value);
+    value = (*converter) (nominal_type, value);
 
   /* If this is the first label, warn if any insns have been emitted.  */
   if (case_stack->data.case_stmt.seenlabel == 0)
@@ -3405,159 +4098,591 @@ pushcase (value, label, duplicate)
          *duplicate = case_stack->data.case_stmt.default_label;
          return 2;
        }
-      case_stack->data.case_stmt.default_label = label;
-    }
-  else
-    {
-      /* Find the elt in the chain before which to insert the new value,
-        to keep the chain sorted in increasing order.
-        But report an error if this element is a duplicate.  */
-      for (l = &case_stack->data.case_stmt.case_list;
-          /* Keep going past elements distinctly less than VALUE.  */
-          *l != 0 && tree_int_cst_lt ((*l)->high, value);
-          l = &(*l)->right)
-       ;
-      if (*l)
+      case_stack->data.case_stmt.default_label = label;
+    }
+  else
+    return add_case_node (value, value, label, duplicate);
+
+  expand_label (label);
+  return 0;
+}
+
+/* Like pushcase but this case applies to all values
+   between VALUE1 and VALUE2 (inclusive).
+   The return value is the same as that of pushcase
+   but there is one additional error code:
+   4 means the specified range was empty.  */
+
+int
+pushcase_range (value1, value2, converter, label, duplicate)
+     register tree value1, value2;
+     tree (*converter) PROTO((tree, tree));
+     register tree label;
+     tree *duplicate;
+{
+  register struct case_node **l;
+  register struct case_node *n;
+  tree index_type;
+  tree nominal_type;
+
+  /* Fail if not inside a real case statement.  */
+  if (! (case_stack && case_stack->data.case_stmt.start))
+    return 1;
+
+  if (stack_block_stack
+      && stack_block_stack->depth > case_stack->depth)
+    return 5;
+
+  index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
+  nominal_type = case_stack->data.case_stmt.nominal_type;
+
+  /* If the index is erroneous, avoid more problems: pretend to succeed.  */
+  if (index_type == error_mark_node)
+    return 0;
+
+  /* If this is the first label, warn if any insns have been emitted.  */
+  if (case_stack->data.case_stmt.seenlabel == 0)
+    {
+      rtx insn;
+      for (insn = case_stack->data.case_stmt.start;
+          insn;
+          insn = NEXT_INSN (insn))
+       {
+         if (GET_CODE (insn) == CODE_LABEL)
+           break;
+         if (GET_CODE (insn) != NOTE
+             && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
+           {
+             warning ("unreachable code at beginning of %s",
+                      case_stack->data.case_stmt.printname);
+             break;
+           }
+       }
+    }
+  case_stack->data.case_stmt.seenlabel = 1;
+
+  /* Convert VALUEs to type in which the comparisons are nominally done.  */
+  if (value1 == 0)  /* Negative infinity. */
+    value1 = TYPE_MIN_VALUE(index_type);
+  value1 = (*converter) (nominal_type, value1);
+
+  if (value2 == 0)  /* Positive infinity. */
+    value2 = TYPE_MAX_VALUE(index_type);
+  value2 = (*converter) (nominal_type, value2);
+
+  /* Fail if these values are out of range.  */
+  if (! int_fits_type_p (value1, index_type))
+    return 3;
+
+  if (! int_fits_type_p (value2, index_type))
+    return 3;
+
+  /* Fail if the range is empty.  */
+  if (tree_int_cst_lt (value2, value1))
+    return 4;
+
+  return add_case_node (value1, value2, label, duplicate);
+}
+
+/* Do the actual insertion of a case label for pushcase and pushcase_range
+   into case_stack->data.case_stmt.case_list.  Use an AVL tree to avoid
+   slowdown for large switch statements.  */
+
+static int
+add_case_node (low, high, label, duplicate)
+     tree low, high;
+     tree label;
+     tree *duplicate;
+{
+  struct case_node *p, **q, *r;
+
+  q = &case_stack->data.case_stmt.case_list;
+  p = *q;
+
+  while (r = *q)
+    {
+      p = r;
+
+      /* Keep going past elements distinctly greater than HIGH.  */
+      if (tree_int_cst_lt (high, p->low))
+       q = &p->left;
+
+      /* or distinctly less than LOW.  */
+      else if (tree_int_cst_lt (p->high, low))
+       q = &p->right;
+
+      else
+       {
+         /* We have an overlap; this is an error.  */
+         *duplicate = p->code_label;
+         return 2;
+       }
+    }
+
+  /* Add this label to the chain, and succeed.
+     Copy LOW, HIGH so they are on temporary rather than momentary
+     obstack and will thus survive till the end of the case statement.  */
+
+  r = (struct case_node *) oballoc (sizeof (struct case_node));
+  r->low = copy_node (low);
+
+  /* If the bounds are equal, turn this into the one-value case.  */
+
+  if (tree_int_cst_equal (low, high))
+    r->high = r->low;
+  else
+    {
+      r->high = copy_node (high);
+      case_stack->data.case_stmt.num_ranges++;
+    }
+
+  r->code_label = label;
+  expand_label (label);
+
+  *q = r;
+  r->parent = p;
+  r->left = 0;
+  r->right = 0;
+  r->balance = 0;
+
+  while (p)
+    {
+      struct case_node *s;
+
+      if (r == p->left)
+       {
+         int b;
+
+         if (! (b = p->balance))
+           /* Growth propagation from left side.  */
+           p->balance = -1;
+         else if (b < 0)
+           {
+             if (r->balance < 0)
+               {
+                 /* R-Rotation */
+                 if (p->left = s = r->right)
+                   s->parent = p;
+
+                 r->right = p;
+                 p->balance = 0;
+                 r->balance = 0;
+                 s = p->parent;
+                 p->parent = r;
+
+                 if (r->parent = s)
+                   {
+                     if (s->left == p)
+                       s->left = r;
+                     else
+                       s->right = r;
+                   }
+                 else
+                   case_stack->data.case_stmt.case_list = r;
+               }
+             else
+               /* r->balance == +1 */
+               {
+                 /* LR-Rotation */
+
+                 int b2;
+                 struct case_node *t = r->right;
+
+                 if (p->left = s = t->right)
+                   s->parent = p;
+
+                 t->right = p;
+                 if (r->right = s = t->left)
+                   s->parent = r;
+
+                 t->left = r;
+                 b = t->balance;
+                 b2 = b < 0;
+                 p->balance = b2;
+                 b2 = -b2 - b;
+                 r->balance = b2;
+                 t->balance = 0;
+                 s = p->parent;
+                 p->parent = t;
+                 r->parent = t;
+
+                 if (t->parent = s)
+                   {
+                     if (s->left == p)
+                       s->left = t;
+                     else
+                       s->right = t;
+                   }
+                 else
+                   case_stack->data.case_stmt.case_list = t;
+               }
+             break;
+           }
+
+         else
+           {
+             /* p->balance == +1; growth of left side balances the node.  */
+             p->balance = 0;
+             break;
+           }
+       }
+      else
+       /* r == p->right */
        {
-         /* Element we will insert before must be distinctly greater;
-            overlap means error.  */
-         if (! tree_int_cst_lt (value, (*l)->low))
+         int b;
+
+         if (! (b = p->balance))
+           /* Growth propagation from right side.  */
+           p->balance++;
+         else if (b > 0)
+           {
+             if (r->balance > 0)
+               {
+                 /* L-Rotation */
+
+                 if (p->right = s = r->left)
+                   s->parent = p;
+
+                 r->left = p;
+                 p->balance = 0;
+                 r->balance = 0;
+                 s = p->parent;
+                 p->parent = r;
+                 if (r->parent = s)
+                   {
+                     if (s->left == p)
+                       s->left = r;
+                     else
+                       s->right = r;
+                   }
+
+                 else
+                   case_stack->data.case_stmt.case_list = r;
+               }
+
+             else
+               /* r->balance == -1 */
+               {
+                 /* RL-Rotation */
+                 int b2;
+                 struct case_node *t = r->left;
+
+                 if (p->right = s = t->left)
+                   s->parent = p;
+
+                 t->left = p;
+
+                 if (r->left = s = t->right)
+                   s->parent = r;
+
+                 t->right = r;
+                 b = t->balance;
+                 b2 = b < 0;
+                 r->balance = b2;
+                 b2 = -b2 - b;
+                 p->balance = b2;
+                 t->balance = 0;
+                 s = p->parent;
+                 p->parent = t;
+                 r->parent = t;
+
+                 if (t->parent = s)
+                   {
+                     if (s->left == p)
+                       s->left = t;
+                     else
+                       s->right = t;
+                   }
+
+                 else
+                   case_stack->data.case_stmt.case_list = t;
+               }
+             break;
+           }
+         else
            {
-             *duplicate = (*l)->code_label;
-             return 2;
+             /* p->balance == -1; growth of right side balances the node.  */
+             p->balance = 0;
+             break;
            }
        }
 
-      /* Add this label to the chain, and succeed.
-        Copy VALUE so it is on temporary rather than momentary
-        obstack and will thus survive till the end of the case statement.  */
-      n = (struct case_node *) oballoc (sizeof (struct case_node));
-      n->left = 0;
-      n->right = *l;
-      n->high = n->low = copy_node (value);
-      n->code_label = label;
-      *l = n;
+      r = p;
+      p = p->parent;
     }
 
-  expand_label (label);
   return 0;
 }
 
-/* Like pushcase but this case applies to all values
-   between VALUE1 and VALUE2 (inclusive).
-   The return value is the same as that of pushcase
-   but there is one additional error code:
-   4 means the specified range was empty.  */
+/* Accumulate one case or default label; VALUE is the value of the
+   case, or nil for a default label.  If not currently inside a case,
+   return 1 and do nothing.  If VALUE is a duplicate or overlaps, return
+   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. */
 
-int
-pushcase_range (value1, value2, label, duplicate)
-     register tree value1, value2;
-     register tree label;
-     tree *duplicate;
+static int
+bc_pushcase (value, label)
+     tree value;
+     tree label;
 {
-  register struct case_node **l;
-  register struct case_node *n;
-  tree index_type;
-  tree nominal_type;
+  struct nesting *thiscase = case_stack;
+  struct case_node *case_label, *new_label;
 
-  /* Fail if not inside a real case statement.  */
-  if (! (case_stack && case_stack->data.case_stmt.start))
+  if (! thiscase)
     return 1;
 
-  if (stack_block_stack
-      && stack_block_stack->depth > case_stack->depth)
-    return 5;
-
-  index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
-  nominal_type = case_stack->data.case_stmt.nominal_type;
+  /* Fail if duplicate, overlap, or out of type range.  */
+  if (value)
+    {
+      value = convert (thiscase->data.case_stmt.nominal_type, value);
+      if (! int_fits_type_p (value, thiscase->data.case_stmt.nominal_type))
+       return 3;
+
+      for (case_label = thiscase->data.case_stmt.case_list;
+          case_label->left; case_label = case_label->left)
+       if (! tree_int_cst_lt (case_label->left->high, value))
+         break;
+
+      if (case_label != thiscase->data.case_stmt.case_list
+         && ! tree_int_cst_lt (case_label->high, value)
+         || (case_label->left && ! tree_int_cst_lt (value, case_label->left->low)))
+       return 2;
+
+      new_label = (struct case_node *) oballoc (sizeof (struct case_node));
+      new_label->low = new_label->high = copy_node (value);
+      new_label->code_label = label;
+      new_label->left = case_label->left;
+
+      case_label->left = new_label;
+      thiscase->data.case_stmt.num_ranges++;
+    }
+  else
+    {
+      if (thiscase->data.case_stmt.default_label)
+       return 2;
+      thiscase->data.case_stmt.default_label = label;
+    }
 
-  /* If the index is erroneous, avoid more problems: pretend to succeed.  */
-  if (index_type == error_mark_node)
-    return 0;
+  expand_label (label);
+  return 0;
+}
+\f
+/* Returns the number of possible values of TYPE.
+   Returns -1 if the number is unknown or variable.
+   Returns -2 if the number does not fit in a HOST_WIDE_INT.
+   Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
+   do not increase monotonically (there may be duplicates);
+   to 1 if the values increase monotonically, but not always by 1;
+   otherwise sets it to 0.  */
+
+HOST_WIDE_INT
+all_cases_count (type, spareness)
+     tree type;
+     int *spareness;
+{
+  HOST_WIDE_INT count, count_high = 0;
+  *spareness = 0;
 
-  /* If this is the first label, warn if any insns have been emitted.  */
-  if (case_stack->data.case_stmt.seenlabel == 0)
+  switch (TREE_CODE (type))
     {
-      rtx insn;
-      for (insn = case_stack->data.case_stmt.start;
-          insn;
-          insn = NEXT_INSN (insn))
+      tree t;
+    case BOOLEAN_TYPE:
+      count = 2;
+      break;
+    case CHAR_TYPE:
+      count = 1 << BITS_PER_UNIT;
+      break;
+    default:
+    case INTEGER_TYPE:
+      if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+         || TREE_CODE (TYPE_MAX_VALUE (type)) != INTEGER_CST)
+       return -1;
+      else
        {
-         if (GET_CODE (insn) == CODE_LABEL)
-           break;
-         if (GET_CODE (insn) != NOTE
-             && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
+         /* count
+            = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
+            - TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + 1
+            but with overflow checking. */
+         tree mint = TYPE_MIN_VALUE (type);
+         tree maxt = TYPE_MAX_VALUE (type);
+         HOST_WIDE_INT lo, hi;
+         neg_double(TREE_INT_CST_LOW (mint), TREE_INT_CST_HIGH (mint),
+                    &lo, &hi);
+         add_double(TREE_INT_CST_LOW (maxt), TREE_INT_CST_HIGH (maxt),
+                    lo, hi, &lo, &hi);
+         add_double (lo, hi, 1, 0, &lo, &hi);
+         if (hi != 0 || lo < 0)
+           return -2;
+         count = lo;
+       }
+      break;
+    case ENUMERAL_TYPE:
+      count = 0;
+      for (t = TYPE_VALUES (type); t != NULL_TREE; t = TREE_CHAIN (t))
+       {
+         if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+             || TREE_CODE (TREE_VALUE (t)) != INTEGER_CST
+             || TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + count
+             != TREE_INT_CST_LOW (TREE_VALUE (t)))
+           *spareness = 1;
+         count++;
+       }
+      if (*spareness == 1)
+       {
+         tree prev = TREE_VALUE (TYPE_VALUES (type));
+         for (t = TYPE_VALUES (type); t = TREE_CHAIN (t), t != NULL_TREE; )
            {
-             warning ("unreachable code at beginning of %s",
-                      case_stack->data.case_stmt.printname);
-             break;
+             if (! tree_int_cst_lt (prev, TREE_VALUE (t)))
+               {
+                 *spareness = 2;
+                 break;
+               }
+             prev = TREE_VALUE (t);
            }
+         
        }
     }
-  case_stack->data.case_stmt.seenlabel = 1;
+  return count;
+}
 
-  /* Convert VALUEs to type in which the comparisons are nominally done.  */
-  if (value1 == 0)  /* Negative infinity. */
-    value1 = TYPE_MIN_VALUE(index_type);
-  value1 = convert (nominal_type, value1);
 
-  if (value2 == 0)  /* Positive infinity. */
-    value2 = TYPE_MAX_VALUE(index_type);
-  value2 = convert (nominal_type, value2);
+#define BITARRAY_TEST(ARRAY, INDEX) \
+  ((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))
 
-  /* Fail if these values are out of range.  */
-  if (! int_fits_type_p (value1, index_type))
-    return 3;
+/* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
+   with the case values we have seen, assuming the case expression
+   has the given TYPE.
+   SPARSENESS is as determined by all_cases_count.
 
-  if (! int_fits_type_p (value2, index_type))
-    return 3;
+   The time needed is proportional to COUNT, unless
+   SPARSENESS is 2, in which case quadratic time is needed.  */
 
-  /* Fail if the range is empty.  */
-  if (tree_int_cst_lt (value2, value1))
-    return 4;
+void
+mark_seen_cases (type, cases_seen, count, sparseness)
+     tree type;
+     unsigned char *cases_seen;
+     long count;
+     int sparseness;
+{
+  long i;
 
-  /* If the bounds are equal, turn this into the one-value case.  */
-  if (tree_int_cst_equal (value1, value2))
-    return pushcase (value1, label, duplicate);
-
-  /* Find the elt in the chain before which to insert the new value,
-     to keep the chain sorted in increasing order.
-     But report an error if this element is a duplicate.  */
-  for (l = &case_stack->data.case_stmt.case_list;
-       /* Keep going past elements distinctly less than this range.  */
-       *l != 0 && tree_int_cst_lt ((*l)->high, value1);
-       l = &(*l)->right)
-    ;
-  if (*l)
+  tree next_node_to_try = NULL_TREE;
+  long next_node_offset = 0;
+
+  register struct case_node *n, *root = case_stack->data.case_stmt.case_list;
+  tree val = make_node (INTEGER_CST);
+  TREE_TYPE (val) = type;
+  if (! root)
+    ; /* Do nothing */
+  else if (sparseness == 2)
     {
-      /* Element we will insert before must be distinctly greater;
-        overlap means error.  */
-      if (! tree_int_cst_lt (value2, (*l)->low))
+      tree t;
+      HOST_WIDE_INT xlo;
+
+      /* This less efficient loop is only needed to handle
+        duplicate case values (multiple enum constants
+        with the same value).  */
+      TREE_TYPE (val) = TREE_TYPE (root->low);
+      for (t = TYPE_VALUES (type), xlo = 0;  t != NULL_TREE;
+          t = TREE_CHAIN (t), xlo++)
        {
-         *duplicate = (*l)->code_label;
-         return 2;
+         TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (TREE_VALUE (t));
+         TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (TREE_VALUE (t));
+         n = root;
+         do
+           {
+             /* Keep going past elements distinctly greater than VAL.  */
+             if (tree_int_cst_lt (val, n->low))
+               n = n->left;
+       
+             /* or distinctly less than VAL.  */
+             else if (tree_int_cst_lt (n->high, val))
+               n = n->right;
+       
+             else
+               {
+                 /* We have found a matching range.  */
+                 BITARRAY_SET (cases_seen, xlo);
+                 break;
+               }
+           }
+         while (n);
        }
     }
+  else
+    {
+      if (root->left)
+       case_stack->data.case_stmt.case_list = root = case_tree2list (root, 0);
+      for (n = root; n; n = n->right)
+       {
+         TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
+         TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
+         while ( ! tree_int_cst_lt (n->high, val))
+           {
+             /* Calculate (into xlo) the "offset" of the integer (val).
+                The element with lowest value has offset 0, the next smallest
+                element has offset 1, etc.  */
 
-  /* Add this label to the chain, and succeed.
-     Copy VALUE1, VALUE2 so they are on temporary rather than momentary
-     obstack and will thus survive till the end of the case statement.  */
-
-  n = (struct case_node *) oballoc (sizeof (struct case_node));
-  n->left = 0;
-  n->right = *l;
-  n->low = copy_node (value1);
-  n->high = copy_node (value2);
-  n->code_label = label;
-  *l = n;
-
-  expand_label (label);
-
-  case_stack->data.case_stmt.num_ranges++;
-
-  return 0;
+             HOST_WIDE_INT xlo, xhi;
+             tree t;
+             if (sparseness && TYPE_VALUES (type) != NULL_TREE)
+               {
+                 /* The TYPE_VALUES will be in increasing order, so
+                    starting searching where we last ended.  */
+                 t = next_node_to_try;
+                 xlo = next_node_offset;
+                 xhi = 0;
+                 for (;;)
+                   {
+                     if (t == NULL_TREE)
+                       {
+                         t = TYPE_VALUES (type);
+                         xlo = 0;
+                       }
+                     if (tree_int_cst_equal (val, TREE_VALUE (t)))
+                       {
+                         next_node_to_try = TREE_CHAIN (t);
+                         next_node_offset = xlo + 1;
+                         break;
+                       }
+                     xlo++;
+                     t = TREE_CHAIN (t);
+                     if (t == next_node_to_try)
+                       {
+                         xlo = -1;
+                         break;
+                       }
+                   }
+               }
+             else
+               {
+                 t = TYPE_MIN_VALUE (type);
+                 if (t)
+                   neg_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t),
+                               &xlo, &xhi);
+                 else
+                   xlo = xhi = 0;
+                 add_double (xlo, xhi,
+                             TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+                             &xlo, &xhi);
+               }
+             
+             if (xhi == 0 && xlo >= 0 && xlo < count)
+               BITARRAY_SET (cases_seen, xlo);
+             add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+                         1, 0,
+                         &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
+           }
+       }
+    }
 }
-\f
+
 /* Called when the index of a switch statement is an enumerated type
    and there is no default label.
 
@@ -3578,31 +4703,55 @@ check_for_full_enumeration_handling (type)
   register tree chain;
   int all_values = 1;
 
-  /* The time complexity of this loop is currently O(N * M), with
-     N being the number of members in the enumerated type, and
-     M being the number of case expressions in the switch. */
+  /* True iff the selector type is a numbered set mode. */
+  int sparseness = 0;
+
+  /* The number of possible selector values. */
+  HOST_WIDE_INT size;
 
-  for (chain = TYPE_VALUES (type);
-       chain;
-       chain = TREE_CHAIN (chain))
+  /* For each possible selector value. a one iff it has been matched
+     by a case value alternative. */
+  unsigned char *cases_seen;
+
+  /* The allocated size of cases_seen, in chars. */
+  long bytes_needed;
+  tree t;
+
+  if (output_bytecode)
     {
-      /* Find a match between enumeral and case expression, if possible.
-        Quit looking when we've gone too far (since case expressions
-        are kept sorted in ascending order).  Warn about enumerators not
-        handled in the switch statement case expression list. */
-
-      for (n = case_stack->data.case_stmt.case_list;
-          n && tree_int_cst_lt (n->high, TREE_VALUE (chain));
-          n = n->right)
-       ;
+      bc_check_for_full_enumeration_handling (type);
+      return;
+    }
+
+  if (! warn_switch)
+    return;
+
+  size = all_cases_count (type, &sparseness);
+  bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
+
+  if (size > 0 && size < 600000
+      /* We deliberately use malloc here - not xmalloc. */
+      && (cases_seen = (unsigned char *) malloc (bytes_needed)) != NULL)
+    {
+      long i;
+      tree v = TYPE_VALUES (type);
+      bzero (cases_seen, bytes_needed);
+
+      /* 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. */
+
+      mark_seen_cases (type, cases_seen, size, sparseness);
 
-      if (!n || tree_int_cst_lt (TREE_VALUE (chain), n->low))
+      for (i = 0;  v != NULL_TREE && i < size; i++, v = TREE_CHAIN (v))
        {
-         if (warn_switch)
+         if (BITARRAY_TEST(cases_seen, i) == 0)
            warning ("enumeration value `%s' not handled in switch",
-                    IDENTIFIER_POINTER (TREE_PURPOSE (chain)));
-         all_values = 0;
+                    IDENTIFIER_POINTER (TREE_PURPOSE (v)));
        }
+
+      free (cases_seen);
     }
 
   /* Now we go the other way around; we warn if there are case
@@ -3610,6 +4759,10 @@ check_for_full_enumeration_handling (type)
      occur since C and C++ don't enforce type-checking of
      assignments to enumeration variables. */
 
+  if (case_stack->data.case_stmt.case_list
+      && case_stack->data.case_stmt.case_list->left)
+    case_stack->data.case_stmt.case_list
+      = case_tree2list (case_stack->data.case_stmt.case_list, 0);
   if (warn_switch)
     for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
       {
@@ -3657,7 +4810,7 @@ check_for_full_enumeration_handling (type)
 #if 0
   /* ??? This optimization is disabled because it causes valid programs to
      fail.  ANSI C does not guarantee that an expression with enum type
-     will have a value that is the same as one of the enumation literals.  */
+     will have a value that is the same as one of the enumeration literals.  */
 
   /* If all values were found as case labels, make one of them the default
      label.  Thus, this switch will never fall through.  We arbitrarily pick
@@ -3676,6 +4829,47 @@ check_for_full_enumeration_handling (type)
     }
 #endif /* 0 */
 }
+
+
+/* Check that all enumeration literals are covered by the case
+   expressions of a switch.  Also warn if there are any cases
+   that are not elements of the enumerated type.  */
+
+static void
+bc_check_for_full_enumeration_handling (type)
+     tree type;
+{
+  struct nesting *thiscase = case_stack;
+  struct case_node *c;
+  tree e;
+
+  /* Check for enums not handled.  */
+  for (e = TYPE_VALUES (type); e; e = TREE_CHAIN (e))
+    {
+      for (c = thiscase->data.case_stmt.case_list->left;
+          c && tree_int_cst_lt (c->high, TREE_VALUE (e));
+          c = c->left)
+       ;
+      if (! (c && tree_int_cst_equal (c->low, TREE_VALUE (e))))
+       warning ("enumerated value `%s' not handled in switch",
+                IDENTIFIER_POINTER (TREE_PURPOSE (e)));
+    }
+
+  /* Check for cases not in the enumeration.  */
+  for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
+    {
+      for (e = TYPE_VALUES (type);
+          e && !tree_int_cst_equal (c->low, TREE_VALUE (e));
+          e = TREE_CHAIN (e))
+       ;
+      if (! e)
+       warning ("case value `%d' not in enumerated type `%s'",
+                TREE_INT_CST_LOW (c->low),
+                IDENTIFIER_POINTER (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
+                                    ? TYPE_NAME (type)
+                                    : DECL_NAME (TYPE_NAME (type))));
+    }
+}
 \f
 /* Terminate a case (Pascal) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
@@ -3690,19 +4884,30 @@ expand_end_case (orig_index)
   register struct case_node *n;
   int count;
   rtx index;
-  rtx table_label = gen_label_rtx ();
+  rtx table_label;
   int ncases;
   rtx *labelvec;
   register int i;
   rtx before_case;
   register struct nesting *thiscase = case_stack;
-  tree index_expr = thiscase->data.case_stmt.index_expr;
-  int unsignedp = TREE_UNSIGNED (TREE_TYPE (index_expr));
+  tree index_expr, index_type;
+  int unsignedp;
+
+  if (output_bytecode)
+    {
+      bc_expand_end_case (orig_index);
+      return;
+    }
+
+  table_label = gen_label_rtx ();
+  index_expr = thiscase->data.case_stmt.index_expr;
+  index_type = TREE_TYPE (index_expr);
+  unsignedp = TREE_UNSIGNED (index_type);
 
   do_pending_stack_adjust ();
 
   /* An ERROR_MARK occurs for various reasons including invalid data type.  */
-  if (TREE_TYPE (index_expr) != error_mark_node)
+  if (index_type != error_mark_node)
     {
       /* If switch expression was an enumerated type, check that all
         enumeration literals are covered by the cases.
@@ -3741,6 +4946,11 @@ expand_end_case (orig_index)
 
       before_case = get_last_insn ();
 
+      if (thiscase->data.case_stmt.case_list
+         && thiscase->data.case_stmt.case_list->left)
+       thiscase->data.case_stmt.case_list
+         = case_tree2list(thiscase->data.case_stmt.case_list, 0);
+
       /* Simplify the case-list before we count it.  */
       group_case_nodes (thiscase->data.case_stmt.case_list);
 
@@ -3756,8 +4966,8 @@ expand_end_case (orig_index)
          if (TREE_CODE (n->high) != INTEGER_CST)
            abort ();
 
-         n->low = convert (TREE_TYPE (index_expr), n->low);
-         n->high = convert (TREE_TYPE (index_expr), n->high);
+         n->low = convert (index_type, n->low);
+         n->high = convert (index_type, n->high);
 
          /* Count the elements and track the largest and smallest
             of them (treating them as signed even if they are not).  */
@@ -3782,10 +4992,9 @@ expand_end_case (orig_index)
 
       /* Compute span of values.  */
       if (count != 0)
-       range = fold (build (MINUS_EXPR, TREE_TYPE (index_expr),
-                            maxval, minval));
+       range = fold (build (MINUS_EXPR, index_type, maxval, minval));
 
-      if (count == 0 || TREE_CODE (TREE_TYPE (index_expr)) == ERROR_MARK)
+      if (count == 0)
        {
          expand_expr (index_expr, const0_rtx, VOIDmode, 0);
          emit_queue ();
@@ -3812,6 +5021,9 @@ expand_end_case (orig_index)
               || count < CASE_VALUES_THRESHOLD
               || ((unsigned HOST_WIDE_INT) (TREE_INT_CST_LOW (range))
                   > 10 * count)
+#ifndef ASM_OUTPUT_ADDR_DIFF_ELT
+              || flag_pic
+#endif
               || TREE_CODE (index_expr) == INTEGER_CST
               /* These will reduce to a constant.  */
               || (TREE_CODE (index_expr) == CALL_EXPR
@@ -3858,8 +5070,8 @@ expand_end_case (orig_index)
                {
                  index_expr
                    = build_int_2 (INTVAL (index),
-                                  !unsignedp && INTVAL (index) >= 0 ? 0 : -1);
-                 index_expr = convert (TREE_TYPE (index_expr), index_expr);
+                                  unsignedp || INTVAL (index) >= 0 ? 0 : -1);
+                 index_expr = convert (index_type, index_expr);
                }
 
              /* For constant index expressions we need only
@@ -3867,14 +5079,11 @@ expand_end_case (orig_index)
                 target code.  The job of removing any unreachable
                 code is left to the optimisation phase if the
                 "-O" option is specified.  */
-             for (n = thiscase->data.case_stmt.case_list;
-                  n;
-                  n = n->right)
-               {
-                 if (! tree_int_cst_lt (index_expr, n->low)
-                     && ! tree_int_cst_lt (n->high, index_expr))
-                   break;
-               }
+             for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
+               if (! tree_int_cst_lt (index_expr, n->low)
+                   && ! tree_int_cst_lt (n->high, index_expr))
+                 break;
+
              if (n)
                emit_jump (label_rtx (n->code_label));
              else
@@ -3902,7 +5111,7 @@ expand_end_case (orig_index)
              balance_case_nodes (&thiscase->data.case_stmt.case_list, 
                                  NULL_PTR);
              emit_case_nodes (index, thiscase->data.case_stmt.case_list,
-                              default_label, TREE_TYPE (index_expr));
+                              default_label, index_type);
              emit_jump_if_reachable (default_label);
            }
        }
@@ -3914,16 +5123,18 @@ expand_end_case (orig_index)
            {
              enum machine_mode index_mode = SImode;
              int index_bits = GET_MODE_BITSIZE (index_mode);
+             rtx op1, op2;
+             enum machine_mode op_mode;
 
              /* Convert the index to SImode.  */
-             if (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (index_expr)))
+             if (GET_MODE_BITSIZE (TYPE_MODE (index_type))
                  > GET_MODE_BITSIZE (index_mode))
                {
-                 enum machine_mode omode = TYPE_MODE (TREE_TYPE (index_expr));
+                 enum machine_mode omode = TYPE_MODE (index_type);
                  rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
 
                  /* We must handle the endpoints in the original mode.  */
-                 index_expr = build (MINUS_EXPR, TREE_TYPE (index_expr),
+                 index_expr = build (MINUS_EXPR, index_type,
                                      index_expr, minval);
                  minval = integer_zero_node;
                  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
@@ -3934,19 +5145,39 @@ expand_end_case (orig_index)
                }
              else
                {
-                 if (TYPE_MODE (TREE_TYPE (index_expr)) != index_mode)
-                   index_expr = convert (type_for_size (index_bits, 0),
-                                         index_expr);
+                 if (TYPE_MODE (index_type) != index_mode)
+                   {
+                     index_expr = convert (type_for_size (index_bits, 0),
+                                           index_expr);
+                     index_type = TREE_TYPE (index_expr);
+                   }
+
                  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
                }
              emit_queue ();
              index = protect_from_queue (index, 0);
              do_pending_stack_adjust ();
 
-             emit_jump_insn (gen_casesi (index, expand_expr (minval, NULL_RTX,
-                                                             VOIDmode, 0),
-                                         expand_expr (range, NULL_RTX,
-                                                      VOIDmode, 0),
+             op_mode = insn_operand_mode[(int)CODE_FOR_casesi][0];
+             if (! (*insn_operand_predicate[(int)CODE_FOR_casesi][0])
+                 (index, op_mode))
+               index = copy_to_mode_reg (op_mode, index);
+
+             op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+
+             op_mode = insn_operand_mode[(int)CODE_FOR_casesi][1];
+             if (! (*insn_operand_predicate[(int)CODE_FOR_casesi][1])
+                 (op1, op_mode))
+               op1 = copy_to_mode_reg (op_mode, op1);
+
+             op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+             op_mode = insn_operand_mode[(int)CODE_FOR_casesi][2];
+             if (! (*insn_operand_predicate[(int)CODE_FOR_casesi][2])
+                 (op2, op_mode))
+               op2 = copy_to_mode_reg (op_mode, op2);
+
+             emit_jump_insn (gen_casesi (index, op1, op2,
                                          table_label, default_label));
              win = 1;
            }
@@ -3955,15 +5186,15 @@ expand_end_case (orig_index)
          if (! win && HAVE_tablejump)
            {
              index_expr = convert (thiscase->data.case_stmt.nominal_type,
-                                   fold (build (MINUS_EXPR,
-                                                TREE_TYPE (index_expr),
+                                   fold (build (MINUS_EXPR, index_type,
                                                 index_expr, minval)));
+             index_type = TREE_TYPE (index_expr);
              index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
              emit_queue ();
              index = protect_from_queue (index, 0);
              do_pending_stack_adjust ();
 
-             do_tablejump (index, TYPE_MODE (TREE_TYPE (index_expr)),
+             do_tablejump (index, TYPE_MODE (index_type),
                            expand_expr (range, NULL_RTX, VOIDmode, 0),
                            table_label, default_label);
              win = 1;
@@ -3976,7 +5207,7 @@ expand_end_case (orig_index)
 
          ncases = TREE_INT_CST_LOW (range) + 1;
          labelvec = (rtx *) alloca (ncases * sizeof (rtx));
-         bzero (labelvec, ncases * sizeof (rtx));
+         bzero ((char *) labelvec, ncases * sizeof (rtx));
 
          for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
            {
@@ -4030,6 +5261,7 @@ expand_end_case (orig_index)
       reorder_insns (before_case, get_last_insn (),
                     thiscase->data.case_stmt.start);
     }
+
   if (thiscase->exit_label)
     emit_label (thiscase->exit_label);
 
@@ -4038,6 +5270,133 @@ expand_end_case (orig_index)
   free_temp_slots ();
 }
 
+/* Convert the tree NODE into a list linked by the right field, with the left
+   field zeroed.  RIGHT is used for recursion; it is a list to be placed
+   rightmost in the resulting list.  */
+
+static struct case_node *
+case_tree2list (node, right)
+     struct case_node *node, *right;
+{
+  struct case_node *left;
+
+  if (node->right)
+    right = case_tree2list (node->right, right);
+
+  node->right = right;
+  if (left = node->left)
+    {
+      node->left = 0;
+      return case_tree2list (left, node);
+    }
+
+  return node;
+}
+
+/* Terminate a case statement.  EXPR is the original index
+   expression.  */
+
+static void
+bc_expand_end_case (expr)
+     tree expr;
+{
+  struct nesting *thiscase = case_stack;
+  enum bytecode_opcode opcode;
+  struct bc_label *jump_label;
+  struct case_node *c;
+
+  bc_emit_bytecode (jump);
+  bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->exit_label));
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+
+  /* Now that the size of the jump table is known, emit the actual
+     indexed jump instruction.  */
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscase->data.case_stmt.skip_label));
+
+  opcode = TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode
+    ? TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseSU : caseSI
+      : TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseDU : caseDI;
+
+  bc_emit_bytecode (opcode);
+
+  /* Now emit the case instructions literal arguments, in order.
+     In addition to the value on the stack, it uses:
+     1.  The address of the jump table.
+     2.  The size of the jump table.
+     3.  The default label.  */
+
+  jump_label = bc_get_bytecode_label ();
+  bc_emit_bytecode_labelref (jump_label);
+  bc_emit_bytecode_const ((char *) &thiscase->data.case_stmt.num_ranges,
+                         sizeof thiscase->data.case_stmt.num_ranges);
+
+  if (thiscase->data.case_stmt.default_label)
+    bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (DECL_RTL (thiscase->data.case_stmt.default_label)));
+  else
+    bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->exit_label));
+
+  /* Output the jump table.  */
+
+  bc_align_bytecode (3 /* PTR_ALIGN */);
+  bc_emit_bytecode_labeldef (jump_label);
+
+  if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode)
+    for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
+      {
+       opcode = TREE_INT_CST_LOW (c->low);
+       bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
+
+       opcode = TREE_INT_CST_LOW (c->high);
+       bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
+
+       bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (DECL_RTL (c->code_label)));
+      }
+  else
+    if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == DImode)
+      for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
+       {
+         bc_emit_bytecode_DI_const (c->low);
+         bc_emit_bytecode_DI_const (c->high);
+
+         bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (DECL_RTL (c->code_label)));
+       }
+    else
+      /* Bad mode */
+      abort ();
+
+    
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscase->exit_label));
+
+  /* Possibly issue enumeration warnings.  */
+
+  if (!thiscase->data.case_stmt.default_label
+      && TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE
+      && TREE_CODE (expr) != INTEGER_CST
+      && warn_switch)
+    check_for_full_enumeration_handling (TREE_TYPE (expr));
+
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+
+  POPSTACK (case_stack);
+}
+
+
+/* Return unique bytecode ID. */
+
+int 
+bc_new_uid ()
+{
+  static int bc_uid = 0;
+
+  return (++bc_uid);
+}
+
 /* Generate code to jump to LABEL if OP1 and OP2 are equal.  */
 
 static void
@@ -4099,7 +5458,7 @@ estimate_case_costs (node)
   if (cost_table == NULL)
     {
       cost_table = ((short *) xmalloc (129 * sizeof (short))) + 1;
-      bzero (cost_table - 1, 129 * sizeof (short));
+      bzero ((char *) (cost_table - 1), 129 * sizeof (short));
 
       for (i = 0; i < 128; i++)
        {
@@ -4735,10 +6094,6 @@ find_loop_tree_blocks ()
 {
   tree block = DECL_INITIAL (current_function_decl);
 
-  /* There first block is for the function body, and does not have
-     corresponding block notes.  Don't include it in the block vector.  */
-  block = BLOCK_SUBBLOCKS (block);
-
   block_vector = identify_blocks (block, get_insns ());
 }