OSDN Git Service

Copy files needed for other files at the very end.
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 1c53164..e6caa9f 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, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -49,14 +49,18 @@ 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
 struct obstack stmt_obstack;
 
-extern int xmalloc ();
-extern void free ();
-
 /* Filename and line number of last line-number note,
    whether we actually emitted it or not.  */
 char *emit_filename;
@@ -73,6 +77,13 @@ int expr_stmts_for_value;
 static tree last_expr_type;
 static rtx last_expr_value;
 
+/* Each time we expand the end of a binding contour (in `expand_end_bindings')
+   and we emit a new NOTE_INSN_BLOCK_END note, we save a pointer to it here.
+   This is used by the `remember_end_note' function to record the endpoint
+   of each generated block in its associated BLOCK node.  */
+
+static rtx last_block_end_note;
+
 /* Number of binding contours started so far in this function.  */
 
 int block_start_count;
@@ -177,14 +188,28 @@ static void emit_jump_if_reachable ();
 
 static int warn_if_unused_value ();
 static void expand_goto_internal ();
+static void bc_expand_goto_internal ();
 static int expand_fixup ();
+static void bc_expand_fixup ();
 void fixup_gotos ();
+static void bc_fixup_gotos ();
 void free_temp_slots ();
 static void expand_cleanups ();
-static void fixup_cleanups ();
 static void expand_null_return_1 ();
 static int tail_recursion_args ();
 static void do_jump_if_equal ();
+int bc_expand_exit_loop_if_false ();
+void bc_expand_start_cond ();
+void bc_expand_end_cond ();
+void bc_expand_start_else ();
+void bc_expand_end_bindings ();
+void bc_expand_start_case ();
+void bc_check_for_full_enumeration_handling ();
+void bc_expand_end_case ();
+void bc_expand_decl ();
+
+extern rtx bc_allocate_local ();
+extern rtx bc_allocate_variable_array ();
 \f
 /* Stack of control and binding constructs we are currently inside.
 
@@ -247,7 +272,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
@@ -274,6 +300,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').  */
@@ -282,6 +310,10 @@ struct nesting
          /* The insn after which the case dispatch should finally
             be emitted.  Zero for a dummy.  */
          rtx start;
+         /* For bytecodes, the case table is in-lined right in the code.
+            A label is needed for skipping over this block. It is only
+            used when generating bytecodes. */
+         rtx skip_label;
          /* 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
@@ -329,6 +361,8 @@ struct nesting
 /* Chain of all pending binding contours.  */
 struct nesting *block_stack;
 
+/* If any new stacks are added here, add them to POPSTACKS too.  */
+
 /* Chain of all pending binding contours that restore stack levels
    or have cleanups.  */
 struct nesting *stack_block_stack;
@@ -357,17 +391,31 @@ int nesting_depth;
 #define ALLOC_NESTING() \
  (struct nesting *) obstack_alloc (&stmt_obstack, sizeof (struct nesting))
 
-/* Pop one of the sub-stacks, such as `loop_stack' or `cond_stack';
-   and pop off `nesting_stack' down to the same level.  */
+/* Pop the nesting stack element by element until we pop off
+   the element which is at the top of STACK.
+   Update all the other stacks, popping off elements from them
+   as we pop them from nesting_stack.  */
 
 #define POPSTACK(STACK)                                        \
-do { int initial_depth = nesting_stack->depth;         \
-     do { struct nesting *this = STACK;                        \
-         STACK = this->next;                           \
+do { struct nesting *target = STACK;                   \
+     struct nesting *this;                             \
+     do { this = nesting_stack;                                \
+         if (loop_stack == this)                       \
+           loop_stack = loop_stack->next;              \
+         if (cond_stack == this)                       \
+           cond_stack = cond_stack->next;              \
+         if (block_stack == this)                      \
+           block_stack = block_stack->next;            \
+         if (stack_block_stack == this)                \
+           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;                    \
-         nesting_depth = this->depth;                  \
          obstack_free (&stmt_obstack, this); }         \
-     while (nesting_depth > initial_depth); } while (0)
+     while (this != target); } while (0)
 \f
 /* In some cases it is impossible to generate code for a forward goto
    until the label definition is seen.  This happens when it may be necessary
@@ -387,6 +435,8 @@ struct goto_fixup
   /* The LABEL_DECL that this jump is jumping to, or 0
      for break, continue or return.  */
   tree target;
+  /* The BLOCK for the place where this goto was found.  */
+  tree context;
   /* The CODE_LABEL rtx that this is jumping to.  */
   rtx target_rtl;
   /* Number of binding contours started in current function
@@ -404,6 +454,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;
@@ -493,11 +558,16 @@ 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
+             || prev_real_insn (last_insn) == 0))
+       emit_insn (gen_nop ());
+    }
 }
 \f
 /* Return the rtx-label that corresponds to a LABEL_DECL,
@@ -534,10 +604,17 @@ void
 expand_computed_goto (exp)
      tree exp;
 {
-  rtx x = expand_expr (exp, 0, VOIDmode, 0);
-  emit_queue ();
-  emit_indirect_jump (x);
-  emit_barrier ();
+  if (output_bytecode)
+    {
+      bc_expand_expr (exp);
+      bc_emit_instruction (jumpP);
+    }
+  else
+    {
+      rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+      emit_queue ();
+      emit_indirect_jump (x);
+    }
 }
 \f
 /* Handle goto statements and the labels that they can go to.  */
@@ -559,6 +636,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))
@@ -586,11 +672,9 @@ declare_nonlocal_label (label)
     {
       nonlocal_goto_handler_slot
        = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-      nonlocal_goto_stack_level
-       = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-      emit_insn_before (gen_move_insn (nonlocal_goto_stack_level,
-                                      stack_pointer_rtx),
-                       tail_recursion_reentry);
+      emit_stack_save (SAVE_NONLOCAL,
+                      &nonlocal_goto_stack_level,
+                      PREV_INSN (tail_recursion_reentry));
     }
 }
 
@@ -602,47 +686,80 @@ 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);
+      rtx label_ref = gen_rtx (LABEL_REF, Pmode, label_rtx (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
+        case the virtual stack vars register gets instantiated differently
+        in the parent than in the child.  */
+
 #if HAVE_nonlocal_goto
       if (HAVE_nonlocal_goto)
        emit_insn (gen_nonlocal_goto (lookup_static_chain (label),
-                                     p->nonlocal_goto_handler_slot,
-                                     p->nonlocal_goto_stack_level,
-                                     gen_rtx (LABEL_REF, Pmode,
-                                              label_rtx (label))));
+                                     copy_rtx (p->nonlocal_goto_handler_slot),
+                                     copy_rtx (p->nonlocal_goto_stack_level),
+                                     label_ref));
       else
 #endif
        {
+         rtx addr;
+
          /* Restore frame pointer for containing function.
             This sets the actual hard register used for the frame pointer
             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
+            stack vars.  So replace virtual_stack_vars_rtx in all
+            addresses we use with stack_pointer_rtx.  */
+
          /* Get addr of containing function's current nonlocal goto handler,
             which will do any cleanups and then jump to the label.  */
-         temp = copy_to_reg (p->nonlocal_goto_handler_slot);
+         addr = copy_rtx (p->nonlocal_goto_handler_slot);
+         temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx,
+                                          hard_frame_pointer_rtx));
+         
          /* Restore the stack pointer.  Note this uses fp just restored.  */
-         emit_move_insn (stack_pointer_rtx, p->nonlocal_goto_stack_level);
+         addr = p->nonlocal_goto_stack_level;
+         if (addr)
+           addr = replace_rtx (copy_rtx (addr),
+                               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,
-                         gen_rtx (LABEL_REF, Pmode, label_rtx (label)));
-         /* USE of frame_pointer_rtx added for consistency; not clear if
+         emit_move_insn (static_chain_rtx, label_ref);
+         /* 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);
        }
      }
   else
-    expand_goto_internal (label, label_rtx (label), 0);
+    expand_goto_internal (label, label_rtx (label), NULL_RTX);
 }
 
 /* Generate RTL code for a `goto' statement with target label BODY.
@@ -659,6 +776,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 ();
 
@@ -680,7 +807,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, 0);
+             expand_cleanups (block->data.block.cleanups, NULL_TREE);
              do_pending_stack_adjust ();
            }
        }
@@ -691,7 +818,7 @@ expand_goto_internal (body, label, last_insn)
             the stack pointer.  This one should be deleted as dead by flow. */
          clear_pending_stack_adjust ();
          do_pending_stack_adjust ();
-         emit_move_insn (stack_pointer_rtx, stack_level);
+         emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
        }
 
       if (body != 0 && DECL_TOO_LATE (body))
@@ -711,6 +838,77 @@ 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);
+             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.
@@ -718,8 +916,11 @@ expand_goto_internal (body, label, last_insn)
    If LAST_INSN is nonzero, we pretend that the jump appears
    after insn LAST_INSN instead of at the current point in the insn stream.
 
-   The fixup will be used later to insert insns at this point
-   to restore the stack level as appropriate for the target label.
+   The fixup will be used later to insert insns just before the goto.
+   Those insns will restore the stack level as appropriate for the
+   target label, and will (in the case of C++) also invoke any object
+   destructors which have to be invoked when we exit the scopes which
+   are exited by the goto.
 
    Value is nonzero if a fixup is made.  */
 
@@ -796,9 +997,30 @@ expand_fixup (tree_label, rtl_label, last_insn)
         someone does it!  */
       if (last_insn == 0)
        do_pending_stack_adjust ();
-      fixup->before_jump = last_insn ? last_insn : get_last_insn ();
       fixup->target = tree_label;
       fixup->target_rtl = rtl_label;
+
+      /* Create a BLOCK node and a corresponding matched set of
+        NOTE_INSN_BEGIN_BLOCK and NOTE_INSN_END_BLOCK notes at
+        this point.  The notes will encapsulate any and all fixup
+        code which we might later insert at this point in the insn
+        stream.  Also, the BLOCK node will be the parent (i.e. the
+        `SUPERBLOCK') of any other BLOCK nodes which we might create
+        later on when we are expanding the fixup code.  */
+
+      {
+        register rtx original_before_jump
+          = last_insn ? last_insn : get_last_insn ();
+
+        start_sequence ();
+        pushlevel (0);
+        fixup->before_jump = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+        last_block_end_note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
+        fixup->context = poplevel (1, 0, 0);  /* Create the BLOCK node now! */
+        end_sequence ();
+        emit_insns_after (fixup->before_jump, original_before_jump);
+      }
+
       fixup->block_start_count = block_start_count;
       fixup->stack_level = 0;
       fixup->cleanup_list_list
@@ -808,7 +1030,7 @@ expand_fixup (tree_label, rtl_label, last_insn)
 #endif
             )
            || block->data.block.cleanups)
-          ? tree_cons (0, block->data.block.cleanups,
+          ? tree_cons (NULL_TREE, block->data.block.cleanups,
                        block->data.block.outer_cleanups)
           : 0);
       fixup->next = goto_fixup_chain;
@@ -818,6 +1040,37 @@ 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
+}
+
+
 /* 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.
@@ -841,6 +1094,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
 {
   register struct goto_fixup *f, *prev;
 
+  if (output_bytecode)
+    {
+      bc_fixup_gotos (thisblock, stack_level, 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
@@ -859,6 +1118,8 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
         If so, we can finalize it.  */
       else if (PREV_INSN (f->target_rtl) != 0)
        {
+         register rtx cleanup_insns;
+
          /* Get the first non-label after the label
             this goto jumps to.  If that's before this scope begins,
             we don't have a jump into the scope.  */
@@ -879,15 +1140,28 @@ 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)
-             && ! TREE_REGDECL (f->target))
+             && ! DECL_REGISTER (f->target))
            {
              error_with_decl (f->target,
                               "label `%s' used before containing binding contour");
              /* Prevent multiple errors for one label.  */
-             TREE_REGDECL (f->target) = 1;
+             DECL_REGISTER (f->target) = 1;
            }
 
-         /* Execute cleanups for blocks this jump exits.  */
+         /* We will expand the cleanups into a sequence of their own and
+            then later on we will attach this new sequence to the insn
+            stream just ahead of the actual jump insn.  */
+
+         start_sequence ();
+
+         /* Temporarily restore the lexical context where we will
+            logically be inserting the fixup code.  We do this for the
+            sake of getting the debugging information right.  */
+
+         pushlevel (0);
+         set_block (f->context);
+
+         /* Expand the cleanups for blocks this jump exits.  */
          if (f->cleanup_list_list)
            {
              tree lists;
@@ -896,14 +1170,35 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
                   Do their cleanups.  */
                if (TREE_ADDRESSABLE (lists)
                    && TREE_VALUE (lists) != 0)
-                 fixup_cleanups (TREE_VALUE (lists), &f->before_jump);
+                 {
+                   expand_cleanups (TREE_VALUE (lists), 0);
+                   /* Pop any pushes done in the cleanups,
+                      in case function is about to return.  */
+                   do_pending_stack_adjust ();
+                 }
            }
 
          /* Restore stack level for the biggest contour that this
             jump jumps out of.  */
          if (f->stack_level)
-           emit_insn_after (gen_move_insn (stack_pointer_rtx, f->stack_level),
-                            f->before_jump);
+           emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump);
+
+         /* Finish up the sequence containing the insns which implement the
+            necessary cleanups, and then attach that whole sequence to the
+            insn stream just ahead of the actual jump insn.  Attaching it
+            at that point insures that any cleanups which are in fact
+            implicit C++ object destructions (which must be executed upon
+            leaving the block) appear (to the debugger) to be taking place
+            in an area of the generated code where the object(s) being
+            destructed are still "in scope".  */
+
+         cleanup_insns = get_insns ();
+         poplevel (1, 0, 0);
+
+         end_sequence ();
+         emit_insns_after (cleanup_insns, f->before_jump);
+
+
          f->before_jump = 0;
        }
     }
@@ -937,6 +1232,72 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
          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,
@@ -946,6 +1307,12 @@ void
 expand_asm (body)
      tree body;
 {
+  if (output_bytecode)
+    {
+      error ("`asm' is illegal when generating bytecode");
+      return;
+    }
+
   if (TREE_CODE (body) == ADDR_EXPR)
     body = TREE_OPERAND (body, 0);
 
@@ -980,7 +1347,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   rtx body;
   int ninputs = list_length (inputs);
   int noutputs = list_length (outputs);
-  int nclobbers = list_length (clobbers);
+  int nclobbers;
   tree tail;
   register int i;
   /* Vector of RTX's of evaluated output operands.  */
@@ -988,6 +1355,23 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   /* The insn we have emitted.  */
   rtx insn;
 
+  if (output_bytecode)
+    {
+      error ("`asm' is illegal when generating bytecode");
+      return;
+    }
+
+  /* Count the number of meaningful clobbered registers, ignoring what
+     we would ignore later.  */
+  nclobbers = 0;
+  for (tail = clobbers; tail; tail = TREE_CHAIN (tail))
+    {
+      char *regname = TREE_STRING_POINTER (TREE_VALUE (tail));
+      i = decode_reg_name (regname);
+      if (i >= 0 || i == -4)
+       ++nclobbers;
+    }
+
   last_expr_type = 0;
 
   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
@@ -1034,9 +1418,17 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       if (TREE_CODE (val) != VAR_DECL
          && TREE_CODE (val) != PARM_DECL
          && TREE_CODE (val) != INDIRECT_REF)
-       TREE_VALUE (tail) = save_expr (TREE_VALUE (tail));
+       {
+         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] = expand_expr (TREE_VALUE (tail), 0, VOIDmode, 0);
+      output_rtx[i] = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
     }
 
   if (ninputs + noutputs > MAX_RECOG_OPERANDS)
@@ -1087,7 +1479,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          }
 
       XVECEXP (body, 3, i)      /* argvec */
-       = expand_expr (TREE_VALUE (tail), 0, VOIDmode, 0);
+       = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
       XVECEXP (body, 4, i)      /* constraints */
        = gen_rtx (ASM_INPUT, TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
                   TREE_STRING_POINTER (TREE_PURPOSE (tail)));
@@ -1148,22 +1540,31 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       /* Store (clobber REG) for each clobbered register specified.  */
 
-      for (tail = clobbers; tail; tail = TREE_CHAIN (tail), i++)
+      for (tail = clobbers; tail; tail = TREE_CHAIN (tail))
        {
          char *regname = TREE_STRING_POINTER (TREE_VALUE (tail));
          int j = decode_reg_name (regname);
 
          if (j < 0)
            {
-             if (j == -3)
+             if (j == -3)      /* `cc', which is not a register */
                continue;
 
+             if (j == -4)      /* `memory', don't cache memory across asm */
+               {
+                 XVECEXP (body, 0, i++)
+                   = gen_rtx (CLOBBER, VOIDmode,
+                              gen_rtx (MEM, QImode,
+                                       gen_rtx (SCRATCH, VOIDmode, 0)));
+                 continue;
+               }
+
              error ("unknown register name `%s' in `asm'", regname);
              return;
            }
 
          /* Use QImode since that's guaranteed to clobber just one reg.  */
-         XVECEXP (body, 0, i)
+         XVECEXP (body, 0, i++)
            = gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, QImode, j));
        }
 
@@ -1180,6 +1581,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.  */
@@ -1195,7 +1612,9 @@ expand_expr_stmt (exp)
     }
   last_expr_type = TREE_TYPE (exp);
   if (! flag_syntax_only)
-    last_expr_value = expand_expr (exp, expr_stmts_for_value ? 0 : const0_rtx,
+    last_expr_value = expand_expr (exp,
+                                  (expr_stmts_for_value
+                                   ? NULL_RTX : const0_rtx),
                                   VOIDmode, 0);
 
   /* If all we do is reference a volatile value in memory,
@@ -1203,11 +1622,23 @@ expand_expr_stmt (exp)
   if (last_expr_value != 0 && GET_CODE (last_expr_value) == MEM
       && TREE_THIS_VOLATILE (exp))
     {
-      if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
+      if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)
+       ;
+      else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
        copy_to_reg (last_expr_value);
       else
-       /* This case needs to be written.  */
-       abort ();
+       {
+         rtx lab = gen_label_rtx ();
+         
+         /* Compare the value with itself to reference it.  */
+         emit_cmp_insn (last_expr_value, last_expr_value, EQ,
+                        expand_expr (TYPE_SIZE (last_expr_type),
+                                     NULL_RTX, VOIDmode, 0),
+                        BLKmode, 0,
+                        TYPE_ALIGN (last_expr_type) / BITS_PER_UNIT);
+         emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (lab));
+         emit_label (lab);
+       }
     }
 
   /* If this expression is part of a ({...}) and is in memory, we may have
@@ -1244,8 +1675,6 @@ warn_if_unused_value (exp)
     case CALL_EXPR:
     case METHOD_CALL_EXPR:
     case RTL_EXPR:
-    case WRAPPER_EXPR:
-    case ANTI_WRAPPER_EXPR:
     case WITH_CLEANUP_EXPR:
     case EXIT_EXPR:
       /* We don't warn about COND_EXPR because it may be a useful
@@ -1265,6 +1694,9 @@ warn_if_unused_value (exp)
     case COMPOUND_EXPR:
       if (warn_if_unused_value (TREE_OPERAND (exp, 0)))
        return 1;
+      /* Let people do `(foo (), 0)' without a warning.  */
+      if (TREE_CONSTANT (TREE_OPERAND (exp, 1)))
+       return 0;
       return warn_if_unused_value (TREE_OPERAND (exp, 1));
 
     case NOP_EXPR:
@@ -1288,6 +1720,11 @@ warn_if_unused_value (exp)
        return 0;
 
     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;
       warning_with_file_and_line (emit_filename, emit_lineno,
                                  "value computed is not used");
       return 1;
@@ -1309,10 +1746,17 @@ 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 ();
   NO_DEFER_POP;
@@ -1336,6 +1780,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)
@@ -1391,6 +1867,7 @@ expand_end_stmt_expr (t)
        }
 
     }
+*/
 
 /* Return nonzero iff in a try block at level LEVEL.  */
 
@@ -1489,7 +1966,7 @@ expand_start_try (try_clause, exitflag, escapeflag)
   except_stack = thishandler;
   nesting_stack = thishandler;
 
-  do_jump (try_clause, thishandler->data.except_stmt.except_label, NULL);
+  do_jump (try_clause, thishandler->data.except_stmt.except_label, NULL_RTX);
 }
 
 /* End of a TRY block.  Nothing to do for now.  */
@@ -1498,7 +1975,8 @@ void
 expand_end_try ()
 {
   except_stack->data.except_stmt.after_label = gen_label_rtx ();
-  expand_goto_internal (NULL, except_stack->data.except_stmt.after_label, 0);
+  expand_goto_internal (NULL_TREE, except_stack->data.except_stmt.after_label,
+                       NULL_RTX);
 }
 
 /* Start an `except' nesting contour.
@@ -1561,7 +2039,8 @@ expand_escape_except ()
   for (n = except_stack; n; n = n->next)
     if (n->data.except_stmt.escape_label != 0)
       {
-       expand_goto_internal (0, n->data.except_stmt.escape_label, 0);
+       expand_goto_internal (NULL_TREE,
+                             n->data.except_stmt.escape_label, NULL_RTX);
        return 1;
       }
 
@@ -1664,7 +2143,8 @@ expand_end_catch ()
 {
   if (except_stack == 0 || except_stack->data.except_stmt.after_label == 0)
     return 0;
-  expand_goto_internal (0, except_stack->data.except_stmt.after_label, 0);
+  expand_goto_internal (NULL_TREE, except_stack->data.except_stmt.after_label,
+                       NULL_RTX);
   return 1;
 }
 \f
@@ -1695,7 +2175,10 @@ expand_start_cond (cond, exitflag)
   cond_stack = thiscond;
   nesting_stack = thiscond;
 
-  do_jump (cond, thiscond->data.cond.next_label, NULL);
+  if (output_bytecode)
+    bc_expand_start_cond (cond, exitflag);
+  else
+    do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
 }
 
 /* Generate RTL between then-clause and the elseif-clause
@@ -1710,7 +2193,7 @@ expand_start_elseif (cond)
   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);
+  do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
 }
 
 /* Generate RTL between the then-clause and the else-clause
@@ -1721,6 +2204,13 @@ expand_start_else ()
 {
   if (cond_stack->data.cond.endif_label == 0)
     cond_stack->data.cond.endif_label = gen_label_rtx ();
+
+  if (output_bytecode)
+    {
+      bc_expand_start_else ();
+      return;
+    }
+
   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. */
@@ -1734,15 +2224,71 @@ expand_end_cond ()
 {
   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);
+  if (output_bytecode)
+    bc_expand_end_cond ();
+  else
+    {
+      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 (cond_stack);
   last_expr_type = 0;
 }
+
+
+/* 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
+bc_expand_start_cond (cond, exitflag)
+     tree cond;
+     int exitflag;
+{
+  struct nesting *thiscond = cond_stack;
+
+  thiscond->data.case_stmt.nominal_type = cond;
+  bc_expand_expr (cond);
+  bc_emit_bytecode (xjumpifnot);
+  bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscond->exit_label));
+
+#ifdef DEBUG_PRINT_CODE
+  fputc ('\n', stderr);
+#endif
+}
+
+/* Generate the label for the end of an if with
+   no else- clause.  */
+void
+bc_expand_end_cond ()
+{
+  struct nesting *thiscond = cond_stack;
+
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->exit_label));
+}
+
+/* Generate code for the start of the else- clause of
+   an if-then-else.  */
+void
+bc_expand_start_else ()
+{
+  struct nesting *thiscond = cond_stack;
+
+  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));
+
+#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
    loop should be exited by `exit_something'.  This is a loop for which
@@ -1769,9 +2315,15 @@ expand_start_loop (exit_flag)
   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 (0, NOTE_INSN_LOOP_BEG);
+  emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
   emit_label (thisloop->data.loop.start_label);
 
   return thisloop;
@@ -1797,21 +2349,54 @@ 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 (0, NOTE_INSN_LOOP_CONT);
+  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)
@@ -1902,7 +2487,7 @@ expand_end_loop ()
     }
 
   emit_jump (start_label);
-  emit_note (0, NOTE_INSN_LOOP_END);
+  emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
   emit_label (loop_stack->data.loop.end_label);
 
   POPSTACK (loop_stack);
@@ -1924,7 +2509,8 @@ expand_continue_loop (whichloop)
     whichloop = loop_stack;
   if (whichloop == 0)
     return 0;
-  expand_goto_internal (0, whichloop->data.loop.continue_label, 0);
+  expand_goto_internal (NULL_TREE, whichloop->data.loop.continue_label,
+                       NULL_RTX);
   return 1;
 }
 
@@ -1940,7 +2526,7 @@ expand_exit_loop (whichloop)
     whichloop = loop_stack;
   if (whichloop == 0)
     return 0;
-  expand_goto_internal (0, whichloop->data.loop.end_label, 0);
+  expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label, NULL_RTX);
   return 1;
 }
 
@@ -1958,10 +2544,19 @@ expand_exit_loop_if_false (whichloop, cond)
     whichloop = loop_stack;
   if (whichloop == 0)
     return 0;
-  do_jump (cond, whichloop->data.loop.end_label, NULL);
-  return 1;
-}
-
+  if (output_bytecode)
+    {
+      bc_expand_expr (cond);
+      bc_expand_goto_internal (xjumpifnot,
+                              BYTECODE_BC_LABEL (whichloop->exit_label),
+                              NULL_RTX);
+    }
+  else
+    do_jump (cond, whichloop->data.loop.end_label, NULL_RTX);
+
+  return 1;
+}
+
 /* Return non-zero if we should preserve sub-expressions as separate
    pseudos.  We never do so if we aren't optimizing.  We always do so
    if -fexpensive-optimizations.
@@ -2005,7 +2600,7 @@ expand_exit_something ()
   for (n = nesting_stack; n; n = n->all)
     if (n->exit_label != 0)
       {
-       expand_goto_internal (0, n->exit_label, 0);
+       expand_goto_internal (NULL_TREE, n->exit_label, NULL_RTX);
        return 1;
       }
 
@@ -2021,6 +2616,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)
@@ -2045,7 +2646,26 @@ expand_value_return (val)
      unless it's already there.  */
 
   if (return_reg != val)
-    emit_move_insn (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);
+       }
+
+      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
+       convert_move (return_reg, val, unsignedp);
+      else
+#endif
+       emit_move_insn (return_reg, val);
+    }
   if (GET_CODE (return_reg) == REG
       && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
     emit_insn (gen_rtx (USE, VOIDmode, return_reg));
@@ -2083,7 +2703,7 @@ expand_null_return_1 (last_insn, use_goto)
     {
       if (end_label == 0)
        end_label = return_label = gen_label_rtx ();
-      expand_goto_internal (0, end_label, last_insn);
+      expand_goto_internal (NULL_TREE, end_label, last_insn);
       return;
     }
 
@@ -2099,7 +2719,7 @@ expand_null_return_1 (last_insn, use_goto)
 #endif
 
   /* Otherwise jump to the epilogue.  */
-  expand_goto_internal (0, end_label, last_insn);
+  expand_goto_internal (NULL_TREE, end_label, last_insn);
 }
 \f
 /* Generate RTL to evaluate the expression RETVAL and return it
@@ -2124,10 +2744,20 @@ 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)
     {
-      expand_expr (retval, 0, VOIDmode, 0);
+      expand_expr (retval, NULL_RTX, VOIDmode, 0);
+      emit_queue ();
       expand_null_return ();
       return;
     }
@@ -2163,14 +2793,21 @@ expand_return (retval)
          || TREE_CODE (TREE_OPERAND (retval_rhs, 2)) == CALL_EXPR))
     {
       rtx label = gen_label_rtx ();
-      do_jump (TREE_OPERAND (retval_rhs, 0), label, 0);
-      expand_return (build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
-                           DECL_RESULT (current_function_decl),
-                           TREE_OPERAND (retval_rhs, 1)));
+      tree expr;
+
+      do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
+      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;
     }
 
@@ -2195,7 +2832,8 @@ expand_return (retval)
          emit_label_after (tail_recursion_label,
                            tail_recursion_reentry);
        }
-      expand_goto_internal (0, tail_recursion_label, last_insn);
+      emit_queue ();
+      expand_goto_internal (NULL_TREE, tail_recursion_label, last_insn);
       emit_barrier ();
       return;
     }
@@ -2206,11 +2844,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))
          {
@@ -2225,6 +2865,7 @@ expand_return (retval)
          case TRUTH_AND_EXPR:
          case TRUTH_OR_EXPR:
          case TRUTH_NOT_EXPR:
+         case TRUTH_XOR_EXPR:
            op0 = gen_label_rtx ();
            jumpifnot (retval_rhs, op0);
            expand_value_return (const1_rtx);
@@ -2241,7 +2882,7 @@ expand_return (retval)
       && GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)
     {
       /* Calculate the return value into a pseudo reg.  */
-      val = expand_expr (retval_rhs, 0, VOIDmode, 0);
+      val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
       emit_queue ();
       /* All temporaries have now been used.  */
       free_temp_slots ();
@@ -2252,7 +2893,7 @@ expand_return (retval)
     {
       /* No cleanups or no hard reg used;
         calculate value into hard return reg.  */
-      expand_expr (retval, 0, VOIDmode, 0);
+      expand_expr (retval, const0_rtx, VOIDmode, 0);
       emit_queue ();
       free_temp_slots ();
       expand_value_return (DECL_RTL (DECL_RESULT (current_function_decl)));
@@ -2307,7 +2948,7 @@ tail_recursion_args (actuals, formals)
   argvec = (rtx *) alloca (i * sizeof (rtx));
 
   for (a = actuals, i = 0; a; a = TREE_CHAIN (a), i++)
-    argvec[i] = expand_expr (TREE_VALUE (a), 0, VOIDmode, 0);
+    argvec[i] = expand_expr (TREE_VALUE (a), NULL_RTX, VOIDmode, 0);
 
   /* Find which actual values refer to current values of previous formals.
      Copy each of them now, before any formal is changed.  */
@@ -2328,7 +2969,7 @@ tail_recursion_args (actuals, formals)
   for (f = formals, a = actuals, i = 0; f;
        f = TREE_CHAIN (f), a = TREE_CHAIN (a), i++)
     {
-      if (DECL_MODE (f) == GET_MODE (argvec[i]))
+      if (GET_MODE (DECL_RTL (f)) == GET_MODE (argvec[i]))
        emit_move_insn (DECL_RTL (f), argvec[i]);
       else
        convert_move (DECL_RTL (f), argvec[i],
@@ -2350,8 +2991,10 @@ expand_start_bindings (exit_flag)
      int exit_flag;
 {
   struct nesting *thisblock = ALLOC_NESTING ();
+  rtx note;
 
-  rtx note = emit_note (0, NOTE_INSN_BLOCK_BEG);
+  if (!output_bytecode)
+    note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
 
   /* Make an entry on block_stack for the block we are entering.  */
 
@@ -2394,8 +3037,23 @@ 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
+   generated NOTE_INSN_BLOCK_END in the BLOCK_END_NOTE field of the given
+   BLOCK node.  */
+
+void
+remember_end_note (block)
+     register tree block;
+{
+  BLOCK_END_NOTE (block) = last_block_end_note;
+  last_block_end_note = NULL_RTX;
 }
 
 /* Generate RTL code to terminate a binding contour.
@@ -2416,19 +3074,18 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
   register struct nesting *thisblock = block_stack;
   register tree 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)
+      if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
+         && ! DECL_IN_SYSTEM_HEADER (decl))
        warning_with_decl (decl, "unused variable `%s'");
 
-  /* Mark the beginning and end of the scope if requested.  */
-
-  if (mark_ends)
-    emit_note (0, NOTE_INSN_BLOCK_END);
-  else
-    /* Get rid of the beginning-mark if we don't make an end-mark.  */
-    NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
-
   if (thisblock->exit_label)
     {
       do_pending_stack_adjust ();
@@ -2489,19 +3146,38 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
           decrementing fp by STARTING_FRAME_OFFSET.  */
        emit_move_insn (virtual_stack_vars_rtx, frame_pointer_rtx);
 
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
       if (fixed_regs[ARG_POINTER_REGNUM])
        {
-         /* Now restore our arg pointer from the address at which it was saved
-            in our stack frame.
-            If there hasn't be space allocated for it yet, make some now.  */
-         if (arg_pointer_save_area == 0)
-           arg_pointer_save_area
-             = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-         emit_move_insn (virtual_incoming_args_rtx,
-                         /* We need a pseudo here,
-                            or else instantiate_virtual_regs_1 complains.  */
-                         copy_to_reg (arg_pointer_save_area));
+#ifdef ELIMINABLE_REGS
+         /* If the argument pointer can be eliminated in favor of the
+            frame pointer, we don't need to restore it.  We assume here
+            that if such an elimination is present, it can always be used.
+            This is the case on all known machines; if we don't make this
+            assumption, we do unnecessary saving on many machines.  */
+         static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+         int i;
+
+         for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+           if (elim_regs[i].from == ARG_POINTER_REGNUM
+               && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+             break;
+
+         if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+           {
+             /* Now restore our arg pointer from the address at which it
+                was saved in our stack frame.
+                If there hasn't be space allocated for it yet, make
+                some now.  */
+             if (arg_pointer_save_area == 0)
+               arg_pointer_save_area
+                 = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+             emit_move_insn (virtual_incoming_args_rtx,
+                             /* We need a pseudo here, or else
+                                instantiate_virtual_regs_1 complains.  */
+                             copy_to_reg (arg_pointer_save_area));
+           }
        }
 #endif
 
@@ -2563,7 +3239,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       expr_stmts_for_value = 0;
 
       /* Do the cleanups.  */
-      expand_cleanups (thisblock->data.block.cleanups, 0);
+      expand_cleanups (thisblock->data.block.cleanups, NULL_TREE);
       do_pending_stack_adjust ();
 
       expr_stmts_for_value = old_expr_stmts_for_value;
@@ -2574,14 +3250,16 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
 
       if (thisblock->data.block.stack_level != 0)
        {
-         emit_move_insn (stack_pointer_rtx,
-                         thisblock->data.block.stack_level);
-         if (nonlocal_goto_stack_level != 0)
-           emit_move_insn (nonlocal_goto_stack_level, stack_pointer_rtx);
+         emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
+                             thisblock->data.block.stack_level, NULL_RTX);
+         if (nonlocal_goto_handler_slot != 0)
+           emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level,
+                            NULL_RTX);
        }
 
       /* Any gotos out of this block must also do these things.
-        Also report any gotos with fixups that came to labels in this level.  */
+        Also report any gotos with fixups that came to labels in this
+        level.  */
       fixup_gotos (thisblock,
                   thisblock->data.block.stack_level,
                   thisblock->data.block.cleanups,
@@ -2589,6 +3267,16 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
                   dont_jump_in);
     }
 
+  /* Mark the beginning and end of the scope if requested.
+     We do this now, after running cleanups on the variables
+     just going out of scope, so they are in scope for their cleanups.  */
+
+  if (mark_ends)
+    last_block_end_note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
+  else
+    /* Get rid of the beginning-mark if we don't make an end-mark.  */
+    NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
+
   /* If doing stupid register allocation, make sure lives of all
      register variables declared here extend thru end of scope.  */
 
@@ -2608,6 +3296,35 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
   /* Pop the stack slot nesting and free any slots at this level.  */
   pop_temp_slots ();
 }
+
+
+/* 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.  */
+
+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'");
+
+  bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisbind->exit_label));
+
+  /* Pop block/bindings off stack */
+  POPSTACK (nesting_stack);
+  POPSTACK (block_stack);
+}
 \f
 /* Generate RTL for the automatic variable declaration DECL.
    (Other kinds of declarations are simply ignored if seen here.)
@@ -2632,7 +3349,15 @@ 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,
@@ -2642,7 +3367,7 @@ expand_decl (decl)
 
   if (TREE_CODE (decl) != VAR_DECL)
     return;
-  if (TREE_STATIC (decl) || TREE_EXTERNAL (decl))
+  if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
     return;
 
   /* Create the RTL representation for the variable.  */
@@ -2667,13 +3392,41 @@ expand_decl (decl)
                && TREE_CODE (type) == REAL_TYPE)
           && ! TREE_THIS_VOLATILE (decl)
           && ! TREE_ADDRESSABLE (decl)
-          && (TREE_REGDECL (decl) || ! obey_regdecls))
+          && (DECL_REGISTER (decl) || ! obey_regdecls))
     {
       /* Automatic variable that can go in a register.  */
-      DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
-      if (TREE_CODE (type) == POINTER_TYPE)
-       mark_reg_pointer (DECL_RTL (decl));
-      REG_USERVAR_P (DECL_RTL (decl)) = 1;
+      enum machine_mode reg_mode = DECL_MODE (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 (reg_mode, unsignedp, type);
+       }
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+       {
+         rtx realpart, imagpart;
+         enum machine_mode partmode = TYPE_MODE (TREE_TYPE (type));
+
+         /* For a complex type variable, make a CONCAT of two pseudos
+            so that the real and imaginary parts
+            can be allocated separately.  */
+         realpart = gen_reg_rtx (partmode);
+         REG_USERVAR_P (realpart) = 1;
+         imagpart = gen_reg_rtx (partmode);
+         REG_USERVAR_P (imagpart) = 1;
+         DECL_RTL (decl) = gen_rtx (CONCAT, reg_mode, realpart, imagpart);
+       }
+      else
+       {
+         DECL_RTL (decl) = gen_reg_rtx (reg_mode);
+         if (TREE_CODE (type) == POINTER_TYPE)
+           mark_reg_pointer (DECL_RTL (decl));
+         REG_USERVAR_P (DECL_RTL (decl)) = 1;
+       }
     }
   else if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
     {
@@ -2716,7 +3469,8 @@ expand_decl (decl)
       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)) == UNION_TYPE
+          || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE);
 #if 0
       /* If this is in memory because of -ffloat-store,
         set the volatile bit, to prevent optimizations from
@@ -2735,8 +3489,9 @@ expand_decl (decl)
       if (thisblock->data.block.stack_level == 0)
        {
          do_pending_stack_adjust ();
-         thisblock->data.block.stack_level
-           = copy_to_reg (stack_pointer_rtx);
+         emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
+                          &thisblock->data.block.stack_level,
+                          thisblock->data.block.first_insn);
          stack_block_stack = thisblock;
        }
 
@@ -2744,18 +3499,30 @@ expand_decl (decl)
       size = expand_expr (size_binop (CEIL_DIV_EXPR,
                                      DECL_SIZE (decl),
                                      size_int (BITS_PER_UNIT)),
-                         0, VOIDmode, 0);
+                         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.  */
-      address = allocate_dynamic_stack_space (size, 0, DECL_ALIGN (decl));
+      address = allocate_dynamic_stack_space (size, NULL_RTX,
+                                             DECL_ALIGN (decl));
 
-      if (nonlocal_goto_stack_level != 0)
-       emit_move_insn (nonlocal_goto_stack_level, stack_pointer_rtx);
+      if (nonlocal_goto_handler_slot != 0)
+       emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
 
       /* 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);
+
       /* Indicate the alignment we actually gave this variable.  */
 #ifdef STACK_BOUNDARY
       DECL_ALIGN (decl) = STACK_BOUNDARY;
@@ -2766,8 +3533,15 @@ expand_decl (decl)
 
   if (TREE_THIS_VOLATILE (decl))
     MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
+#if 0 /* A variable is not necessarily unchanging
+        just because it is const.  RTX_UNCHANGING_P
+        means no change in the function,
+        not merely no change in the variable's scope.
+        It is correct to set RTX_UNCHANGING_P if the variable's scope
+        is the whole function.  There's no convenient way to test that.  */
   if (TREE_READONLY (decl))
     RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
+#endif
 
   /* If doing stupid register allocation, make sure life of any
      register variable starts here, at the start of its scope.  */
@@ -2775,6 +3549,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.  */
+
+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.  */
 
@@ -2784,6 +3604,20 @@ expand_decl_init (decl)
 {
   int was_used = TREE_USED (decl);
 
+  /* 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;
 
@@ -2812,6 +3646,81 @@ expand_decl_init (decl)
   free_temp_slots ();
 }
 
+/* Expand initialization for variable-sized types. Allocate array
+   using newlocalSI and set local variable, which is a pointer to the
+   storage. */
+
+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.  */
+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.
 
@@ -2936,33 +3845,6 @@ expand_cleanups (list, dont_do)
       }
 }
 
-/* Expand a list of cleanups for a goto fixup.
-   The expansion is put into the insn chain after the insn *BEFORE_JUMP
-   and *BEFORE_JUMP is set to the insn that now comes before the jump.  */
-
-static void
-fixup_cleanups (list, before_jump)
-     tree list;
-     rtx *before_jump;
-{
-  rtx beyond_jump = get_last_insn ();
-  rtx new_before_jump;
-
-  expand_cleanups (list, 0);
-  /* Pop any pushes done in the cleanups,
-     in case function is about to return.  */
-  do_pending_stack_adjust ();
-
-  new_before_jump = get_last_insn ();
-
-  if (beyond_jump != new_before_jump)
-    {
-      /* If cleanups expand to nothing, don't reorder.  */
-      reorder_insns (NEXT_INSN (beyond_jump), new_before_jump, *before_jump);
-      *before_jump = new_before_jump;
-    }
-}
-
 /* Move all cleanups from the current block_stack
    to the containing block_stack, where they are assumed to
    have been created.  If anything can cause a temporary to
@@ -3057,16 +3939,48 @@ 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
      need any transformation before expand_end_case.  */
   if (GET_CODE (get_last_insn ()) != NOTE)
-    emit_note (0, NOTE_INSN_DELETED);
+    emit_note (NULL_PTR, NOTE_INSN_DELETED);
 
   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. */
+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
@@ -3113,6 +4027,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.
@@ -3125,8 +4041,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;
 {
@@ -3135,6 +4052,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;
@@ -3152,7 +4072,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)
@@ -3233,8 +4153,9 @@ pushcase (value, label, duplicate)
    4 means the specified range was empty.  */
 
 int
-pushcase_range (value1, value2, label, duplicate)
+pushcase_range (value1, value2, converter, label, duplicate)
      register tree value1, value2;
+     tree (*converter) PROTO((tree, tree));
      register tree label;
      tree *duplicate;
 {
@@ -3282,11 +4203,11 @@ pushcase_range (value1, value2, label, duplicate)
   /* 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);
+  value1 = (*converter) (nominal_type, value1);
 
   if (value2 == 0)  /* Positive infinity. */
     value2 = TYPE_MAX_VALUE(index_type);
-  value2 = convert (nominal_type, value2);
+  value2 = (*converter) (nominal_type, value2);
 
   /* Fail if these values are out of range.  */
   if (! int_fits_type_p (value1, index_type))
@@ -3301,7 +4222,7 @@ pushcase_range (value1, value2, label, duplicate)
 
   /* If the bounds are equal, turn this into the one-value case.  */
   if (tree_int_cst_equal (value1, value2))
-    return pushcase (value1, label, duplicate);
+    return pushcase (value1, converter, label, duplicate);
 
   /* Find the elt in the chain before which to insert the new value,
      to keep the chain sorted in increasing order.
@@ -3340,6 +4261,62 @@ pushcase_range (value1, value2, label, duplicate)
 
   return 0;
 }
+
+
+/* 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
+bc_pushcase (value, label)
+     tree value;
+     tree label;
+{
+  struct nesting *thiscase = case_stack;
+  struct case_node *case_label, *new_label;
+
+  if (! thiscase)
+    return 1;
+
+  /* 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;
+    }
+
+  expand_label (label);
+  return 0;
+}
 \f
 /* Called when the index of a switch statement is an enumerated type
    and there is no default label.
@@ -3361,8 +4338,14 @@ check_for_full_enumeration_handling (type)
   register tree chain;
   int all_values = 1;
 
+  if (output_bytecode)
+    {
+      bc_check_for_full_enumeration_handling (type);
+      return;
+    }
+
   /* The time complexity of this loop is currently O(N * M), with
-     N being the number of enumerals in the enumerated type, and
+     N being the number of members in the enumerated type, and
      M being the number of case expressions in the switch. */
 
   for (chain = TYPE_VALUES (type);
@@ -3371,7 +4354,7 @@ check_for_full_enumeration_handling (type)
     {
       /* 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 enumerals not
+        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;
@@ -3379,17 +4362,17 @@ check_for_full_enumeration_handling (type)
           n = n->right)
        ;
 
-      if (!(n && tree_int_cst_equal (n->low, TREE_VALUE (chain))))
+      if (!n || tree_int_cst_lt (TREE_VALUE (chain), n->low))
        {
          if (warn_switch)
-           warning ("enumerated value `%s' not handled in switch",
+           warning ("enumeration value `%s' not handled in switch",
                     IDENTIFIER_POINTER (TREE_PURPOSE (chain)));
          all_values = 0;
        }
     }
 
   /* Now we go the other way around; we warn if there are case
-     expressions that don't correspond to enumerals.  This can
+     expressions that don't correspond to enumerators.  This can
      occur since C and C++ don't enforce type-checking of
      assignments to enumeration variables. */
 
@@ -3402,14 +4385,46 @@ check_for_full_enumeration_handling (type)
          ;
 
        if (!chain)
-         warning ("case value `%d' not in enumerated type `%s'",
-                  TREE_INT_CST_LOW (n->low),
-                  IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
-                                       == IDENTIFIER_NODE)
-                                      ? TYPE_NAME (type)
-                                      : DECL_NAME (TYPE_NAME (type))));
+         {
+           if (TYPE_NAME (type) == 0)
+             warning ("case value `%d' not in enumerated type",
+                      TREE_INT_CST_LOW (n->low));
+           else
+             warning ("case value `%d' not in enumerated type `%s'",
+                      TREE_INT_CST_LOW (n->low),
+                      IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
+                                           == IDENTIFIER_NODE)
+                                          ? TYPE_NAME (type)
+                                          : DECL_NAME (TYPE_NAME (type))));
+         }
+       if (!tree_int_cst_equal (n->low, n->high))
+         {
+           for (chain = TYPE_VALUES (type);
+                chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain));
+                chain = TREE_CHAIN (chain))
+             ;
+
+           if (!chain)
+             {
+               if (TYPE_NAME (type) == 0)
+                 warning ("case value `%d' not in enumerated type",
+                          TREE_INT_CST_LOW (n->high));
+               else
+                 warning ("case value `%d' not in enumerated type `%s'",
+                          TREE_INT_CST_LOW (n->high),
+                          IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
+                                               == IDENTIFIER_NODE)
+                                              ? TYPE_NAME (type)
+                                              : DECL_NAME (TYPE_NAME (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.  */
+
   /* 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
      the last one to make the default since this is likely the most
@@ -3425,29 +4440,80 @@ check_for_full_enumeration_handling (type)
       case_stack->data.case_stmt.default_label = (*l)->code_label;
       *l = 0;
     }
+#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.  */
+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 CASE_INDEX is the expression to be tested.
+   in which ORIG_INDEX is the expression to be tested.
    Generate the code to test it and jump to the right place.  */
 
 void
 expand_end_case (orig_index)
      tree orig_index;
 {
-  tree minval, maxval, range;
+  tree minval, maxval, range, orig_minval;
   rtx default_label = 0;
   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;
+  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;
+  unsignedp = TREE_UNSIGNED (TREE_TYPE (index_expr));
 
   do_pending_stack_adjust ();
 
@@ -3528,6 +4594,8 @@ expand_end_case (orig_index)
            count++;
        }
 
+      orig_minval = minval;
+
       /* Compute span of values.  */
       if (count != 0)
        range = fold (build (MINUS_EXPR, TREE_TYPE (index_expr),
@@ -3539,20 +4607,27 @@ expand_end_case (orig_index)
          emit_queue ();
          emit_jump (default_label);
        }
+
       /* If range of values is much bigger than number of values,
         make a sequence of conditional branches instead of a dispatch.
         If the switch-index is a constant, do it this way
         because we can optimize it.  */
-      else if (TREE_INT_CST_HIGH (range) != 0
+
+#ifndef CASE_VALUES_THRESHOLD
 #ifdef HAVE_casesi
-              || (HAVE_casesi ? count < 4 : count < 5)
+#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
 #else
-              /* If machine does not have a case insn that compares the
-                 bounds, this means extra overhead for dispatch tables
-                 which raises the threshold for using them.  */
-              || count < 5
-#endif
-              || (unsigned) (TREE_INT_CST_LOW (range)) > 10 * count
+      /* If machine does not have a case insn that compares the
+        bounds, this means extra overhead for dispatch tables
+        which raises the threshold for using them.  */
+#define CASE_VALUES_THRESHOLD 5
+#endif /* HAVE_casesi */
+#endif /* CASE_VALUES_THRESHOLD */
+
+      else if (TREE_INT_CST_HIGH (range) != 0
+              || count < CASE_VALUES_THRESHOLD
+              || ((unsigned HOST_WIDE_INT) (TREE_INT_CST_LOW (range))
+                  > 10 * count)
               || TREE_CODE (index_expr) == INTEGER_CST
               /* These will reduce to a constant.  */
               || (TREE_CODE (index_expr) == CALL_EXPR
@@ -3562,7 +4637,7 @@ expand_end_case (orig_index)
               || (TREE_CODE (index_expr) == COMPOUND_EXPR
                   && TREE_CODE (TREE_OPERAND (index_expr, 1)) == INTEGER_CST))
        {
-         index = expand_expr (index_expr, 0, VOIDmode, 0);
+         index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
 
          /* If the index is a short or char that we do not have
             an insn to handle comparisons directly, convert it to
@@ -3639,9 +4714,9 @@ expand_end_case (orig_index)
 
              use_cost_table
                = (TREE_CODE (TREE_TYPE (orig_index)) != ENUMERAL_TYPE
-                  && default_label != 0
                   && estimate_case_costs (thiscase->data.case_stmt.case_list));
-             balance_case_nodes (&thiscase->data.case_stmt.case_list, 0);
+             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));
              emit_jump_if_reachable (default_label);
@@ -3660,20 +4735,34 @@ expand_end_case (orig_index)
              if (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (index_expr)))
                  > GET_MODE_BITSIZE (index_mode))
                {
+                 enum machine_mode omode = TYPE_MODE (TREE_TYPE (index_expr));
+                 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, minval);
                  minval = integer_zero_node;
+                 index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+                 emit_cmp_insn (rangertx, index, LTU, NULL_RTX, omode, 1, 0);
+                 emit_jump_insn (gen_bltu (default_label));
+                 /* Now we can safely truncate.  */
+                 index = convert_to_mode (index_mode, index, 0);
+               }
+             else
+               {
+                 if (TYPE_MODE (TREE_TYPE (index_expr)) != index_mode)
+                   index_expr = convert (type_for_size (index_bits, 0),
+                                         index_expr);
+                 index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
                }
-             if (TYPE_MODE (TREE_TYPE (index_expr)) != index_mode)
-               index_expr = convert (type_for_size (index_bits, 0),
-                                     index_expr);
-             index = expand_expr (index_expr, 0, VOIDmode, 0);
              emit_queue ();
              index = protect_from_queue (index, 0);
              do_pending_stack_adjust ();
 
-             emit_jump_insn (gen_casesi (index, expand_expr (minval, 0, VOIDmode, 0),
-                                         expand_expr (range, 0, VOIDmode, 0),
+             emit_jump_insn (gen_casesi (index, expand_expr (minval, NULL_RTX,
+                                                             VOIDmode, 0),
+                                         expand_expr (range, NULL_RTX,
+                                                      VOIDmode, 0),
                                          table_label, default_label));
              win = 1;
            }
@@ -3685,15 +4774,13 @@ expand_end_case (orig_index)
                                    fold (build (MINUS_EXPR,
                                                 TREE_TYPE (index_expr),
                                                 index_expr, minval)));
-             index = expand_expr (index_expr, 0, VOIDmode, 0);
+             index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
              emit_queue ();
-             /* convert_to_mode calls protect_from_queue.  */
-             index = convert_to_mode (Pmode, index, 1);
+             index = protect_from_queue (index, 0);
              do_pending_stack_adjust ();
 
-             do_tablejump (index, Pmode,
-                           gen_rtx (CONST_INT, VOIDmode,
-                                    TREE_INT_CST_LOW (range)),
+             do_tablejump (index, TYPE_MODE (TREE_TYPE (index_expr)),
+                           expand_expr (range, NULL_RTX, VOIDmode, 0),
                            table_label, default_label);
              win = 1;
            }
@@ -3709,14 +4796,14 @@ expand_end_case (orig_index)
 
          for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
            {
-             register int i
-               = TREE_INT_CST_LOW (n->low) - TREE_INT_CST_LOW (minval);
+             register HOST_WIDE_INT i
+               = TREE_INT_CST_LOW (n->low) - TREE_INT_CST_LOW (orig_minval);
 
              while (1)
                {
                  labelvec[i]
                    = gen_rtx (LABEL_REF, Pmode, label_rtx (n->code_label));
-                 if (i + TREE_INT_CST_LOW (minval)
+                 if (i + TREE_INT_CST_LOW (orig_minval)
                      == TREE_INT_CST_LOW (n->high))
                    break;
                  i++;
@@ -3732,7 +4819,7 @@ expand_end_case (orig_index)
          emit_label (table_label);
 
          /* This would be a lot nicer if CASE_VECTOR_PC_RELATIVE
-            were an expression, instead of a an #ifdef/#ifndef.  */
+            were an expression, instead of an #ifdef/#ifndef.  */
          if (
 #ifdef CASE_VECTOR_PC_RELATIVE
              1 ||
@@ -3767,6 +4854,109 @@ expand_end_case (orig_index)
   free_temp_slots ();
 }
 
+
+/* Terminate a case statement.  EXPR is the original index
+   expression.  */
+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
@@ -3785,7 +4975,7 @@ do_jump_if_equal (op1, op2, label, unsignedp)
       enum machine_mode mode = GET_MODE (op1);
       if (mode == VOIDmode)
        mode = GET_MODE (op2);
-      emit_cmp_insn (op1, op2, EQ, 0, mode, unsignedp, 0);
+      emit_cmp_insn (op1, op2, EQ, NULL_RTX, mode, unsignedp, 0);
       emit_jump_insn (gen_beq (label));
     }
 }
@@ -3914,7 +5104,7 @@ group_case_nodes (head)
 
 /* Take an ordered list of case nodes
    and transform them into a near optimal binary tree,
-   on the assumtion that any target code selection value is as
+   on the assumption that any target code selection value is as
    likely as any other.
 
    The transformation is performed by splitting the ordered
@@ -4166,7 +5356,7 @@ emit_jump_if_reachable (label)
    current node are arranged to target the subordinates associated
    code for out of bound conditions on the current node node.
 
-   We can asume that when control reaches the code generated here,
+   We can assume that when control reaches the code generated here,
    the index value has already been compared with the parents
    of this node, and determined to be on the same side of each parent
    as this node is.  Thus, if this node tests for the value 51,
@@ -4200,7 +5390,7 @@ emit_case_nodes (index, node, default_label, index_type)
       /* Node is single valued.  First see if the index expression matches
         this node and then check our children, if any. */
 
-      do_jump_if_equal (index, expand_expr (node->low, 0, VOIDmode, 0),
+      do_jump_if_equal (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
                        label_rtx (node->code_label), unsignedp);
 
       if (node->right != 0 && node->left != 0)
@@ -4213,8 +5403,9 @@ emit_case_nodes (index, node, default_label, index_type)
 
          if (node_is_bounded (node->right, index_type))
            {
-             emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                            GT, 0, mode, unsignedp, 0);
+             emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                                VOIDmode, 0),
+                            GT, NULL_RTX, mode, unsignedp, 0);
 
              emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label)));
              emit_case_nodes (index, node->left, default_label, index_type);
@@ -4222,9 +5413,9 @@ emit_case_nodes (index, node, default_label, index_type)
 
          else if (node_is_bounded (node->left, index_type))
            {
-             emit_cmp_insn (index, expand_expr (node->high, 0,
+             emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
                                                 VOIDmode, 0),
-                            LT, 0, mode, unsignedp, 0);
+                            LT, NULL_RTX, mode, unsignedp, 0);
              emit_jump_insn ((*gen_blt_pat) (label_rtx (node->left->code_label)));
              emit_case_nodes (index, node->right, default_label, index_type);
            }
@@ -4238,9 +5429,9 @@ emit_case_nodes (index, node, default_label, index_type)
                = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
 
              /* See if the value is on the right.  */
-             emit_cmp_insn (index, expand_expr (node->high, 0,
+             emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
                                                 VOIDmode, 0),
-                            GT, 0, mode, unsignedp, 0);
+                            GT, NULL_RTX, mode, unsignedp, 0);
              emit_jump_insn ((*gen_bgt_pat) (label_rtx (test_label)));
 
              /* Value must be on the left.
@@ -4269,8 +5460,9 @@ emit_case_nodes (index, node, default_label, index_type)
            {
              if (!node_has_low_bound (node, index_type))
                {
-                 emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                                LT, 0, mode, unsignedp, 0);
+                 emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                                    VOIDmode, 0),
+                                LT, NULL_RTX, mode, unsignedp, 0);
                  emit_jump_insn ((*gen_blt_pat) (default_label));
                }
 
@@ -4281,7 +5473,8 @@ emit_case_nodes (index, node, default_label, index_type)
               since we haven't ruled out the numbers less than
               this node's value.  So handle node->right explicitly.  */
            do_jump_if_equal (index,
-                             expand_expr (node->right->low, 0, VOIDmode, 0),
+                             expand_expr (node->right->low, NULL_RTX,
+                                          VOIDmode, 0),
                              label_rtx (node->right->code_label), unsignedp);
        }
 
@@ -4307,8 +5500,9 @@ emit_case_nodes (index, node, default_label, index_type)
            {
              if (!node_has_high_bound (node, index_type))
                {
-                 emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                                GT, 0, mode, unsignedp, 0);
+                 emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                                    VOIDmode, 0),
+                                GT, NULL_RTX, mode, unsignedp, 0);
                  emit_jump_insn ((*gen_bgt_pat) (default_label));
                }
 
@@ -4319,7 +5513,8 @@ emit_case_nodes (index, node, default_label, index_type)
               since we haven't ruled out the numbers less than
               this node's value.  So handle node->left explicitly.  */
            do_jump_if_equal (index,
-                             expand_expr (node->left->low, 0, VOIDmode, 0),
+                             expand_expr (node->left->low, NULL_RTX,
+                                          VOIDmode, 0),
                              label_rtx (node->left->code_label), unsignedp);
        }
     }
@@ -4338,8 +5533,9 @@ emit_case_nodes (index, node, default_label, index_type)
             then handle the two subtrees.  */
          tree test_label = 0;
 
-         emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                        GT, 0, mode, unsignedp, 0);
+         emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                            VOIDmode, 0),
+                        GT, NULL_RTX, mode, unsignedp, 0);
 
          if (node_is_bounded (node->right, index_type))
            /* Right hand node is fully bounded so we can eliminate any
@@ -4356,8 +5552,8 @@ emit_case_nodes (index, node, default_label, index_type)
 
          /* Value belongs to this node or to the left-hand subtree.  */
 
-         emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0),
-                        GE, 0, mode, unsignedp, 0);
+         emit_cmp_insn (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
+                        GE, NULL_RTX, mode, unsignedp, 0);
          emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
 
          /* Handle the left-hand subtree.  */
@@ -4382,15 +5578,17 @@ emit_case_nodes (index, node, default_label, index_type)
             if they are possible.  */
          if (!node_has_low_bound (node, index_type))
            {
-             emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0),
-                            LT, 0, mode, unsignedp, 0);
+             emit_cmp_insn (index, expand_expr (node->low, NULL_RTX,
+                                                VOIDmode, 0),
+                            LT, NULL_RTX, mode, unsignedp, 0);
              emit_jump_insn ((*gen_blt_pat) (default_label));
            }
 
          /* Value belongs to this node or to the right-hand subtree.  */
 
-         emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                        LE, 0, mode, unsignedp, 0);
+         emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                            VOIDmode, 0),
+                        LE, NULL_RTX, mode, unsignedp, 0);
          emit_jump_insn ((*gen_ble_pat) (label_rtx (node->code_label)));
 
          emit_case_nodes (index, node->right, default_label, index_type);
@@ -4402,15 +5600,16 @@ emit_case_nodes (index, node, default_label, index_type)
             if they are possible.  */
          if (!node_has_high_bound (node, index_type))
            {
-             emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                            GT, 0, mode, unsignedp, 0);
+             emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                                VOIDmode, 0),
+                            GT, NULL_RTX, mode, unsignedp, 0);
              emit_jump_insn ((*gen_bgt_pat) (default_label));
            }
 
          /* Value belongs to this node or to the left-hand subtree.  */
 
-         emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0),
-                        GE, 0, mode, unsignedp, 0);
+         emit_cmp_insn (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
+                        GE, NULL_RTX, mode, unsignedp, 0);
          emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
 
          emit_case_nodes (index, node->left, default_label, index_type);
@@ -4424,15 +5623,17 @@ emit_case_nodes (index, node, default_label, index_type)
 
          if (!node_has_high_bound (node, index_type))
            {
-             emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0),
-                            GT, 0, mode, unsignedp, 0);
+             emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
+                                                VOIDmode, 0),
+                            GT, NULL_RTX, mode, unsignedp, 0);
              emit_jump_insn ((*gen_bgt_pat) (default_label));
            }
 
          if (!node_has_low_bound (node, index_type))
            {
-             emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0),
-                            LT, 0, mode, unsignedp, 0);
+             emit_cmp_insn (index, expand_expr (node->low, NULL_RTX,
+                                                VOIDmode, 0),
+                            LT, NULL_RTX, mode, unsignedp, 0);
              emit_jump_insn ((*gen_blt_pat) (default_label));
            }
 
@@ -4444,168 +5645,27 @@ emit_case_nodes (index, node, default_label, index_type)
 /* These routines are used by the loop unrolling code.  They copy BLOCK trees
    so that the debugging info will be correct for the unrolled loop.  */
 
-/* Indexed by loop number, contains pointer to the first block in the loop,
-   or zero if none.  Only valid if doing loop unrolling and outputting debugger
-   info.  */
-
-tree *loop_number_first_block;
-
-/* Indexed by loop number, contains pointer to the last block in the loop,
-   only valid if loop_number_first_block is nonzero.  */
-
-tree *loop_number_last_block;
-
-/* Indexed by loop number, contains nesting level of first block in the
-   loop, if any.  Only valid if doing loop unrolling and outputting debugger
-   info.  */
-
-int *loop_number_block_level;
+/* Indexed by block number, contains a pointer to the N'th block node.  */
 
-/* Scan the function looking for loops, and walk the BLOCK tree at the
-   same time.  Record the first and last BLOCK tree corresponding to each
-   loop.  This function is similar to find_and_verify_loops in loop.c.  */
+static tree *block_vector;
 
 void
-find_loop_tree_blocks (f)
-     rtx f;
+find_loop_tree_blocks ()
 {
-  rtx insn;
-  int current_loop = -1;
-  int next_loop = -1;
-  int loop;
-  int block_level, tree_level;
-  tree tree_block, parent_tree_block;
-
-  tree_block = DECL_INITIAL (current_function_decl);
-  parent_tree_block = 0;
-  block_level = 0;
-  tree_level = -1;
+  tree block = DECL_INITIAL (current_function_decl);
 
-  /* Find boundaries of loops, and save the first and last BLOCK tree
-     corresponding to each loop.  */
+  /* 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);
 
-  for (insn = f; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == NOTE)
-       switch (NOTE_LINE_NUMBER (insn))
-         {
-         case NOTE_INSN_LOOP_BEG:
-           loop_number_block_level[++next_loop] = block_level;
-           loop_number_first_block[next_loop] = 0;
-           current_loop = next_loop;
-           break;
-
-         case NOTE_INSN_LOOP_END:
-           if (current_loop == -1)
-             abort ();
-
-           current_loop = loop_outer_loop[current_loop];
-           break;
-
-         case NOTE_INSN_BLOCK_BEG:
-           if (tree_level < block_level)
-             {
-               /* We have seen two NOTE_INSN_BLOCK_BEG notes in a row, so
-                  we must now visit the subtree of the current block.  */
-               parent_tree_block = tree_block;
-               tree_block = BLOCK_SUBBLOCKS (tree_block);
-               tree_level++;
-             }
-           else if (tree_level > block_level)
-             abort ();
-
-           /* Save this block tree here for all nested loops for which
-              this is the topmost block.  */
-           for (loop = current_loop;
-                loop != -1 && block_level == loop_number_block_level[loop];
-                loop = loop_outer_loop[loop])
-             {
-               if (loop_number_first_block[loop] == 0)
-                 loop_number_first_block[loop] = tree_block;
-               loop_number_last_block[loop] = tree_block;
-             }
-
-           block_level++;
-           break;
-
-         case NOTE_INSN_BLOCK_END:
-           block_level--;
-           if (tree_level > block_level)
-             {
-               /* We have seen two NOTE_INSN_BLOCK_END notes in a row, so
-                  we must now visit the parent of the current tree.  */
-               if (tree_block != 0 || parent_tree_block == 0)
-                 abort ();
-               tree_block = parent_tree_block;
-               parent_tree_block = BLOCK_SUPERCONTEXT (parent_tree_block);
-               tree_level--;
-             }
-           tree_block = BLOCK_CHAIN (tree_block);
-           break;
-         }
-    }
+  block_vector = identify_blocks (block, get_insns ());
 }
 
-/* This routine will make COPIES-1 copies of all BLOCK trees that correspond
-   to BLOCK_BEG notes inside the loop LOOP_NUMBER.
-
-   Note that we only copy the topmost level of tree nodes; they will share
-   pointers to the same subblocks.  */
-
 void
-unroll_block_trees (loop_number, copies)
-     int loop_number;
-     int copies;
+unroll_block_trees ()
 {
-  int i;
-
-  /* First check whether there are any blocks that need to be copied.  */
-  if (loop_number_first_block[loop_number])
-    {
-      tree first_block = loop_number_first_block[loop_number];
-      tree last_block = loop_number_last_block[loop_number];
-      tree last_block_created = 0;
-
-      for (i = 0; i < copies - 1; i++)
-       {
-         tree block = first_block;
-         tree insert_after = last_block;
-         tree copied_block;
-
-         /* Copy every block between first_block and last_block inclusive,
-            inserting the new blocks after last_block.  */
-         do
-           {
-             tree new_block = make_node (BLOCK);
-             BLOCK_VARS (new_block) = BLOCK_VARS (block);
-             BLOCK_TYPE_TAGS (new_block) = BLOCK_TYPE_TAGS (block);
-             BLOCK_SUBBLOCKS (new_block) = BLOCK_SUBBLOCKS (block);
-             BLOCK_SUPERCONTEXT (new_block) = BLOCK_SUPERCONTEXT (block);
-             TREE_USED (new_block) = TREE_USED (block);
-
-             /* Insert the new block after the insertion point, and move
-                the insertion point to the new block.  This ensures that
-                the copies are inserted in the right order.  */
-             BLOCK_CHAIN (new_block) = BLOCK_CHAIN (insert_after);
-             BLOCK_CHAIN (insert_after) = new_block;
-             insert_after = new_block;
-
-             copied_block = block;
-             block = BLOCK_CHAIN (block);
-           }
-         while (copied_block != last_block);
-
-         /* Remember the last block created, so that we can update the
-            info in the tables.  */
-         if (last_block_created == 0)
-           last_block_created = insert_after;
-       }
+  tree block = DECL_INITIAL (current_function_decl);
 
-      /* For all nested loops for which LAST_BLOCK was originally the last
-        block, update the tables to indicate that LAST_BLOCK_CREATED is
-        now the last block in the loop.  */
-      for (i = loop_number; last_block == loop_number_last_block[i];
-          i = loop_outer_loop[i])
-       loop_number_last_block[i] = last_block_created;
-    }
+  reorder_blocks (block_vector, block, get_insns ());
 }
+