OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 3c4ccd1..f968012 100644 (file)
@@ -1,6 +1,6 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -35,6 +35,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "tree.h"
@@ -46,17 +48,15 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "expr.h"
 #include "libfuncs.h"
 #include "hard-reg-set.h"
-#include "obstack.h"
 #include "loop.h"
 #include "recog.h"
 #include "machmode.h"
 #include "toplev.h"
 #include "output.h"
 #include "ggc.h"
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-struct obstack stmt_obstack;
+#include "langhooks.h"
+#include "predict.h"
+#include "optabs.h"
 
 /* Assume that case vectors are not pc-relative.  */
 #ifndef CASE_VECTOR_PC_RELATIVE
@@ -87,7 +87,7 @@ struct obstack stmt_obstack;
    and nodes on the right having higher values.  We then output the tree
    in order.  */
 
-struct case_node
+struct case_node GTY(())
 {
   struct case_node     *left;  /* Left son in binary tree */
   struct case_node     *right; /* Right son in binary tree; also node chain */
@@ -110,7 +110,7 @@ static int cost_table_initialized;
 
 /* Special care is needed because we allow -1, but TREE_INT_CST_LOW
    is unsigned.  */
-#define COST_TABLE(I)  cost_table_[(unsigned HOST_WIDE_INT)((I) + 1)]
+#define COST_TABLE(I)  cost_table_[(unsigned HOST_WIDE_INT) ((I) + 1)]
 \f
 /* Stack of control and binding constructs we are currently inside.
 
@@ -137,16 +137,22 @@ static int cost_table_initialized;
    The construct is visible if the `exit_label' field is non-null.
    In that case, the value should be a CODE_LABEL rtx.  */
 
-struct nesting
+struct nesting GTY(())
 {
   struct nesting *all;
   struct nesting *next;
   int depth;
   rtx exit_label;
-  union
+  enum nesting_desc {
+    COND_NESTING,
+    LOOP_NESTING,
+    BLOCK_NESTING,
+    CASE_NESTING
+  } desc;
+  union nesting_u
     {
       /* For conds (if-then and if-then-else statements).  */
-      struct
+      struct nesting_cond
        {
          /* Label for the end of the if construct.
             There is none if EXITFLAG was not set
@@ -155,23 +161,20 @@ struct nesting
          /* Label for the end of this alternative.
             This may be the end of the if or the next else/elseif.  */
          rtx next_label;
-       } cond;
+       } GTY ((tag ("COND_NESTING"))) cond;
       /* For loops.  */
-      struct
+      struct nesting_loop
        {
          /* Label at the top of the loop; place to loop back to.  */
          rtx start_label;
          /* Label at the end of the whole construct.  */
          rtx end_label;
-         /* Label before a jump that branches to the end of the whole
-            construct.  This is where destructors go if any.  */
-         rtx alt_end_label;
          /* Label for `continue' statement to jump to;
             this is in front of the stepper of the loop.  */
          rtx continue_label;
-       } loop;
+       } GTY ((tag ("LOOP_NESTING"))) loop;
       /* For variable binding contours.  */
-      struct
+      struct nesting_block
        {
          /* Sequence number of this binding contour within the function,
             in order of entry.  */
@@ -203,7 +206,7 @@ struct nesting
          struct label_chain *label_chain;
          /* Number of function calls seen, as of start of this block.  */
          int n_function_calls;
-         /* Nonzero if this is associated with a EH region.  */
+         /* Nonzero if this is associated with an EH region.  */
          int exception_region;
          /* The saved target_temp_slot_level from our outer block.
             We may reset target_temp_slot_level to be the level of
@@ -221,14 +224,10 @@ struct nesting
             the start of the last unconditional cleanup, and before any
             conditional branch points.  */
          rtx last_unconditional_cleanup;
-         /* When in a conditional context, this is the specific
-            cleanup list associated with last_unconditional_cleanup,
-            where we place the conditionalized cleanups.  */
-         tree *cleanup_ptr;
-       } block;
+       } GTY ((tag ("BLOCK_NESTING"))) block;
       /* For switch (C) or case (Pascal) statements,
         and also for dummies (see `expand_start_case_dummy').  */
-      struct
+      struct nesting_case
        {
          /* The insn after which the case dispatch should finally
             be emitted.  Zero for a dummy.  */
@@ -249,14 +248,14 @@ struct nesting
             We set this to -1 when we see the first case label in this
             case statement.  */
          int line_number_status;
-       } case_stmt;
-    } data;
+       } GTY ((tag ("CASE_NESTING"))) case_stmt;
+    } GTY ((desc ("%1.desc"))) data;
 };
 
 /* Allocate and return a new `struct nesting'.  */
 
 #define ALLOC_NESTING() \
- (struct nesting *) obstack_alloc (&stmt_obstack, sizeof (struct nesting))
+ (struct nesting *) ggc_alloc (sizeof (struct nesting))
 
 /* Pop the nesting stack element by element until we pop off
    the element which is at the top of STACK.
@@ -278,8 +277,7 @@ do { struct nesting *target = STACK;                        \
          if (case_stack == this)                       \
            case_stack = case_stack->next;              \
          nesting_depth = nesting_stack->depth - 1;     \
-         nesting_stack = this->all;                    \
-         obstack_free (&stmt_obstack, this); }         \
+         nesting_stack = this->all; }                  \
      while (this != target); } while (0)
 \f
 /* In some cases it is impossible to generate code for a forward goto
@@ -290,7 +288,7 @@ do { struct nesting *target = STACK;                        \
    we check each fixup.
    If the target label has now been defined, we can insert the proper code.  */
 
-struct goto_fixup
+struct goto_fixup GTY(())
 {
   /* Points to following fixup.  */
   struct goto_fixup *next;
@@ -324,36 +322,36 @@ struct goto_fixup
 /* Within any binding contour that must restore a stack level,
    all labels are recorded with a chain of these structures.  */
 
-struct label_chain
+struct label_chain GTY(())
 {
   /* Points to following fixup.  */
   struct label_chain *next;
   tree label;
 };
 
-struct stmt_status
+struct stmt_status GTY(())
 {
   /* Chain of all pending binding contours.  */
-  struct nesting *x_block_stack;
+  struct nesting * x_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 *x_stack_block_stack;
+  struct nesting * x_stack_block_stack;
 
   /* Chain of all pending conditional statements.  */
-  struct nesting *x_cond_stack;
+  struct nesting * x_cond_stack;
 
   /* Chain of all pending loops.  */
-  struct nesting *x_loop_stack;
+  struct nesting * x_loop_stack;
 
   /* Chain of all pending case or switch statements.  */
-  struct nesting *x_case_stack;
+  struct nesting * x_case_stack;
 
   /* Separate chain including all of the above,
      chained through the `all' field.  */
-  struct nesting *x_nesting_stack;
+  struct nesting * x_nesting_stack;
 
   /* Number of entries on nesting_stack now.  */
   int x_nesting_depth;
@@ -393,10 +391,14 @@ struct stmt_status
 #define emit_lineno (cfun->stmt->x_emit_lineno)
 #define goto_fixup_chain (cfun->stmt->x_goto_fixup_chain)
 
-/* Non-zero if we are using EH to handle cleanus.  */
+/* Nonzero if we are using EH to handle cleanups.  */
 static int using_eh_for_cleanups_p = 0;
 
 static int n_occurrences               PARAMS ((int, const char *));
+static bool parse_input_constraint     PARAMS ((const char **, int, int, int,
+                                                int, const char * const *,
+                                                bool *, bool *));
+static bool decl_conflicts_with_clobbers_p PARAMS ((tree, const HARD_REG_SET));
 static void expand_goto_internal       PARAMS ((tree, rtx, rtx));
 static int expand_fixup                        PARAMS ((tree, rtx, rtx));
 static rtx expand_nl_handler_label     PARAMS ((rtx, rtx));
@@ -410,12 +412,19 @@ static tree resolve_operand_names PARAMS ((tree, tree, tree,
                                                 const char **));
 static char *resolve_operand_name_1    PARAMS ((char *, tree, tree));
 static void expand_null_return_1       PARAMS ((rtx));
+static enum br_predictor return_prediction PARAMS ((rtx));
 static void expand_value_return                PARAMS ((rtx));
 static int tail_recursion_args         PARAMS ((tree, tree));
 static void expand_cleanups            PARAMS ((tree, tree, int, int));
 static void check_seenlabel            PARAMS ((void));
 static void do_jump_if_equal           PARAMS ((rtx, rtx, rtx, int));
 static int estimate_case_costs         PARAMS ((case_node_ptr));
+static bool same_case_target_p         PARAMS ((rtx, rtx));
+static void strip_default_case_nodes   PARAMS ((case_node_ptr *, rtx));
+static bool lshift_cheap_p             PARAMS ((void));
+static int case_bit_test_cmp           PARAMS ((const void *, const void *));
+static void emit_case_bit_tests                PARAMS ((tree, tree, tree, tree,
+                                                case_node_ptr, rtx));
 static void group_case_nodes           PARAMS ((case_node_ptr));
 static void balance_case_nodes         PARAMS ((case_node_ptr *,
                                               case_node_ptr));
@@ -425,13 +434,6 @@ static int node_is_bounded         PARAMS ((case_node_ptr, tree));
 static void emit_jump_if_reachable     PARAMS ((rtx));
 static void emit_case_nodes            PARAMS ((rtx, case_node_ptr, rtx, tree));
 static struct case_node *case_tree2list        PARAMS ((case_node *, case_node *));
-static void mark_cond_nesting           PARAMS ((struct nesting *));
-static void mark_loop_nesting           PARAMS ((struct nesting *));
-static void mark_block_nesting          PARAMS ((struct nesting *));
-static void mark_case_nesting           PARAMS ((struct nesting *));
-static void mark_case_node             PARAMS ((struct case_node *));
-static void mark_goto_fixup             PARAMS ((struct goto_fixup *));
-static void free_case_nodes             PARAMS ((case_node_ptr));
 \f
 void
 using_eh_for_cleanups ()
@@ -439,176 +441,10 @@ using_eh_for_cleanups ()
   using_eh_for_cleanups_p = 1;
 }
 
-/* Mark N (known to be a cond-nesting) for GC.  */
-
-static void
-mark_cond_nesting (n)
-     struct nesting *n;
-{
-  while (n)
-    {
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.cond.endif_label);
-      ggc_mark_rtx (n->data.cond.next_label);
-
-      n = n->next;
-    }
-}
-
-/* Mark N (known to be a loop-nesting) for GC.  */
-
-static void
-mark_loop_nesting (n)
-     struct nesting *n;
-{
-
-  while (n)
-    {
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.loop.start_label);
-      ggc_mark_rtx (n->data.loop.end_label);
-      ggc_mark_rtx (n->data.loop.alt_end_label);
-      ggc_mark_rtx (n->data.loop.continue_label);
-
-      n = n->next;
-    }
-}
-
-/* Mark N (known to be a block-nesting) for GC.  */
-
-static void
-mark_block_nesting (n)
-     struct nesting *n;
-{
-  while (n)
-    {
-      struct label_chain *l;
-
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.block.stack_level);
-      ggc_mark_rtx (n->data.block.first_insn);
-      ggc_mark_tree (n->data.block.cleanups);
-      ggc_mark_tree (n->data.block.outer_cleanups);
-
-      for (l = n->data.block.label_chain; l != NULL; l = l->next) 
-       {
-         ggc_mark (l);
-         ggc_mark_tree (l->label);
-       }
-
-      ggc_mark_rtx (n->data.block.last_unconditional_cleanup);
-
-      /* ??? cleanup_ptr never points outside the stack, does it?  */
-
-      n = n->next;
-    }
-}
-
-/* Mark N (known to be a case-nesting) for GC.  */
-
-static void
-mark_case_nesting (n)
-     struct nesting *n;
-{
-  while (n)
-    {
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.case_stmt.start);
-
-      ggc_mark_tree (n->data.case_stmt.default_label);
-      ggc_mark_tree (n->data.case_stmt.index_expr);
-      ggc_mark_tree (n->data.case_stmt.nominal_type);
-
-      mark_case_node (n->data.case_stmt.case_list);
-      n = n->next;
-    }
-}
-
-/* Mark C for GC.  */
-
-static void
-mark_case_node (c)
-     struct case_node *c;
-{
-  if (c != 0)
-    {
-      ggc_mark_tree (c->low);
-      ggc_mark_tree (c->high);
-      ggc_mark_tree (c->code_label);
-
-      mark_case_node (c->right);
-      mark_case_node (c->left);
-    }
-}
-
-/* Mark G for GC.  */
-
-static void
-mark_goto_fixup (g)
-     struct goto_fixup *g;
-{
-  while (g)
-    {
-      ggc_mark (g);
-      ggc_mark_rtx (g->before_jump);
-      ggc_mark_tree (g->target);
-      ggc_mark_tree (g->context);
-      ggc_mark_rtx (g->target_rtl);
-      ggc_mark_rtx (g->stack_level);
-      ggc_mark_tree (g->cleanup_list_list);
-
-      g = g->next;
-    }
-}
-
-/* Clear out all parts of the state in F that can safely be discarded
-   after the function has been compiled, to let garbage collection
-   reclaim the memory.  */
-
-void
-free_stmt_status (f)
-     struct function *f;
-{
-  /* We're about to free the function obstack.  If we hold pointers to
-     things allocated there, then we'll try to mark them when we do
-     GC.  So, we clear them out here explicitly.  */
-  if (f->stmt)
-    free (f->stmt);
-  f->stmt = NULL;
-}
-
-/* Mark P for GC.  */
-
-void
-mark_stmt_status (p)
-     struct stmt_status *p;
-{
-  if (p == 0)
-    return;
-
-  mark_block_nesting (p->x_block_stack);
-  mark_cond_nesting (p->x_cond_stack);
-  mark_loop_nesting (p->x_loop_stack);
-  mark_case_nesting (p->x_case_stack);
-
-  ggc_mark_tree (p->x_last_expr_type);
-  /* last_epxr_value is only valid if last_expr_type is nonzero.  */
-  if (p->x_last_expr_type)
-    ggc_mark_rtx (p->x_last_expr_value);
-
-  mark_goto_fixup (p->x_goto_fixup_chain);
-}
-
-void
-init_stmt ()
-{
-  gcc_obstack_init (&stmt_obstack);
-}
-
 void
 init_stmt_for_function ()
 {
-  cfun->stmt = (struct stmt_status *) xmalloc (sizeof (struct stmt_status));
+  cfun->stmt = ((struct stmt_status *)ggc_alloc (sizeof (struct stmt_status)));
 
   /* We are not currently within any block, conditional, loop or case.  */
   block_stack = 0;
@@ -626,18 +462,9 @@ init_stmt_for_function ()
 
   /* We are not processing a ({...}) grouping.  */
   expr_stmts_for_value = 0;
-  last_expr_type = 0;
-  last_expr_value = NULL_RTX;
+  clear_last_expr ();
 }
 \f
-/* Return nonzero if anything is pushed on the loop, condition, or case
-   stack.  */
-int
-in_control_zone_p ()
-{
-  return cond_stack || loop_stack || case_stack;
-}
-
 /* Record the current file and line.  Called from emit_line_note.  */
 void
 set_file_and_line_for_stmt (file, line)
@@ -842,7 +669,7 @@ expand_goto (label)
          emit_indirect_jump (handler_slot);
        }
 
-      /* Search backwards to the jump insn and mark it as a 
+      /* Search backwards to the jump insn and mark it as a
         non-local goto.  */
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
        {
@@ -1041,8 +868,8 @@ expand_fixup (tree_label, rtl_label, last_insn)
         as a placeholder.  */
 
       {
-        rtx original_before_jump
-          = last_insn ? last_insn : get_last_insn ();
+       rtx original_before_jump
+         = last_insn ? last_insn : get_last_insn ();
        rtx start;
        rtx end;
        tree block;
@@ -1051,7 +878,7 @@ expand_fixup (tree_label, rtl_label, last_insn)
        TREE_USED (block) = 1;
 
        if (!cfun->x_whole_function_mode_p)
-         insert_block (block);
+         (*lang_hooks.decls.insert_block) (block);
        else
          {
            BLOCK_CHAIN (block)
@@ -1060,17 +887,17 @@ expand_fixup (tree_label, rtl_label, last_insn)
              = block;
          }
 
-        start_sequence ();
-        start = emit_note (NULL, NOTE_INSN_BLOCK_BEG);
+       start_sequence ();
+       start = emit_note (NULL, NOTE_INSN_BLOCK_BEG);
        if (cfun->x_whole_function_mode_p)
          NOTE_BLOCK (start) = block;
        fixup->before_jump = emit_note (NULL, NOTE_INSN_DELETED);
        end = emit_note (NULL, NOTE_INSN_BLOCK_END);
        if (cfun->x_whole_function_mode_p)
          NOTE_BLOCK (end) = block;
-        fixup->context = block;
-        end_sequence ();
-        emit_insns_after (start, original_before_jump);
+       fixup->context = block;
+       end_sequence ();
+       emit_insn_after (start, original_before_jump);
       }
 
       fixup->block_start_count = current_block_start_count;
@@ -1172,8 +999,8 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
             logically be inserting the fixup code.  We do this for the
             sake of getting the debugging information right.  */
 
-         pushlevel (0);
-         set_block (f->context);
+         (*lang_hooks.decls.pushlevel) (0);
+         (*lang_hooks.decls.set_block) (f->context);
 
          /* Expand the cleanups for blocks this jump exits.  */
          if (f->cleanup_list_list)
@@ -1212,10 +1039,10 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
             destructed are still "in scope".  */
 
          cleanup_insns = get_insns ();
-         poplevel (1, 0, 0);
+         (*lang_hooks.decls.poplevel) (1, 0, 0);
 
          end_sequence ();
-         emit_insns_after (cleanup_insns, f->before_jump);
+         emit_insn_after (cleanup_insns, f->before_jump);
 
          f->before_jump = 0;
        }
@@ -1246,16 +1073,16 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
          if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups)
            {
              start_sequence ();
-             pushlevel (0);
-             set_block (f->context);
+             (*lang_hooks.decls.pushlevel) (0);
+             (*lang_hooks.decls.set_block) (f->context);
              expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1);
              do_pending_stack_adjust ();
              cleanup_insns = get_insns ();
-             poplevel (1, 0, 0);
+             (*lang_hooks.decls.poplevel) (1, 0, 0);
              end_sequence ();
              if (cleanup_insns != 0)
                f->before_jump
-                 = emit_insns_after (cleanup_insns, f->before_jump);
+                 = emit_insn_after (cleanup_insns, f->before_jump);
 
              f->cleanup_list_list = TREE_CHAIN (lists);
            }
@@ -1278,19 +1105,27 @@ n_occurrences (c, s)
 }
 \f
 /* Generate RTL for an asm statement (explicit assembler code).
-   BODY is a STRING_CST node containing the assembler code text,
-   or an ADDR_EXPR containing a STRING_CST.  */
+   STRING is a STRING_CST node containing the assembler code text,
+   or an ADDR_EXPR containing a STRING_CST.  VOL nonzero means the
+   insn is volatile; don't optimize it.  */
 
 void
-expand_asm (body)
-     tree body;
+expand_asm (string, vol)
+     tree string;
+     int vol;
 {
-  if (TREE_CODE (body) == ADDR_EXPR)
-    body = TREE_OPERAND (body, 0);
+  rtx body;
+
+  if (TREE_CODE (string) == ADDR_EXPR)
+    string = TREE_OPERAND (string, 0);
+
+  body = gen_rtx_ASM_INPUT (VOIDmode, TREE_STRING_POINTER (string));
 
-  emit_insn (gen_rtx_ASM_INPUT (VOIDmode,
-                               TREE_STRING_POINTER (body)));
-  last_expr_type = 0;
+  MEM_VOLATILE_P (body) = vol;
+
+  emit_insn (body);
+  
+  clear_last_expr ();
 }
 
 /* Parse the output constraint pointed to by *CONSTRAINT_P.  It is the
@@ -1302,18 +1137,13 @@ expand_asm (body)
    will be true if the operand is read-write, i.e., if it is used as
    an input as well as an output.  If *CONSTRAINT_P is not in
    canonical form, it will be made canonical.  (Note that `+' will be
-   rpelaced with `=' as part of this process.)
+   replaced with `=' as part of this process.)
 
    Returns TRUE if all went well; FALSE if an error occurred.  */
 
 bool
-parse_output_constraint (constraint_p, 
-                        operand_num,
-                        ninputs,
-                        noutputs,
-                        allows_mem, 
-                        allows_reg, 
-                        is_inout)
+parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
+                        allows_mem, allows_reg, is_inout)
      const char **constraint_p;
      int operand_num;
      int ninputs;
@@ -1374,14 +1204,14 @@ parse_output_constraint (constraint_p,
     }
 
   /* Loop through the constraint string.  */
-  for (p = constraint + 1; *p; ++p)
+  for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
     switch (*p)
       {
       case '+':
       case '=':
        error ("operand constraint contains incorrectly positioned '+' or '='");
        return false;
-       
+
       case '%':
        if (operand_num + 1 == ninputs + noutputs)
          {
@@ -1418,7 +1248,7 @@ parse_output_constraint (constraint_p,
        *allows_reg = true;
        *allows_mem = true;
        break;
-       
+
       case 'p': case 'r':
        *allows_reg = true;
        break;
@@ -1426,9 +1256,149 @@ parse_output_constraint (constraint_p,
       default:
        if (!ISALPHA (*p))
          break;
-       if (REG_CLASS_FROM_LETTER (*p) != NO_REGS)
+       if (REG_CLASS_FROM_CONSTRAINT (*p, p) != NO_REGS)
+         *allows_reg = true;
+#ifdef EXTRA_CONSTRAINT_STR
+       else if (EXTRA_ADDRESS_CONSTRAINT (*p, p))
+         *allows_reg = true;
+       else if (EXTRA_MEMORY_CONSTRAINT (*p, p))
+         *allows_mem = true;
+       else
+         {
+           /* Otherwise we can't assume anything about the nature of
+              the constraint except that it isn't purely registers.
+              Treat it like "g" and hope for the best.  */
+           *allows_reg = true;
+           *allows_mem = true;
+         }
+#endif
+       break;
+      }
+
+  return true;
+}
+
+/* Similar, but for input constraints.  */
+
+static bool
+parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
+                       constraints, allows_mem, allows_reg)
+     const char **constraint_p;
+     int input_num;
+     int ninputs;
+     int noutputs;
+     int ninout;
+     const char * const * constraints;
+     bool *allows_mem;
+     bool *allows_reg;
+{
+  const char *constraint = *constraint_p;
+  const char *orig_constraint = constraint;
+  size_t c_len = strlen (constraint);
+  size_t j;
+
+  /* Assume the constraint doesn't allow the use of either
+     a register or memory.  */
+  *allows_mem = false;
+  *allows_reg = false;
+
+  /* Make sure constraint has neither `=', `+', nor '&'.  */
+
+  for (j = 0; j < c_len; j += CONSTRAINT_LEN (constraint[j], constraint+j))
+    switch (constraint[j])
+      {
+      case '+':  case '=':  case '&':
+       if (constraint == orig_constraint)
+         {
+           error ("input operand constraint contains `%c'", constraint[j]);
+           return false;
+         }
+       break;
+
+      case '%':
+       if (constraint == orig_constraint
+           && input_num + 1 == ninputs - ninout)
+         {
+           error ("`%%' constraint used with last operand");
+           return false;
+         }
+       break;
+
+      case 'V':  case 'm':  case 'o':
+       *allows_mem = true;
+       break;
+
+      case '<':  case '>':
+      case '?':  case '!':  case '*':  case '#':
+      case 'E':  case 'F':  case 'G':  case 'H':
+      case 's':  case 'i':  case 'n':
+      case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
+      case 'N':  case 'O':  case 'P':  case ',':
+       break;
+
+       /* Whether or not a numeric constraint allows a register is
+          decided by the matching constraint, and so there is no need
+          to do anything special with them.  We must handle them in
+          the default case, so that we don't unnecessarily force
+          operands to memory.  */
+      case '0':  case '1':  case '2':  case '3':  case '4':
+      case '5':  case '6':  case '7':  case '8':  case '9':
+       {
+         char *end;
+         unsigned long match;
+
+         match = strtoul (constraint + j, &end, 10);
+         if (match >= (unsigned long) noutputs)
+           {
+             error ("matching constraint references invalid operand number");
+             return false;
+           }
+
+         /* Try and find the real constraint for this dup.  Only do this
+            if the matching constraint is the only alternative.  */
+         if (*end == '\0'
+             && (j == 0 || (j == 1 && constraint[0] == '%')))
+           {
+             constraint = constraints[match];
+             *constraint_p = constraint;
+             c_len = strlen (constraint);
+             j = 0;
+             /* ??? At the end of the loop, we will skip the first part of
+                the matched constraint.  This assumes not only that the
+                other constraint is an output constraint, but also that
+                the '=' or '+' come first.  */
+             break;
+           }
+         else
+           j = end - constraint;
+         /* Anticipate increment at end of loop.  */
+         j--;
+       }
+       /* Fall through.  */
+
+      case 'p':  case 'r':
+       *allows_reg = true;
+       break;
+
+      case 'g':  case 'X':
+       *allows_reg = true;
+       *allows_mem = true;
+       break;
+
+      default:
+       if (! ISALPHA (constraint[j]))
+         {
+           error ("invalid punctuation `%c' in constraint", constraint[j]);
+           return false;
+         }
+       if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
+           != NO_REGS)
+         *allows_reg = true;
+#ifdef EXTRA_CONSTRAINT_STR
+       else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j], constraint + j))
          *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT
+       else if (EXTRA_MEMORY_CONSTRAINT (constraint[j], constraint + j))
+         *allows_mem = true;
        else
          {
            /* Otherwise we can't assume anything about the nature of
@@ -1444,12 +1414,49 @@ parse_output_constraint (constraint_p,
   return true;
 }
 
+/* Check for overlap between registers marked in CLOBBERED_REGS and
+   anything inappropriate in DECL.  Emit error and return TRUE for error,
+   FALSE for ok.  */
+
+static bool
+decl_conflicts_with_clobbers_p (decl, clobbered_regs)
+     tree decl;
+     const HARD_REG_SET clobbered_regs;
+{
+  /* Conflicts between asm-declared register variables and the clobber
+     list are not allowed.  */
+  if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
+      && DECL_REGISTER (decl)
+      && REG_P (DECL_RTL (decl))
+      && REGNO (DECL_RTL (decl)) < FIRST_PSEUDO_REGISTER)
+    {
+      rtx reg = DECL_RTL (decl);
+      unsigned int regno;
+
+      for (regno = REGNO (reg);
+          regno < (REGNO (reg)
+                   + HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)));
+          regno++)
+       if (TEST_HARD_REG_BIT (clobbered_regs, regno))
+         {
+           error ("asm-specifier for variable `%s' conflicts with asm clobber list",
+                  IDENTIFIER_POINTER (DECL_NAME (decl)));
+
+           /* Reset registerness to stop multiple errors emitted for a
+              single variable.  */
+           DECL_REGISTER (decl) = 0;
+           return true;
+         }
+    }
+  return false;
+}
+
 /* Generate RTL for an asm statement with arguments.
    STRING is the instruction template.
    OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
    Each output or input has an expression in the TREE_VALUE and
    and a tree list in TREE_PURPOSE which in turn contains a constraint
-   name in TREE_VALUE (or NULL_TREE) and a constraint string 
+   name in TREE_VALUE (or NULL_TREE) and a constraint string
    in TREE_PURPOSE.
    CLOBBERS is a list of STRING_CST nodes each naming a hard register
    that is clobbered by this insn.
@@ -1472,8 +1479,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   rtx body;
   int ninputs = list_length (inputs);
   int noutputs = list_length (outputs);
-  int ninout = 0;
+  int ninout;
   int nclobbers;
+  HARD_REG_SET clobbered_regs;
+  int clobber_conflict_found = 0;
   tree tail;
   int i;
   /* Vector of RTX's of evaluated output operands.  */
@@ -1484,8 +1493,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
     = (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
   const char **constraints
     = (const char **) alloca ((noutputs + ninputs) * sizeof (const char *));
-  /* The insn we have emitted.  */
-  rtx insn;
   int old_generating_concat_p = generating_concat_p;
 
   /* An ASM with no outputs needs to be treated as volatile, for now.  */
@@ -1511,6 +1518,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   /* Count the number of meaningful clobbered registers, ignoring what
      we would ignore later.  */
   nclobbers = 0;
+  CLEAR_HARD_REG_SET (clobbered_regs);
   for (tail = clobbers; tail; tail = TREE_CHAIN (tail))
     {
       const char *regname = TREE_STRING_POINTER (TREE_VALUE (tail));
@@ -1520,14 +1528,32 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
        ++nclobbers;
       else if (i == -2)
        error ("unknown register name `%s' in `asm'", regname);
+
+      /* Mark clobbered registers.  */
+      if (i >= 0)
+        {
+         /* Clobbering the PIC register is an error */
+         if (i == (int) PIC_OFFSET_TABLE_REGNUM)
+           {
+             error ("PIC register `%s' clobbered in `asm'", regname);
+             return;
+           }
+
+         SET_HARD_REG_BIT (clobbered_regs, i);
+       }
     }
 
-  last_expr_type = 0;
+  clear_last_expr ();
+
+  /* First pass over inputs and outputs checks validity and sets
+     mark_addressable if needed.  */
 
+  ninout = 0;
   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
     {
       tree val = TREE_VALUE (tail);
       tree type = TREE_TYPE (val);
+      const char *constraint;
       bool is_inout;
       bool allows_reg;
       bool allows_mem;
@@ -1536,22 +1562,68 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       if (type == error_mark_node)
        return;
 
-      /* Make sure constraint has `=' and does not have `+'.  Also, see
-        if it allows any register.  Be liberal on the latter test, since
-        the worst that happens if we get it wrong is we issue an error
-        message.  */
-
       /* Try to parse the output constraint.  If that fails, there's
         no point in going further.  */
-      if (!parse_output_constraint (&constraints[i],
-                                   i,
-                                   ninputs,
-                                   noutputs,
-                                   &allows_mem,
-                                   &allows_reg,
-                                   &is_inout))
+      constraint = constraints[i];
+      if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                   &allows_mem, &allows_reg, &is_inout))
+       return;
+
+      if (! allows_reg
+         && (allows_mem
+             || is_inout
+             || (DECL_P (val)
+                 && GET_CODE (DECL_RTL (val)) == REG
+                 && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
+       (*lang_hooks.mark_addressable) (val);
+
+      if (is_inout)
+       ninout++;
+    }
+
+  ninputs += ninout;
+  if (ninputs + noutputs > MAX_RECOG_OPERANDS)
+    {
+      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
+      return;
+    }
+
+  for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail))
+    {
+      bool allows_reg, allows_mem;
+      const char *constraint;
+
+      /* If there's an erroneous arg, emit no insn, because the ASM_INPUT
+        would get VOIDmode and that could cause a crash in reload.  */
+      if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
+       return;
+
+      constraint = constraints[i + noutputs];
+      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                   constraints, &allows_mem, &allows_reg))
        return;
 
+      if (! allows_reg && allows_mem)
+       (*lang_hooks.mark_addressable) (TREE_VALUE (tail));
+    }
+
+  /* Second pass evaluates arguments.  */
+
+  ninout = 0;
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+    {
+      tree val = TREE_VALUE (tail);
+      tree type = TREE_TYPE (val);
+      bool is_inout;
+      bool allows_reg;
+      bool allows_mem;
+      rtx op;
+
+      if (!parse_output_constraint (&constraints[i], i, ninputs,
+                                   noutputs, &allows_mem, &allows_reg,
+                                   &is_inout))
+       abort ();
+
       /* If an output operand is not a decl or indirect ref and our constraint
         allows a register, make a temporary to act as an intermediate.
         Make the asm insn write into that, then our caller will copy it to
@@ -1569,44 +1641,39 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          || ! allows_reg
          || is_inout)
        {
-         if (! allows_reg)
-           mark_addressable (TREE_VALUE (tail));
-
-         output_rtx[i]
-           = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
-                          EXPAND_WRITE);
+         op = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
+         if (GET_CODE (op) == MEM)
+           op = validize_mem (op);
 
-         if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
+         if (! allows_reg && GET_CODE (op) != MEM)
            error ("output number %d not directly addressable", i);
-         if ((! allows_mem && GET_CODE (output_rtx[i]) == MEM)
-             || GET_CODE (output_rtx[i]) == CONCAT)
+         if ((! allows_mem && GET_CODE (op) == MEM)
+             || GET_CODE (op) == CONCAT)
            {
-             real_output_rtx[i] = protect_from_queue (output_rtx[i], 1);
-             output_rtx[i] = gen_reg_rtx (GET_MODE (output_rtx[i]));
+             real_output_rtx[i] = protect_from_queue (op, 1);
+             op = gen_reg_rtx (GET_MODE (op));
              if (is_inout)
-               emit_move_insn (output_rtx[i], real_output_rtx[i]);
+               emit_move_insn (op, real_output_rtx[i]);
            }
        }
       else
        {
-         output_rtx[i] = assign_temp (type, 0, 0, 1);
-         TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
+         op = assign_temp (type, 0, 0, 1);
+         op = validize_mem (op);
+         TREE_VALUE (tail) = make_tree (type, op);
        }
+      output_rtx[i] = op;
 
       generating_concat_p = old_generating_concat_p;
 
       if (is_inout)
        {
-         inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
+         inout_mode[ninout] = TYPE_MODE (type);
          inout_opnum[ninout++] = i;
        }
-    }
 
-  ninputs += ninout;
-  if (ninputs + noutputs > MAX_RECOG_OPERANDS)
-    {
-      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
-      return;
+      if (decl_conflicts_with_clobbers_p (val, clobbered_regs))
+       clobber_conflict_found = 1;
     }
 
   /* Make vectors for the expression-rtx, constraint strings,
@@ -1617,7 +1684,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
                                : GET_MODE (output_rtx[0])),
-                              TREE_STRING_POINTER (string), 
+                              TREE_STRING_POINTER (string),
                               empty_string, 0, argvec, constraintvec,
                               filename, line);
 
@@ -1628,167 +1695,59 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
     {
-      int j;
-      int allows_reg = 0, allows_mem = 0;
-      const char *constraint, *orig_constraint;
-      int c_len;
+      bool allows_reg, allows_mem;
+      const char *constraint;
+      tree val, type;
       rtx op;
 
-      /* If there's an erroneous arg, emit no insn,
-        because the ASM_INPUT would get VOIDmode
-        and that could cause a crash in reload.  */
-      if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
-       return;
-
-      /* ??? Can this happen, and does the error message make any sense? */
-      if (TREE_PURPOSE (tail) == NULL_TREE)
-       {
-         error ("hard register `%s' listed as input operand to `asm'",
-                TREE_STRING_POINTER (TREE_VALUE (tail)) );
-         return;
-       }
-
-      orig_constraint = constraint = constraints[i + noutputs];
-      c_len = strlen (constraint);
-
-      /* Make sure constraint has neither `=', `+', nor '&'.  */
-
-      for (j = 0; j < c_len; j++)
-       switch (constraint[j])
-         {
-         case '+':  case '=':  case '&':
-           if (constraint == orig_constraint)
-             {
-               error ("input operand constraint contains `%c'",
-                      constraint[j]);
-               return;
-             }
-           break;
-
-         case '%':
-           if (constraint == orig_constraint
-               && i + 1 == ninputs - ninout)
-             {
-               error ("`%%' constraint used with last operand");
-               return;
-             }
-           break;
-
-         case 'V':  case 'm':  case 'o':
-           allows_mem = 1;
-           break;
-
-         case '<':  case '>':
-         case '?':  case '!':  case '*':  case '#':
-         case 'E':  case 'F':  case 'G':  case 'H':
-         case 's':  case 'i':  case 'n':
-         case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
-         case 'N':  case 'O':  case 'P':  case ',':
-           break;
-
-           /* Whether or not a numeric constraint allows a register is
-              decided by the matching constraint, and so there is no need
-              to do anything special with them.  We must handle them in
-              the default case, so that we don't unnecessarily force
-              operands to memory.  */
-         case '0':  case '1':  case '2':  case '3':  case '4':
-         case '5':  case '6':  case '7':  case '8':  case '9':
-           {
-             char *end;
-             unsigned long match;
-
-             match = strtoul (constraint + j, &end, 10);
-             if (match >= (unsigned long) noutputs)
-               {
-                 error ("matching constraint references invalid operand number");
-                 return;
-               }
-
-             /* Try and find the real constraint for this dup.  Only do
-                this if the matching constraint is the only alternative.  */
-             if (*end == '\0'
-                 && (j == 0 || (j == 1 && constraint[0] == '%')))
-               {
-                 constraint = constraints[match];
-                 c_len = strlen (constraint);
-                 j = 0;
-                 break;
-               }
-             else
-               j = end - constraint;
-           }
-           /* Fall through.  */
-
-         case 'p':  case 'r':
-           allows_reg = 1;
-           break;
-
-         case 'g':  case 'X':
-           allows_reg = 1;
-           allows_mem = 1;
-           break;
-
-         default:
-           if (! ISALPHA (constraint[j]))
-             {
-               error ("invalid punctuation `%c' in constraint",
-                      constraint[j]);
-               return;
-             }
-           if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
-             allows_reg = 1;
-#ifdef EXTRA_CONSTRAINT
-           else
-             {
-               /* Otherwise we can't assume anything about the nature of
-                  the constraint except that it isn't purely registers.
-                  Treat it like "g" and hope for the best.  */
-               allows_reg = 1;
-               allows_mem = 1;
-             }
-#endif
-           break;
-         }
+      constraint = constraints[i + noutputs];
+      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                   constraints, &allows_mem, &allows_reg))
+       abort ();
 
-      if (! allows_reg && allows_mem)
-       mark_addressable (TREE_VALUE (tail));
+      generating_concat_p = 0;
 
-      op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
+      val = TREE_VALUE (tail);
+      type = TREE_TYPE (val);
+      op = expand_expr (val, NULL_RTX, VOIDmode, 0);
 
       /* Never pass a CONCAT to an ASM.  */
-      generating_concat_p = 0;
       if (GET_CODE (op) == CONCAT)
        op = force_reg (GET_MODE (op), op);
+      else if (GET_CODE (op) == MEM)
+       op = validize_mem (op);
 
       if (asm_operand_ok (op, constraint) <= 0)
        {
          if (allows_reg)
-           op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
+           op = force_reg (TYPE_MODE (type), op);
          else if (!allows_mem)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
          else if (CONSTANT_P (op))
-           op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                                 op);
+           {
+             op = force_const_mem (TYPE_MODE (type), op);
+             op = validize_mem (op);
+           }
          else if (GET_CODE (op) == REG
                   || GET_CODE (op) == SUBREG
                   || GET_CODE (op) == ADDRESSOF
                   || GET_CODE (op) == CONCAT)
            {
-             tree type = TREE_TYPE (TREE_VALUE (tail));
              tree qual_type = build_qualified_type (type,
                                                     (TYPE_QUALS (type)
                                                      | TYPE_QUAL_CONST));
              rtx memloc = assign_temp (qual_type, 1, 1, 1);
-
+             memloc = validize_mem (memloc);
              emit_move_insn (memloc, op);
              op = memloc;
            }
 
          else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
-           /* We won't recognize volatile memory as available a
-              memory_operand at this point.  Ignore it.  */
-           ;
+           {
+             /* We won't recognize volatile memory as available a
+                memory_operand at this point.  Ignore it.  */
+           }
          else if (queued_subexp_p (op))
            ;
          else
@@ -1798,12 +1757,15 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
        }
+
       generating_concat_p = old_generating_concat_p;
       ASM_OPERANDS_INPUT (body, i) = op;
 
       ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
-       = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                            orig_constraint);
+       = gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
+
+      if (decl_conflicts_with_clobbers_p (val, clobbered_regs))
+       clobber_conflict_found = 1;
     }
 
   /* Protect all the operands from the queue now that they have all been
@@ -1842,13 +1804,13 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   if (noutputs == 1 && nclobbers == 0)
     {
       ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
-      insn = emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
+      emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
     }
 
   else if (noutputs == 0 && nclobbers == 0)
     {
       /* No output operands: put in a raw ASM_OPERANDS rtx.  */
-      insn = emit_insn (body);
+      emit_insn (body);
     }
 
   else
@@ -1888,6 +1850,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
        {
          const char *regname = TREE_STRING_POINTER (TREE_VALUE (tail));
          int j = decode_reg_name (regname);
+         rtx clobbered_reg;
 
          if (j < 0)
            {
@@ -1909,11 +1872,32 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            }
 
          /* Use QImode since that's guaranteed to clobber just one reg.  */
+         clobbered_reg = gen_rtx_REG (QImode, j);
+
+         /* Do sanity check for overlap between clobbers and respectively
+            input and outputs that hasn't been handled.  Such overlap
+            should have been detected and reported above.  */
+         if (!clobber_conflict_found)
+           {
+             int opno;
+
+             /* We test the old body (obody) contents to avoid tripping
+                over the under-construction body.  */
+             for (opno = 0; opno < noutputs; opno++)
+               if (reg_overlap_mentioned_p (clobbered_reg, output_rtx[opno]))
+                 internal_error ("asm clobber conflict with output operand");
+
+             for (opno = 0; opno < ninputs - ninout; opno++)
+               if (reg_overlap_mentioned_p (clobbered_reg,
+                                            ASM_OPERANDS_INPUT (obody, opno)))
+                 internal_error ("asm clobber conflict with input operand");
+           }
+
          XVECEXP (body, 0, i++)
-           = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (QImode, j));
+           = gen_rtx_CLOBBER (VOIDmode, clobbered_reg);
        }
 
-      insn = emit_insn (body);
+      emit_insn (body);
     }
 
   /* For any outputs that needed reloading into registers, spill them
@@ -1985,7 +1969,7 @@ check_unique_operand_names (outputs, inputs)
        continue;
 
       for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
-       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+       if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
          goto failure;
     }
 
@@ -1996,10 +1980,10 @@ check_unique_operand_names (outputs, inputs)
        continue;
 
       for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
-       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+       if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
          goto failure;
       for (j = outputs; j ; j = TREE_CHAIN (j))
-       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+       if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
          goto failure;
     }
 
@@ -2007,7 +1991,7 @@ check_unique_operand_names (outputs, inputs)
 
  failure:
   error ("duplicate asm operand name '%s'",
-        IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
+        TREE_STRING_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
   return false;
 }
 
@@ -2032,8 +2016,16 @@ resolve_operand_names (string, outputs, inputs, pconstraints)
   p = buffer;
   while ((p = strchr (p, '%')) != NULL)
     {
-      if (*++p != '[')
-       continue;
+      if (p[1] == '[')
+       p += 1;
+      else if (ISALPHA (p[1]) && p[2] == '[')
+       p += 2;
+      else
+       {
+         p += 1;
+         continue;
+       }
+
       p = resolve_operand_name_1 (p, outputs, inputs);
     }
 
@@ -2068,7 +2060,7 @@ resolve_operand_names (string, outputs, inputs, pconstraints)
 
 /* A subroutine of resolve_operand_names.  P points to the '[' for a
    potential named operand of the form [<name>].  In place, replace
-   the name and brackets with a number.  Return a pointer to the 
+   the name and brackets with a number.  Return a pointer to the
    balance of the string after substitution.  */
 
 static char *
@@ -2093,15 +2085,23 @@ resolve_operand_name_1 (p, outputs, inputs)
   /* Resolve the name to a number.  */
   for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
     {
-      const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
-      if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
-       goto found;
+      tree name = TREE_PURPOSE (TREE_PURPOSE (t));
+      if (name)
+       {
+         const char *c = TREE_STRING_POINTER (name);
+         if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+           goto found;
+       }
     }
   for (t = inputs; t ; t = TREE_CHAIN (t), op++)
     {
-      const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
-      if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
-       goto found;
+      tree name = TREE_PURPOSE (TREE_PURPOSE (t));
+      if (name)
+       {
+         const char *c = TREE_STRING_POINTER (name);
+         if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+           goto found;
+       }
     }
 
   *q = '\0';
@@ -2126,16 +2126,39 @@ resolve_operand_name_1 (p, outputs, inputs)
 }
 \f
 /* Generate RTL to evaluate the expression EXP
-   and remember it in case this is the VALUE in a ({... VALUE; }) constr.  */
+   and remember it in case this is the VALUE in a ({... VALUE; }) constr.
+   Provided just for backward-compatibility.  expand_expr_stmt_value()
+   should be used for new code.  */
 
 void
 expand_expr_stmt (exp)
      tree exp;
 {
-  /* If -W, warn about statements with no side effects,
+  expand_expr_stmt_value (exp, -1, 1);
+}
+
+/* Generate RTL to evaluate the expression EXP.  WANT_VALUE tells
+   whether to (1) save the value of the expression, (0) discard it or
+   (-1) use expr_stmts_for_value to tell.  The use of -1 is
+   deprecated, and retained only for backward compatibility.  */
+
+void
+expand_expr_stmt_value (exp, want_value, maybe_last)
+     tree exp;
+     int want_value, maybe_last;
+{
+  rtx value;
+  tree type;
+
+  if (want_value == -1)
+    want_value = expr_stmts_for_value != 0;
+
+  /* If -Wextra, 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.  */
-  if (expr_stmts_for_value == 0 && exp != error_mark_node)
+     except for last statement in ({...}) where they may be useful.  */
+  if (! want_value
+      && (expr_stmts_for_value == 0 || ! maybe_last)
+      && exp != error_mark_node)
     {
       if (! TREE_SIDE_EFFECTS (exp))
        {
@@ -2151,34 +2174,31 @@ expand_expr_stmt (exp)
 
   /* If EXP is of function type and we are expanding statements for
      value, convert it to pointer-to-function.  */
-  if (expr_stmts_for_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
+  if (want_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
     exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
 
   /* The call to `expand_expr' could cause last_expr_type and
      last_expr_value to get reset.  Therefore, we set last_expr_value
      and last_expr_type *after* calling expand_expr.  */
-  last_expr_value = expand_expr (exp,
-                                (expr_stmts_for_value
-                                 ? NULL_RTX : const0_rtx),
-                                VOIDmode, 0);
-  last_expr_type = TREE_TYPE (exp);
+  value = expand_expr (exp, want_value ? NULL_RTX : const0_rtx,
+                      VOIDmode, 0);
+  type = TREE_TYPE (exp);
 
   /* If all we do is reference a volatile value in memory,
      copy it to a register to be sure it is actually touched.  */
-  if (last_expr_value != 0 && GET_CODE (last_expr_value) == MEM
-      && TREE_THIS_VOLATILE (exp))
+  if (value && GET_CODE (value) == MEM && TREE_THIS_VOLATILE (exp))
     {
-      if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)
+      if (TYPE_MODE (type) == VOIDmode)
        ;
-      else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
-       copy_to_reg (last_expr_value);
+      else if (TYPE_MODE (type) != BLKmode)
+       value = copy_to_reg (value);
       else
        {
          rtx lab = gen_label_rtx ();
 
          /* Compare the value with itself to reference it.  */
-         emit_cmp_and_jump_insns (last_expr_value, last_expr_value, EQ,
-                                  expand_expr (TYPE_SIZE (last_expr_type),
+         emit_cmp_and_jump_insns (value, value, EQ,
+                                  expand_expr (TYPE_SIZE (type),
                                                NULL_RTX, VOIDmode, 0),
                                   BLKmode, 0, lab);
          emit_label (lab);
@@ -2187,13 +2207,19 @@ expand_expr_stmt (exp)
 
   /* If this expression is part of a ({...}) and is in memory, we may have
      to preserve temporaries.  */
-  preserve_temp_slots (last_expr_value);
+  preserve_temp_slots (value);
 
   /* Free any temporaries used to evaluate this expression.  Any temporary
      used as a result of this expression will already have been preserved
      above.  */
   free_temp_slots ();
 
+  if (want_value)
+    {
+      last_expr_value = value;
+      last_expr_type = type;
+    }
+
   emit_queue ();
 }
 
@@ -2213,10 +2239,6 @@ warn_if_unused_value (exp)
   if (VOID_TYPE_P (TREE_TYPE (exp)))
     return 0;
 
-  /* If this is an expression with side effects, don't warn.  */
-  if (TREE_SIDE_EFFECTS (exp))
-    return 0;
-
   switch (TREE_CODE (exp))
     {
     case PREINCREMENT_EXPR:
@@ -2276,7 +2298,7 @@ warn_if_unused_value (exp)
            || TREE_CODE (tem) == CALL_EXPR)
          return 0;
       }
-      goto warn;
+      goto maybe_warn;
 
     case INDIRECT_REF:
       /* Don't warn about automatic dereferencing of references, since
@@ -2299,7 +2321,11 @@ warn_if_unused_value (exp)
          && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
        return 0;
 
-    warn:
+    maybe_warn:
+      /* If this is an expression with side effects, don't warn.  */
+      if (TREE_SIDE_EFFECTS (exp))
+       return 0;
+
       warning_with_file_and_line (emit_filename, emit_lineno,
                                  "value computed is not used");
       return 1;
@@ -2311,15 +2337,20 @@ warn_if_unused_value (exp)
 void
 clear_last_expr ()
 {
-  last_expr_type = 0;
+  last_expr_type = NULL_TREE;
+  last_expr_value = NULL_RTX;
 }
 
-/* Begin a statement which will return a value.
-   Return the RTL_EXPR for this statement expr.
-   The caller must save that value and pass it to expand_end_stmt_expr.  */
+/* Begin a statement-expression, i.e., a series of statements which
+   may return a value.  Return the RTL_EXPR for this statement expr.
+   The caller must save that value and pass it to
+   expand_end_stmt_expr.  If HAS_SCOPE is nonzero, temporaries created
+   in the statement-expression are deallocated at the end of the
+   expression.  */
 
 tree
-expand_start_stmt_expr ()
+expand_start_stmt_expr (has_scope)
+     int has_scope;
 {
   tree t;
 
@@ -2327,7 +2358,10 @@ expand_start_stmt_expr ()
      so that rtl_expr_chain doesn't become garbage.  */
   t = make_node (RTL_EXPR);
   do_pending_stack_adjust ();
-  start_sequence_for_rtl_expr (t);
+  if (has_scope)
+    start_sequence_for_rtl_expr (t);
+  else
+    start_sequence ();
   NO_DEFER_POP;
   expr_stmts_for_value++;
   return t;
@@ -2351,15 +2385,11 @@ expand_end_stmt_expr (t)
 {
   OK_DEFER_POP;
 
-  if (last_expr_type == 0)
+  if (! last_expr_value || ! last_expr_type)
     {
-      last_expr_type = void_type_node;
       last_expr_value = const0_rtx;
+      last_expr_type = void_type_node;
     }
-  else if (last_expr_value == 0)
-    /* There are some cases where this can happen, such as when the
-       statement is void type.  */
-    last_expr_value = const0_rtx;
   else if (GET_CODE (last_expr_value) != REG && ! CONSTANT_P (last_expr_value))
     /* Remove any possible QUEUED.  */
     last_expr_value = protect_from_queue (last_expr_value, 0);
@@ -2379,7 +2409,7 @@ expand_end_stmt_expr (t)
   /* Propagate volatility of the actual RTL expr.  */
   TREE_THIS_VOLATILE (t) = volatile_refs_p (last_expr_value);
 
-  last_expr_type = 0;
+  clear_last_expr ();
   expr_stmts_for_value--;
 
   return t;
@@ -2400,6 +2430,7 @@ expand_start_cond (cond, exitflag)
 
   /* Make an entry on cond_stack for the cond we are entering.  */
 
+  thiscond->desc = COND_NESTING;
   thiscond->next = cond_stack;
   thiscond->all = nesting_stack;
   thiscond->depth = ++nesting_depth;
@@ -2470,7 +2501,7 @@ expand_end_cond ()
     emit_label (thiscond->data.cond.endif_label);
 
   POPSTACK (cond_stack);
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 \f
 /* Generate RTL for the start of a loop.  EXIT_FLAG is nonzero if this
@@ -2488,12 +2519,12 @@ expand_start_loop (exit_flag)
 
   /* Make an entry on loop_stack for the loop we are entering.  */
 
+  thisloop->desc = LOOP_NESTING;
   thisloop->next = loop_stack;
   thisloop->all = nesting_stack;
   thisloop->depth = ++nesting_depth;
   thisloop->data.loop.start_label = gen_label_rtx ();
   thisloop->data.loop.end_label = gen_label_rtx ();
-  thisloop->data.loop.alt_end_label = 0;
   thisloop->data.loop.continue_label = thisloop->data.loop.start_label;
   thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0;
   loop_stack = thisloop;
@@ -2529,12 +2560,12 @@ expand_start_null_loop ()
 
   /* Make an entry on loop_stack for the loop we are entering.  */
 
+  thisloop->desc = LOOP_NESTING;
   thisloop->next = loop_stack;
   thisloop->all = nesting_stack;
   thisloop->depth = ++nesting_depth;
   thisloop->data.loop.start_label = emit_note (NULL, NOTE_INSN_DELETED);
   thisloop->data.loop.end_label = gen_label_rtx ();
-  thisloop->data.loop.alt_end_label = NULL_RTX;
   thisloop->data.loop.continue_label = thisloop->data.loop.end_label;
   thisloop->exit_label = thisloop->data.loop.end_label;
   loop_stack = thisloop;
@@ -2544,329 +2575,172 @@ expand_start_null_loop ()
 }
 
 /* Specify the continuation point for a loop started with
-   expand_start_loop_continue_elsewhere.
-   Use this at the point in the code to which a continue statement
-   should jump.  */
-
-void
-expand_loop_continue_here ()
-{
-  do_pending_stack_adjust ();
-  emit_note (NULL, NOTE_INSN_LOOP_CONT);
-  emit_label (loop_stack->data.loop.continue_label);
-}
-
-/* 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 ()
-{
-  rtx start_label = loop_stack->data.loop.start_label;
-  rtx insn = get_last_insn ();
-  int needs_end_jump = 1;
-
-  /* Mark the continue-point at the top of the loop if none elsewhere.  */
-  if (start_label == loop_stack->data.loop.continue_label)
-    emit_note_before (NOTE_INSN_LOOP_CONT, start_label);
-
-  do_pending_stack_adjust ();
-
-  /* If optimizing, perhaps reorder the loop.
-     First, try to use a condjump near the end.
-     expand_exit_loop_if_false ends loops with unconditional jumps,
-     like this:
-
-     if (test) goto label;
-     optional: cleanup
-     goto loop_stack->data.loop.end_label
-     barrier
-     label:
-
-     If we find such a pattern, we can end the loop earlier.  */
-
-  if (optimize
-      && GET_CODE (insn) == CODE_LABEL
-      && LABEL_NAME (insn) == NULL
-      && GET_CODE (PREV_INSN (insn)) == BARRIER)
-    {
-      rtx label = insn;
-      rtx jump = PREV_INSN (PREV_INSN (label));
-
-      if (GET_CODE (jump) == JUMP_INSN
-         && GET_CODE (PATTERN (jump)) == SET
-         && SET_DEST (PATTERN (jump)) == pc_rtx
-         && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
-         && (XEXP (SET_SRC (PATTERN (jump)), 0)
-             == loop_stack->data.loop.end_label))
-       {
-         rtx prev;
-
-         /* The test might be complex and reference LABEL multiple times,
-            like the loop in loop_iterations to set vtop.  To handle this,
-            we move LABEL.  */
-         insn = PREV_INSN (label);
-         reorder_insns (label, label, start_label);
-
-         for (prev = PREV_INSN (jump);; prev = PREV_INSN (prev))
-           {
-             /* We ignore line number notes, but if we see any other note,
-                in particular NOTE_INSN_BLOCK_*, NOTE_INSN_EH_REGION_*,
-                NOTE_INSN_LOOP_*, we disable this optimization.  */
-             if (GET_CODE (prev) == NOTE)
-               {
-                 if (NOTE_LINE_NUMBER (prev) < 0)
-                   break;
-                 continue;
-               }
-             if (GET_CODE (prev) == CODE_LABEL)
-               break;
-             if (GET_CODE (prev) == JUMP_INSN)
-               {
-                 if (GET_CODE (PATTERN (prev)) == SET
-                     && SET_DEST (PATTERN (prev)) == pc_rtx
-                     && GET_CODE (SET_SRC (PATTERN (prev))) == IF_THEN_ELSE
-                     && (GET_CODE (XEXP (SET_SRC (PATTERN (prev)), 1))
-                         == LABEL_REF)
-                     && XEXP (XEXP (SET_SRC (PATTERN (prev)), 1), 0) == label)
-                   {
-                     XEXP (XEXP (SET_SRC (PATTERN (prev)), 1), 0)
-                       = start_label;
-                     emit_note_after (NOTE_INSN_LOOP_END, prev);
-                     needs_end_jump = 0;
-                   }
-                 break;
-               }
-          }
-       }
-    }
-
-     /* If the loop starts with a loop exit, roll that to the end where
-     it will optimize together with the jump back.
-
-     We look for the conditional branch to the exit, except that once
-     we find such a branch, we don't look past 30 instructions.
-
-     In more detail, if the loop presently looks like this (in pseudo-C):
-
-         start_label:
-         if (test) goto end_label;
-        body;
-        goto start_label;
-        end_label:
-
-     transform it to look like:
-
-         goto start_label;
-         newstart_label:
-        body;
-        start_label:
-        if (test) goto end_label;
-        goto newstart_label;
-        end_label:
-
-     Here, the `test' may actually consist of some reasonably complex
-     code, terminating in a test.  */
-
-  if (optimize
-      && needs_end_jump
-      &&
-      ! (GET_CODE (insn) == JUMP_INSN
-        && GET_CODE (PATTERN (insn)) == SET
-        && SET_DEST (PATTERN (insn)) == pc_rtx
-        && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
-    {
-      int eh_regions = 0;
-      int num_insns = 0;
-      rtx last_test_insn = NULL_RTX;
+   expand_start_loop_continue_elsewhere.
+   Use this at the point in the code to which a continue statement
+   should jump.  */
 
-      /* Scan insns from the top of the loop looking for a qualified
-        conditional exit.  */
-      for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn;
-          insn = NEXT_INSN (insn))
-       {
-         if (GET_CODE (insn) == NOTE)
-           {
-             if (optimize < 2
-                 && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-                     || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
-               /* The code that actually moves the exit test will
-                  carefully leave BLOCK notes in their original
-                  location.  That means, however, that we can't debug
-                  the exit test itself.  So, we refuse to move code
-                  containing BLOCK notes at low optimization levels.  */
-               break;
-
-             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
-               ++eh_regions;
-             else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
-               {
-                 --eh_regions;
-                 if (eh_regions < 0)
-                   /* We've come to the end of an EH region, but
-                      never saw the beginning of that region.  That
-                      means that an EH region begins before the top
-                      of the loop, and ends in the middle of it.  The
-                      existence of such a situation violates a basic
-                      assumption in this code, since that would imply
-                      that even when EH_REGIONS is zero, we might
-                      move code out of an exception region.  */
-                   abort ();
-               }
+void
+expand_loop_continue_here ()
+{
+  do_pending_stack_adjust ();
+  emit_note (NULL, NOTE_INSN_LOOP_CONT);
+  emit_label (loop_stack->data.loop.continue_label);
+}
 
-             /* We must not walk into a nested loop.  */
-             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-               break;
+/* Finish a loop.  Generate a jump back to the top and the loop-exit label.
+   Pop the block off of loop_stack.  */
 
-             /* We already know this INSN is a NOTE, so there's no
-                point in looking at it to see if it's a JUMP.  */
-             continue;
-           }
+void
+expand_end_loop ()
+{
+  rtx start_label = loop_stack->data.loop.start_label;
+  rtx etc_note;
+  int eh_regions, debug_blocks;
+  bool empty_test;
 
-         if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
-           num_insns++;
+  /* Mark the continue-point at the top of the loop if none elsewhere.  */
+  if (start_label == loop_stack->data.loop.continue_label)
+    emit_note_before (NOTE_INSN_LOOP_CONT, start_label);
 
-         if (last_test_insn && num_insns > 30)
-           break;
+  do_pending_stack_adjust ();
 
-         if (eh_regions > 0)
-           /* We don't want to move a partial EH region.  Consider:
-
-                 while ( ( { try {
-                               if (cond ()) 0;
-                               else {
-                                 bar();
-                                 1;
-                               }
-                             } catch (...) {
-                               1;
-                             } )) {
-                    body;
-                 }
+  /* If the loop starts with a loop exit, roll that to the end where
+     it will optimize together with the jump back.
 
-               This isn't legal C++, but here's what it's supposed to
-               mean: if cond() is true, stop looping.  Otherwise,
-               call bar, and keep looping.  In addition, if cond
-               throws an exception, catch it and keep looping. Such
-               constructs are certainy legal in LISP.
+     If the loop presently looks like this (in pseudo-C):
 
-               We should not move the `if (cond()) 0' test since then
-               the EH-region for the try-block would be broken up.
-               (In this case we would the EH_BEG note for the `try'
-               and `if cond()' but not the call to bar() or the
-               EH_END note.)
+       LOOP_BEG
+       start_label:
+         if (test) goto end_label;
+       LOOP_END_TOP_COND
+         body;
+         goto start_label;
+       end_label:
 
-               So we don't look for tests within an EH region.  */
-           continue;
+     transform it to look like:
 
-         if (GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == SET
-             && SET_DEST (PATTERN (insn)) == pc_rtx)
-           {
-             /* This is indeed a jump.  */
-             rtx dest1 = NULL_RTX;
-             rtx dest2 = NULL_RTX;
-             rtx potential_last_test;
-             if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
-               {
-                 /* A conditional jump.  */
-                 dest1 = XEXP (SET_SRC (PATTERN (insn)), 1);
-                 dest2 = XEXP (SET_SRC (PATTERN (insn)), 2);
-                 potential_last_test = insn;
-               }
-             else
-               {
-                 /* An unconditional jump.  */
-                 dest1 = SET_SRC (PATTERN (insn));
-                 /* Include the BARRIER after the JUMP.  */
-                 potential_last_test = NEXT_INSN (insn);
-               }
+       LOOP_BEG
+         goto start_label;
+       top_label:
+         body;
+       start_label:
+         if (test) goto end_label;
+         goto top_label;
+       end_label:
+
+     We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
+     the end of the entry conditional.  Without this, our lexical scan
+     can't tell the difference between an entry conditional and a
+     body conditional that exits the loop.  Mistaking the two means
+     that we can misplace the NOTE_INSN_LOOP_CONT note, which can
+     screw up loop unrolling.
+
+     Things will be oh so much better when loop optimization is done
+     off of a proper control flow graph...  */
+
+  /* Scan insns from the top of the loop looking for the END_TOP_COND note.  */
+
+  empty_test = true;
+  eh_regions = debug_blocks = 0;
+  for (etc_note = start_label; etc_note ; etc_note = NEXT_INSN (etc_note))
+    if (GET_CODE (etc_note) == NOTE)
+      {
+       if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_END_TOP_COND)
+         break;
 
-             do {
-               if (dest1 && GET_CODE (dest1) == LABEL_REF
-                   && ((XEXP (dest1, 0)
-                        == loop_stack->data.loop.alt_end_label)
-                       || (XEXP (dest1, 0)
-                           == loop_stack->data.loop.end_label)))
-                 {
-                   last_test_insn = potential_last_test;
-                   break;
-                 }
+       /* We must not walk into a nested loop.  */
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG)
+         {
+           etc_note = NULL_RTX;
+           break;
+         }
 
-               /* If this was a conditional jump, there may be
-                  another label at which we should look.  */
-               dest1 = dest2;
-               dest2 = NULL_RTX;
-             } while (dest1);
-           }
-       }
+       /* At the same time, scan for EH region notes, as we don't want
+          to scrog region nesting.  This shouldn't happen, but...  */
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG)
+         eh_regions++;
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_END)
+         {
+           if (--eh_regions < 0)
+             /* We've come to the end of an EH region, but never saw the
+                beginning of that region.  That means that an EH region
+                begins before the top of the loop, and ends in the middle
+                of it.  The existence of such a situation violates a basic
+                assumption in this code, since that would imply that even
+                when EH_REGIONS is zero, we might move code out of an
+                exception region.  */
+             abort ();
+         }
 
-      if (last_test_insn != 0 && last_test_insn != get_last_insn ())
+       /* Likewise for debug scopes.  In this case we'll either (1) move
+          all of the notes if they are properly nested or (2) leave the
+          notes alone and only rotate the loop at high optimization
+          levels when we expect to scrog debug info.  */
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_BEG)
+         debug_blocks++;
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_END)
+         debug_blocks--;
+      }
+    else if (INSN_P (etc_note))
+      empty_test = false;
+
+  if (etc_note
+      && optimize
+      && ! empty_test
+      && eh_regions == 0
+      && (debug_blocks == 0 || optimize >= 2)
+      && NEXT_INSN (etc_note) != NULL_RTX
+      && ! any_condjump_p (get_last_insn ()))
+    {
+      /* We found one.  Move everything from START to ETC to the end
+        of the loop, and add a jump from the top of the loop.  */
+      rtx top_label = gen_label_rtx ();
+      rtx start_move = start_label;
+
+      /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
+        then we want to move this note also.  */
+      if (GET_CODE (PREV_INSN (start_move)) == NOTE
+         && NOTE_LINE_NUMBER (PREV_INSN (start_move)) == NOTE_INSN_LOOP_CONT)
+       start_move = PREV_INSN (start_move);
+
+      emit_label_before (top_label, start_move);
+
+      /* Actually move the insns.  If the debug scopes are nested, we
+        can move everything at once.  Otherwise we have to move them
+        one by one and squeeze out the block notes.  */
+      if (debug_blocks == 0)
+       reorder_insns (start_move, etc_note, get_last_insn ());
+      else
        {
-         /* We found one.  Move everything from there up
-            to the end of the loop, and add a jump into the loop
-            to jump to there.  */
-         rtx newstart_label = gen_label_rtx ();
-         rtx start_move = start_label;
-         rtx next_insn;
-
-         /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
-            then we want to move this note also.  */
-         if (GET_CODE (PREV_INSN (start_move)) == NOTE
-             && (NOTE_LINE_NUMBER (PREV_INSN (start_move))
-                 == NOTE_INSN_LOOP_CONT))
-           start_move = PREV_INSN (start_move);
-
-         emit_label_after (newstart_label, PREV_INSN (start_move));
-
-         /* Actually move the insns.  Start at the beginning, and
-            keep copying insns until we've copied the
-            last_test_insn.  */
+         rtx insn, next_insn;
          for (insn = start_move; insn; insn = next_insn)
            {
              /* Figure out which insn comes after this one.  We have
                 to do this before we move INSN.  */
-             if (insn == last_test_insn)
-               /* We've moved all the insns.  */
-               next_insn = NULL_RTX;
-             else
-               next_insn = NEXT_INSN (insn);
+             next_insn = (insn == etc_note ? NULL : NEXT_INSN (insn));
 
              if (GET_CODE (insn) == NOTE
                  && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
                      || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
-               /* We don't want to move NOTE_INSN_BLOCK_BEGs or
-                  NOTE_INSN_BLOCK_ENDs because the correct generation
-                  of debugging information depends on these appearing
-                  in the same order in the RTL and in the tree
-                  structure, where they are represented as BLOCKs.
-                  So, we don't move block notes.  Of course, moving
-                  the code inside the block is likely to make it
-                  impossible to debug the instructions in the exit
-                  test, but such is the price of optimization.  */
                continue;
 
-             /* Move the INSN.  */
              reorder_insns (insn, insn, get_last_insn ());
            }
-
-         emit_jump_insn_after (gen_jump (start_label),
-                               PREV_INSN (newstart_label));
-         emit_barrier_after (PREV_INSN (newstart_label));
-         start_label = newstart_label;
        }
-    }
 
-  if (needs_end_jump)
-    {
-      emit_jump (start_label);
-      emit_note (NULL, NOTE_INSN_LOOP_END);
+      /* Add the jump from the top of the loop.  */
+      emit_jump_insn_before (gen_jump (start_label), top_label);
+      emit_barrier_before (top_label);
+      start_label = top_label;
     }
+
+  emit_jump (start_label);
+  emit_note (NULL, NOTE_INSN_LOOP_END);
   emit_label (loop_stack->data.loop.end_label);
 
   POPSTACK (loop_stack);
 
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 
 /* Finish a null loop, aka do { } while (0).  */
@@ -2879,7 +2753,7 @@ expand_end_null_loop ()
 
   POPSTACK (loop_stack);
 
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 
 /* Generate a jump to the current loop's continue-point.
@@ -2891,7 +2765,12 @@ int
 expand_continue_loop (whichloop)
      struct nesting *whichloop;
 {
-  last_expr_type = 0;
+  /* Emit information for branch prediction.  */
+  rtx note;
+
+  note = emit_note (NULL, NOTE_INSN_PREDICTION);
+  NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
+  clear_last_expr ();
   if (whichloop == 0)
     whichloop = loop_stack;
   if (whichloop == 0)
@@ -2908,7 +2787,7 @@ int
 expand_exit_loop (whichloop)
      struct nesting *whichloop;
 {
-  last_expr_type = 0;
+  clear_last_expr ();
   if (whichloop == 0)
     whichloop = loop_stack;
   if (whichloop == 0)
@@ -2926,22 +2805,32 @@ expand_exit_loop_if_false (whichloop, cond)
      struct nesting *whichloop;
      tree cond;
 {
-  rtx label = gen_label_rtx ();
-  rtx last_insn;
-  last_expr_type = 0;
+  rtx label;
+  clear_last_expr ();
 
   if (whichloop == 0)
     whichloop = loop_stack;
   if (whichloop == 0)
     return 0;
+
+  if (integer_nonzerop (cond))
+    return 1;
+  if (integer_zerop (cond))
+    return expand_exit_loop (whichloop);
+
+  /* Check if we definitely won't need a fixup.  */
+  if (whichloop == nesting_stack)
+    {
+      jumpifnot (cond, whichloop->data.loop.end_label);
+      return 1;
+    }
+
   /* In order to handle fixups, we actually create a conditional jump
      around an unconditional branch to exit the loop.  If fixups are
      necessary, they go before the unconditional branch.  */
 
-  do_jump (cond, NULL_RTX, label);
-  last_insn = get_last_insn ();
-  if (GET_CODE (last_insn) == CODE_LABEL)
-    whichloop->data.loop.alt_end_label = last_insn;
+  label = gen_label_rtx ();
+  jumpif (cond, label);
   expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
                        NULL_RTX);
   emit_label (label);
@@ -2949,18 +2838,23 @@ expand_exit_loop_if_false (whichloop, cond)
   return 1;
 }
 
-/* Return nonzero if the loop nest is empty.  Else return zero.  */
+/* Like expand_exit_loop_if_false except also emit a note marking
+   the end of the conditional.  Should only be used immediately
+   after expand_loop_start.  */
 
 int
-stmt_loop_nest_empty ()
+expand_exit_loop_top_cond (whichloop, cond)
+     struct nesting *whichloop;
+     tree cond;
 {
-  /* cfun->stmt can be NULL if we are building a call to get the
-     EH context for a setjmp/longjmp EH target and the current
-     function was a deferred inline function.  */
-  return (cfun->stmt == NULL || loop_stack == NULL);
+  if (! expand_exit_loop_if_false (whichloop, cond))
+    return 0;
+
+  emit_note (NULL, NOTE_INSN_LOOP_END_TOP_COND);
+  return 1;
 }
 
-/* Return non-zero if we should preserve sub-expressions as separate
+/* Return nonzero 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.
 
@@ -2999,7 +2893,7 @@ int
 expand_exit_something ()
 {
   struct nesting *n;
-  last_expr_type = 0;
+  clear_last_expr ();
   for (n = nesting_stack; n; n = n->all)
     if (n->exit_label != 0)
       {
@@ -3016,7 +2910,9 @@ expand_exit_something ()
 void
 expand_null_return ()
 {
-  rtx last_insn = get_last_insn ();
+  rtx last_insn;
+
+  last_insn = get_last_insn ();
 
   /* If this function was declared to return a value, but we
      didn't, clobber the return registers so that they are not
@@ -3026,14 +2922,58 @@ expand_null_return ()
   expand_null_return_1 (last_insn);
 }
 
+/* Try to guess whether the value of return means error code.  */
+static enum br_predictor
+return_prediction (val)
+     rtx val;
+{
+  /* Different heuristics for pointers and scalars.  */
+  if (POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
+    {
+      /* NULL is usually not returned.  */
+      if (val == const0_rtx)
+       return PRED_NULL_RETURN;
+    }
+  else
+    {
+      /* Negative return values are often used to indicate
+         errors.  */
+      if (GET_CODE (val) == CONST_INT
+         && INTVAL (val) < 0)
+       return PRED_NEGATIVE_RETURN;
+      /* Constant return values are also usually erors,
+         zero/one often mean booleans so exclude them from the
+        heuristics.  */
+      if (CONSTANT_P (val)
+         && (val != const0_rtx && val != const1_rtx))
+       return PRED_CONST_RETURN;
+    }
+  return PRED_NO_PREDICTION;
+}
+
 /* Generate RTL to return from the current function, with value VAL.  */
 
 static void
 expand_value_return (val)
      rtx val;
 {
-  rtx last_insn = get_last_insn ();
-  rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
+  rtx last_insn;
+  rtx return_reg;
+  enum br_predictor pred;
+
+  if ((pred = return_prediction (val)) != PRED_NO_PREDICTION)
+    {
+      /* Emit information for branch prediction.  */
+      rtx note;
+
+      note = emit_note (NULL, NOTE_INSN_PREDICTION);
+
+      NOTE_PREDICTION (note) = NOTE_PREDICT (pred, NOT_TAKEN);
+
+    }
+
+  last_insn = get_last_insn ();
+  return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
 
   /* Copy the value to the return location
      unless it's already there.  */
@@ -3071,7 +3011,7 @@ expand_null_return_1 (last_insn)
 
   clear_pending_stack_adjust ();
   do_pending_stack_adjust ();
-  last_expr_type = 0;
+  clear_last_expr ();
 
   if (end_label == 0)
      end_label = return_label = gen_label_rtx ();
@@ -3112,7 +3052,7 @@ expand_return (retval)
       /* Treat this like a return of no value from a function that
         returns a value.  */
       expand_null_return ();
-      return; 
+      return;
     }
   else if (TREE_CODE (retval) == RESULT_DECL)
     retval_rhs = retval;
@@ -3198,7 +3138,6 @@ expand_return (retval)
         machine, this means we must skip the empty high order bytes when
         calculating the bit offset.  */
       if (BYTES_BIG_ENDIAN
-         && !FUNCTION_ARG_REG_LITTLE_ENDIAN
          && bytes % UNITS_PER_WORD)
        big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
                                                  * BITS_PER_UNIT));
@@ -3297,18 +3236,6 @@ expand_return (retval)
       expand_value_return (result_rtl);
     }
 }
-
-/* Return 1 if the end of the generated RTX is not a barrier.
-   This means code already compiled can drop through.  */
-
-int
-drop_through_at_end_p ()
-{
-  rtx insn = get_last_insn ();
-  while (insn && GET_CODE (insn) == NOTE)
-    insn = PREV_INSN (insn);
-  return insn && GET_CODE (insn) != BARRIER;
-}
 \f
 /* Attempt to optimize a potential tail recursion call into a goto.
    ARGUMENTS are the arguments to a CALL_EXPR; LAST_INSN indicates
@@ -3403,8 +3330,18 @@ tail_recursion_args (actuals, formals)
       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],
-                     TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (a))));
+       {
+         rtx tmp = argvec[i];
+
+         if (DECL_MODE (f) != GET_MODE (DECL_RTL (f)))
+           {
+             tmp = gen_reg_rtx (DECL_MODE (f));
+             convert_move (tmp, argvec[i],
+                           TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (a))));
+           }
+         convert_move (DECL_RTL (f), tmp,
+                       TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (a))));
+       }
     }
 
   free_temp_slots ();
@@ -3457,6 +3394,7 @@ expand_start_bindings_and_block (flags, block)
 
   /* Make an entry on block_stack for the block we are entering.  */
 
+  thisblock->desc = BLOCK_NESTING;
   thisblock->next = block_stack;
   thisblock->all = nesting_stack;
   thisblock->depth = ++nesting_depth;
@@ -3475,7 +3413,6 @@ expand_start_bindings_and_block (flags, block)
      instructions inserted after the last unconditional cleanup are
      never the last instruction.  */
   emit_note (NULL, NOTE_INSN_DELETED);
-  thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
 
   if (block_stack
       && !(block_stack->data.block.cleanups == NULL_TREE
@@ -3527,7 +3464,7 @@ expand_end_target_temps ()
   pop_temp_slots ();
 }
 
-/* Given a pointer to a BLOCK node return non-zero if (and only if) the node
+/* Given a pointer to a BLOCK node return nonzero if (and only if) the node
    in question represents the outermost pair of curly braces (i.e. the "body
    block") of a function or method.
 
@@ -3593,7 +3530,7 @@ expand_nl_handler_label (slot, before_insn)
   emit_move_insn (slot, gen_rtx_LABEL_REF (Pmode, handler_label));
   insns = get_insns ();
   end_sequence ();
-  emit_insns_before (insns, before_insn);
+  emit_insn_before (insns, before_insn);
 
   emit_label (handler_label);
 
@@ -3680,7 +3617,7 @@ expand_nl_goto_receivers (thisblock)
        emit_move_insn (save_receiver, XEXP (slot, 0));
        insns = get_insns ();
        end_sequence ();
-       emit_insns_before (insns, thisblock->data.block.first_insn);
+       emit_insn_before (insns, thisblock->data.block.first_insn);
       }
 
   /* Jump around the handlers; they run only when specially invoked.  */
@@ -3725,9 +3662,7 @@ expand_nl_goto_receivers (thisblock)
   if (any_invalid)
     {
       expand_nl_goto_receiver ();
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), LCT_NORETURN,
-                        VOIDmode, 0);
-      emit_barrier ();
+      expand_builtin_trap ();
     }
 
   nonlocal_goto_handler_labels = label_list;
@@ -3918,7 +3853,6 @@ void
 expand_decl (decl)
      tree decl;
 {
-  struct nesting *thisblock;
   tree type;
 
   type = TREE_TYPE (decl);
@@ -3944,8 +3878,6 @@ expand_decl (decl)
   if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
     return;
 
-  thisblock = block_stack;
-
   /* Create the RTL representation for the variable.  */
 
   if (type == error_mark_node)
@@ -3981,14 +3913,6 @@ expand_decl (decl)
 
       SET_DECL_RTL (decl, gen_reg_rtx (reg_mode));
 
-      if (GET_CODE (DECL_RTL (decl)) == REG)
-       REGNO_DECL (REGNO (DECL_RTL (decl))) = decl;
-      else if (GET_CODE (DECL_RTL (decl)) == CONCAT)
-       {
-         REGNO_DECL (REGNO (XEXP (DECL_RTL (decl), 0))) = decl;
-         REGNO_DECL (REGNO (XEXP (DECL_RTL (decl), 1))) = decl;
-       }
-
       mark_user_reg (DECL_RTL (decl));
 
       if (POINTER_TYPE_P (type))
@@ -4029,7 +3953,7 @@ expand_decl (decl)
                           : GET_MODE_BITSIZE (DECL_MODE (decl)));
       DECL_USER_ALIGN (decl) = 0;
 
-      x = assign_temp (TREE_TYPE (decl), 1, 1, 1);
+      x = assign_temp (decl, 1, 1, 1);
       set_mem_attributes (x, decl, 1);
       SET_DECL_RTL (decl, x);
 
@@ -4168,21 +4092,22 @@ expand_decl_cleanup (decl, cleanup)
          end_sequence ();
 
          thisblock->data.block.last_unconditional_cleanup
-           = emit_insns_after (set_flag_0,
+           = emit_insn_after (set_flag_0,
                                thisblock->data.block.last_unconditional_cleanup);
 
          emit_move_insn (flag, const1_rtx);
 
-         cond = build_decl (VAR_DECL, NULL_TREE, type_for_mode (word_mode, 1));
+         cond = build_decl (VAR_DECL, NULL_TREE,
+                            (*lang_hooks.types.type_for_mode) (word_mode, 1));
          SET_DECL_RTL (cond, flag);
 
          /* Conditionalize the cleanup.  */
          cleanup = build (COND_EXPR, void_type_node,
-                          truthvalue_conversion (cond),
+                          (*lang_hooks.truthvalue_conversion) (cond),
                           cleanup, integer_zero_node);
          cleanup = fold (cleanup);
 
-         cleanups = thisblock->data.block.cleanup_ptr;
+         cleanups = &thisblock->data.block.cleanups;
        }
 
       cleanup = unsave_expr (cleanup);
@@ -4209,8 +4134,8 @@ expand_decl_cleanup (decl, cleanup)
          end_sequence ();
          if (seq)
            thisblock->data.block.last_unconditional_cleanup
-             = emit_insns_after (seq,
-                                 thisblock->data.block.last_unconditional_cleanup);
+             = emit_insn_after (seq,
+                                thisblock->data.block.last_unconditional_cleanup);
        }
       else
        {
@@ -4223,11 +4148,27 @@ expand_decl_cleanup (decl, cleanup)
             instructions inserted after the last unconditional cleanup are
             never the last instruction.  */
          emit_note (NULL, NOTE_INSN_DELETED);
-         thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
        }
     }
   return 1;
 }
+
+/* Like expand_decl_cleanup, but maybe only run the cleanup if an exception
+   is thrown.  */
+
+int
+expand_decl_cleanup_eh (decl, cleanup, eh_only)
+     tree decl, cleanup;
+     int eh_only;
+{
+  int ret = expand_decl_cleanup (decl, cleanup);
+  if (cleanup && ret)
+    {
+      tree node = block_stack->data.block.cleanups;
+      CLEANUP_EH_ONLY (node) = eh_only;
+    }
+  return ret;
+}
 \f
 /* DECL is an anonymous union.  CLEANUP is a cleanup for DECL.
    DECL_ELTS is the list of elements that belong to DECL's type.
@@ -4260,6 +4201,11 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
       tree cleanup_elt = TREE_PURPOSE (t);
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
 
+      /* If any of the elements are addressable, so is the entire
+        union.  */
+      if (TREE_USED (decl_elt))
+       TREE_USED (decl) = 1;
+
       /* Propagate the union's alignment to the elements.  */
       DECL_ALIGN (decl_elt) = DECL_ALIGN (decl);
       DECL_USER_ALIGN (decl_elt) = DECL_USER_ALIGN (decl);
@@ -4307,7 +4253,7 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
    This is sometimes used to avoid a cleanup associated with
    a value that is being returned out of the scope.
 
-   If IN_FIXUP is non-zero, we are generating this cleanup for a fixup
+   If IN_FIXUP is nonzero, we are generating this cleanup for a fixup
    goto and handle protection regions specially in that case.
 
    If REACHABLE, we emit code, otherwise just inform the exception handling
@@ -4331,7 +4277,7 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
            if (! in_fixup && using_eh_for_cleanups_p)
              expand_eh_region_end_cleanup (TREE_VALUE (tail));
 
-           if (reachable)
+           if (reachable && !CLEANUP_EH_ONLY (tail))
              {
                /* Cleanups may be run multiple times.  For example,
                   when exiting a binding contour, we expand the
@@ -4389,24 +4335,6 @@ end_cleanup_deferral ()
     --block_stack->data.block.conditional_code;
 }
 
-/* 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
-   be created, but not expanded for more than one level of
-   block_stacks, then this code will have to change.  */
-
-void
-move_cleanups_up ()
-{
-  struct nesting *block = block_stack;
-  struct nesting *outer = block->next;
-
-  outer->data.block.cleanups
-    = chainon (block->data.block.cleanups,
-              outer->data.block.cleanups);
-  block->data.block.cleanups = 0;
-}
-
 tree
 last_cleanup_this_contour ()
 {
@@ -4465,6 +4393,7 @@ expand_start_case (exit_flag, expr, type, printname)
 
   /* Make an entry on case_stack for the case we are entering.  */
 
+  thiscase->desc = CASE_NESTING;
   thiscase->next = case_stack;
   thiscase->all = nesting_stack;
   thiscase->depth = ++nesting_depth;
@@ -4502,6 +4431,7 @@ expand_start_case_dummy ()
 
   /* Make an entry on case_stack for the dummy.  */
 
+  thiscase->desc = CASE_NESTING;
   thiscase->next = case_stack;
   thiscase->all = nesting_stack;
   thiscase->depth = ++nesting_depth;
@@ -4514,26 +4444,6 @@ expand_start_case_dummy ()
   nesting_stack = thiscase;
   start_cleanup_deferral ();
 }
-
-/* End a dummy case statement.  */
-
-void
-expand_end_case_dummy ()
-{
-  end_cleanup_deferral ();
-  POPSTACK (case_stack);
-}
-
-/* Return the data type of the index-expression
-   of the innermost case statement, or null if none.  */
-
-tree
-case_index_expr_type ()
-{
-  if (case_stack)
-    return TREE_TYPE (case_stack->data.case_stmt.index_expr);
-  return 0;
-}
 \f
 static void
 check_seenlabel ()
@@ -4753,7 +4663,7 @@ add_case_node (low, high, label, duplicate)
 
   /* Add this label to the chain, and succeed.  */
 
-  r = (struct case_node *) xmalloc (sizeof (struct case_node));
+  r = (struct case_node *) ggc_alloc (sizeof (struct case_node));
   r->low = low;
 
   /* If the bounds are equal, turn this into the one-value case.  */
@@ -4943,20 +4853,20 @@ add_case_node (low, high, label, duplicate)
 /* Returns the number of possible values of TYPE.
    Returns -1 if the number is unknown, variable, or if the number does not
    fit in a HOST_WIDE_INT.
-   Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
+   Sets *SPARSENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
    do not increase monotonically (there may be duplicates);
    to 1 if the values increase monotonically, but not always by 1;
    otherwise sets it to 0.  */
 
 HOST_WIDE_INT
-all_cases_count (type, spareness)
+all_cases_count (type, sparseness)
      tree type;
-     int *spareness;
+     int *sparseness;
 {
   tree t;
   HOST_WIDE_INT count, minval, lastval;
 
-  *spareness = 0;
+  *sparseness = 0;
 
   switch (TREE_CODE (type))
     {
@@ -4995,11 +4905,12 @@ all_cases_count (type, spareness)
        {
          HOST_WIDE_INT thisval = tree_low_cst (TREE_VALUE (t), 0);
 
-         if (*spareness == 2 || thisval < lastval)
-           *spareness = 2;
+         if (*sparseness == 2 || thisval <= lastval)
+           *sparseness = 2;
          else if (thisval != minval + count)
-           *spareness = 1;
+           *sparseness = 1;
 
+         lastval = thisval;
          count++;
        }
     }
@@ -5146,16 +5057,23 @@ mark_seen_cases (type, cases_seen, count, sparseness)
     }
 }
 
-/* Called when the index of a switch statement is an enumerated type
-   and there is no default label.
+/* Given a switch statement with an expression that is an enumeration
+   type, warn if any of the enumeration type's literals are not
+   covered by the case expressions of the switch.  Also, warn if there
+   are any extra switch cases that are *not* elements of the
+   enumerated type.
+
+   Historical note:
 
-   Checks that all enumeration literals are covered by the case
-   expressions of a switch.  Also, warn if there are any extra
-   switch cases that are *not* elements of the enumerated type.
+   At one stage this function would: ``If all enumeration literals
+   were covered by the case expressions, turn one of the expressions
+   into the default expression since it should not be possible to fall
+   through such a switch.''
 
-   If all enumeration literals were covered by the case expressions,
-   turn one of the expressions into the default expression since it should
-   not be possible to fall through such a switch.  */
+   That code has since been removed as: ``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 enumeration literals.''  */
 
 void
 check_for_full_enumeration_handling (type)
@@ -5177,9 +5095,6 @@ check_for_full_enumeration_handling (type)
   /* The allocated size of cases_seen, in chars.  */
   HOST_WIDE_INT bytes_needed;
 
-  if (! warn_switch)
-    return;
-
   size = all_cases_count (type, &sparseness);
   bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
 
@@ -5195,7 +5110,7 @@ check_for_full_enumeration_handling (type)
 
       /* The time complexity of this code is normally O(N), where
         N being the number of members in the enumerated type.
-        However, if type is a ENUMERAL_TYPE whose values do not
+        However, if type is an ENUMERAL_TYPE whose values do not
         increase monotonically, O(N*log(N)) time may be needed.  */
 
       mark_seen_cases (type, cases_seen, size, sparseness);
@@ -5217,101 +5132,238 @@ check_for_full_enumeration_handling (type)
       && case_stack->data.case_stmt.case_list->left)
     case_stack->data.case_stmt.case_list
       = case_tree2list (case_stack->data.case_stmt.case_list, 0);
-  if (warn_switch)
-    for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
-      {
-       for (chain = TYPE_VALUES (type);
-            chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
-            chain = TREE_CHAIN (chain))
-         ;
+  for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
+    {
+      for (chain = TYPE_VALUES (type);
+          chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
+          chain = TREE_CHAIN (chain))
+       ;
 
-       if (!chain)
-         {
-           if (TYPE_NAME (type) == 0)
-             warning ("case value `%ld' not in enumerated type",
-                      (long) TREE_INT_CST_LOW (n->low));
-           else
-             warning ("case value `%ld' not in enumerated type `%s'",
-                      (long) 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 `%ld' not in enumerated type",
+                    (long) TREE_INT_CST_LOW (n->low));
+         else
+           warning ("case value `%ld' not in enumerated type `%s'",
+                    (long) 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 `%ld' not in enumerated type",
-                          (long) TREE_INT_CST_LOW (n->high));
-               else
-                 warning ("case value `%ld' not in enumerated type `%s'",
-                          (long) TREE_INT_CST_LOW (n->high),
-                          IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
-                                               == IDENTIFIER_NODE)
-                                              ? TYPE_NAME (type)
-                                              : DECL_NAME (TYPE_NAME (type))));
-             }
-         }
-      }
+         if (!chain)
+           {
+             if (TYPE_NAME (type) == 0)
+               warning ("case value `%ld' not in enumerated type",
+                        (long) TREE_INT_CST_LOW (n->high));
+             else
+               warning ("case value `%ld' not in enumerated type `%s'",
+                        (long) TREE_INT_CST_LOW (n->high),
+                        IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
+                                             == IDENTIFIER_NODE)
+                                            ? TYPE_NAME (type)
+                                            : DECL_NAME (TYPE_NAME (type))));
+           }
+       }
+    }
 }
 
-/* Free CN, and its children.  */
+\f
+/* Maximum number of case bit tests.  */
+#define MAX_CASE_BIT_TESTS  3
+
+/* By default, enable case bit tests on targets with ashlsi3.  */
+#ifndef CASE_USE_BIT_TESTS
+#define CASE_USE_BIT_TESTS  (ashl_optab->handlers[word_mode].insn_code \
+                            != CODE_FOR_nothing)
+#endif
+
+
+/* A case_bit_test represents a set of case nodes that may be
+   selected from using a bit-wise comparison.  HI and LO hold
+   the integer to be tested against, LABEL contains the label
+   to jump to upon success and BITS counts the number of case
+   nodes handled by this test, typically the number of bits
+   set in HI:LO.  */
+
+struct case_bit_test
+{
+  HOST_WIDE_INT hi;
+  HOST_WIDE_INT lo;
+  rtx label;
+  int bits;
+};
+
+/* Determine whether "1 << x" is relatively cheap in word_mode.  */
 
-static void 
-free_case_nodes (cn)
-     case_node_ptr cn;
+static bool lshift_cheap_p ()
 {
-  if (cn) 
+  static bool init = false;
+  static bool cheap = true;
+
+  if (!init)
     {
-      free_case_nodes (cn->left);
-      free_case_nodes (cn->right);
-      free (cn);
+      rtx reg = gen_rtx_REG (word_mode, 10000);
+      int cost = rtx_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg), SET);
+      cheap = cost < COSTS_N_INSNS (3);
+      init = true;
     }
+
+  return cheap;
 }
 
-\f
+/* Comparison function for qsort to order bit tests by decreasing
+   number of case nodes, i.e. the node with the most cases gets
+   tested first.  */
+
+static int case_bit_test_cmp (p1, p2)
+     const void *p1;
+     const void *p2;
+{
+  const struct case_bit_test *d1 = p1;
+  const struct case_bit_test *d2 = p2;
+
+  return d2->bits - d1->bits;
+}
+
+/*  Expand a switch statement by a short sequence of bit-wise
+    comparisons.  "switch(x)" is effectively converted into
+    "if ((1 << (x-MINVAL)) & CST)" where CST and MINVAL are
+    integer constants.
+
+    INDEX_EXPR is the value being switched on, which is of
+    type INDEX_TYPE.  MINVAL is the lowest case value of in
+    the case nodes, of INDEX_TYPE type, and RANGE is highest
+    value minus MINVAL, also of type INDEX_TYPE.  NODES is
+    the set of case nodes, and DEFAULT_LABEL is the label to
+    branch to should none of the cases match.
+
+    There *MUST* be MAX_CASE_BIT_TESTS or less unique case
+    node targets.  */
+
+static void
+emit_case_bit_tests (index_type, index_expr, minval, range,
+                    nodes, default_label)
+     tree index_type, index_expr, minval, range;
+     case_node_ptr nodes;
+     rtx default_label;
+{
+  struct case_bit_test test[MAX_CASE_BIT_TESTS];
+  enum machine_mode mode;
+  rtx expr, index, label;
+  unsigned int i,j,lo,hi;
+  struct case_node *n;
+  unsigned int count;
+
+  count = 0;
+  for (n = nodes; n; n = n->right)
+    {
+      label = label_rtx (n->code_label);
+      for (i = 0; i < count; i++)
+       if (same_case_target_p (label, test[i].label))
+         break;
+
+      if (i == count)
+       {
+         if (count >= MAX_CASE_BIT_TESTS)
+           abort ();
+          test[i].hi = 0;
+          test[i].lo = 0;
+         test[i].label = label;
+         test[i].bits = 1;
+         count++;
+       }
+      else
+        test[i].bits++;
+
+      lo = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+                                     n->low, minval)), 1);
+      hi = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+                                     n->high, minval)), 1);
+      for (j = lo; j <= hi; j++)
+        if (j >= HOST_BITS_PER_WIDE_INT)
+         test[i].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT);
+       else
+         test[i].lo |= (HOST_WIDE_INT) 1 << j;
+    }
+
+  qsort (test, count, sizeof(*test), case_bit_test_cmp);
+
+  index_expr = fold (build (MINUS_EXPR, index_type,
+                           convert (index_type, index_expr),
+                           convert (index_type, minval)));
+  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  mode = TYPE_MODE (index_type);
+  expr = expand_expr (range, NULL_RTX, VOIDmode, 0);
+  emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1,
+                          default_label);
+
+  index = convert_to_mode (word_mode, index, 0);
+  index = expand_binop (word_mode, ashl_optab, const1_rtx,
+                       index, NULL_RTX, 1, OPTAB_WIDEN);
+
+  for (i = 0; i < count; i++)
+    {
+      expr = immed_double_const (test[i].lo, test[i].hi, word_mode);
+      expr = expand_binop (word_mode, and_optab, index, expr,
+                          NULL_RTX, 1, OPTAB_WIDEN);
+      emit_cmp_and_jump_insns (expr, const0_rtx, NE, NULL_RTX,
+                              word_mode, 1, test[i].label);
+    }
+
+  emit_jump (default_label);
+}
 
 /* Terminate a case (Pascal) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
+   If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
+   type as given in the source before any compiler conversions.
    Generate the code to test it and jump to the right place.  */
 
 void
-expand_end_case (orig_index)
-     tree orig_index;
+expand_end_case_type (orig_index, orig_type)
+     tree orig_index, orig_type;
 {
   tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
   rtx default_label = 0;
-  struct case_node *n;
-  unsigned int count;
+  struct case_node *n, *m;
+  unsigned int count, uniq;
   rtx index;
   rtx table_label;
   int ncases;
   rtx *labelvec;
   int i;
-  rtx before_case, end;
+  rtx before_case, end, lab;
   struct nesting *thiscase = case_stack;
   tree index_expr, index_type;
+  bool exit_done = false;
   int unsignedp;
 
   /* Don't crash due to previous errors.  */
   if (thiscase == NULL)
     return;
 
-  table_label = gen_label_rtx ();
   index_expr = thiscase->data.case_stmt.index_expr;
   index_type = TREE_TYPE (index_expr);
   unsignedp = TREE_UNSIGNED (index_type);
+  if (orig_type == NULL)
+    orig_type = TREE_TYPE (orig_index);
 
   do_pending_stack_adjust ();
 
-  /* This might get an spurious warning in the presence of a syntax error;
+  /* This might get a spurious warning in the presence of a syntax error;
      it could be fixed by moving the call to check_seenlabel after the
      check for error_mark_node, and copying the code of check_seenlabel that
      deals with case_stack->data.case_stmt.line_number_status /
@@ -5323,14 +5375,18 @@ expand_end_case (orig_index)
   /* An ERROR_MARK occurs for various reasons including invalid data type.  */
   if (index_type != error_mark_node)
     {
-      /* If switch expression was an enumerated type, check that all
-        enumeration literals are covered by the cases.
-        No sense trying this if there's a default case, however.  */
-
-      if (!thiscase->data.case_stmt.default_label
-         && TREE_CODE (TREE_TYPE (orig_index)) == ENUMERAL_TYPE
+      /* If the switch expression was an enumerated type, check that
+        exactly all enumeration literals are covered by the cases.
+        The check is made when -Wswitch was specified and there is no
+        default case, or when -Wswitch-enum was specified.  */
+      if (((warn_switch && !thiscase->data.case_stmt.default_label)
+          || warn_switch_enum)
+         && TREE_CODE (orig_type) == ENUMERAL_TYPE
          && TREE_CODE (index_expr) != INTEGER_CST)
-       check_for_full_enumeration_handling (TREE_TYPE (orig_index));
+       check_for_full_enumeration_handling (orig_type);
+
+      if (warn_switch_default && !thiscase->data.case_stmt.default_label)
+       warning ("switch missing default case");
 
       /* If we don't have a default-label, create one here,
         after the body of the switch.  */
@@ -5338,6 +5394,13 @@ expand_end_case (orig_index)
        {
          thiscase->data.case_stmt.default_label
            = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+         /* Share the exit label if possible.  */
+          if (thiscase->exit_label)
+           {
+             SET_DECL_RTL (thiscase->data.case_stmt.default_label,
+                           thiscase->exit_label);
+             exit_done = true;
+           }
          expand_label (thiscase->data.case_stmt.default_label);
        }
       default_label = label_rtx (thiscase->data.case_stmt.default_label);
@@ -5351,10 +5414,13 @@ expand_end_case (orig_index)
 
       /* Simplify the case-list before we count it.  */
       group_case_nodes (thiscase->data.case_stmt.case_list);
+      strip_default_case_nodes (&thiscase->data.case_stmt.case_list,
+                               default_label);
 
       /* Get upper and lower bounds of case values.
         Also convert all the case values to the index expr's data type.  */
 
+      uniq = 0;
       count = 0;
       for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
        {
@@ -5384,6 +5450,16 @@ expand_end_case (orig_index)
          /* A range counts double, since it requires two compares.  */
          if (! tree_int_cst_equal (n->low, n->high))
            count++;
+
+         /* Count the number of unique case node targets.  */
+          uniq++;
+         lab = label_rtx (n->code_label);
+          for (m = thiscase->data.case_stmt.case_list; m != n; m = m->right)
+            if (same_case_target_p (label_rtx (m->code_label), lab))
+              {
+                uniq--;
+                break;
+              }
        }
 
       /* Compute span of values.  */
@@ -5399,6 +5475,31 @@ expand_end_case (orig_index)
          emit_jump (default_label);
        }
 
+      /* Try implementing this switch statement by a short sequence of
+        bit-wise comparisons.  However, we let the binary-tree case
+        below handle constant index expressions.  */
+      else if (CASE_USE_BIT_TESTS
+              && ! TREE_CONSTANT (index_expr)
+              && compare_tree_int (range, GET_MODE_BITSIZE (word_mode)) < 0
+              && lshift_cheap_p ()
+              && ((uniq == 1 && count >= 3)
+                  || (uniq == 2 && count >= 5)
+                  || (uniq == 3 && count >= 6)))
+       {
+         /* Optimize the case where all the case values fit in a
+            word without having to subtract MINVAL.  In this case,
+            we can optimize away the subtraction.  */
+         if (compare_tree_int (minval, 0) > 0
+             && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
+           {
+             minval = integer_zero_node;
+             range = maxval;
+           }
+         emit_case_bit_tests (index_type, index_expr, minval, range,
+                              thiscase->data.case_stmt.case_list,
+                              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
@@ -5412,9 +5513,7 @@ expand_end_case (orig_index)
 #ifndef ASM_OUTPUT_ADDR_DIFF_ELT
               || flag_pic
 #endif
-              || TREE_CODE (index_expr) == INTEGER_CST
-              || (TREE_CODE (index_expr) == COMPOUND_EXPR
-                  && TREE_CODE (TREE_OPERAND (index_expr, 1)) == INTEGER_CST))
+              || TREE_CONSTANT (index_expr))
        {
          index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
 
@@ -5487,7 +5586,7 @@ expand_end_case (orig_index)
                 default code is emitted.  */
 
              use_cost_table
-               = (TREE_CODE (TREE_TYPE (orig_index)) != ENUMERAL_TYPE
+               = (TREE_CODE (orig_type) != ENUMERAL_TYPE
                   && estimate_case_costs (thiscase->data.case_stmt.case_list));
              balance_case_nodes (&thiscase->data.case_stmt.case_list, NULL);
              emit_case_nodes (index, thiscase->data.case_stmt.case_list,
@@ -5497,26 +5596,27 @@ expand_end_case (orig_index)
        }
       else
        {
+         table_label = gen_label_rtx ();
          if (! try_casesi (index_type, index_expr, minval, range,
                            table_label, default_label))
            {
              index_type = thiscase->data.case_stmt.nominal_type;
 
-              /* Index jumptables from zero for suitable values of
+             /* Index jumptables from zero for suitable values of
                  minval to avoid a subtraction.  */
-              if (! optimize_size
-                  && compare_tree_int (minval, 0) > 0
-                  && compare_tree_int (minval, 3) < 0)
-                {
-                  minval = integer_zero_node;
-                  range = maxval;
-                }
+             if (! optimize_size
+                 && compare_tree_int (minval, 0) > 0
+                 && compare_tree_int (minval, 3) < 0)
+               {
+                 minval = integer_zero_node;
+                 range = maxval;
+               }
 
              if (! try_tablejump (index_type, index_expr, minval, range,
                                   table_label, default_label))
                abort ();
            }
-         
+
          /* Get table of labels to jump to, in order of case index.  */
 
          ncases = tree_low_cst (range, 0) + 1;
@@ -5525,18 +5625,20 @@ expand_end_case (orig_index)
 
          for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
            {
-             HOST_WIDE_INT i
-               = tree_low_cst (n->low, 0) - tree_low_cst (minval, 0);
-
-             while (1)
-               {
-                 labelvec[i]
-                   = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
-                 if (i + tree_low_cst (minval, 0)
-                     == tree_low_cst (n->high, 0))
-                   break;
-                 i++;
-               }
+             /* Compute the low and high bounds relative to the minimum
+                value since that should fit in a HOST_WIDE_INT while the
+                actual values may not.  */
+             HOST_WIDE_INT i_low
+               = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+                                            n->low, minval)), 1);
+             HOST_WIDE_INT i_high
+               = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+                                            n->high, minval)), 1);
+             HOST_WIDE_INT i;
+
+             for (i = i_low; i <= i_high; i ++)
+               labelvec[i]
+                 = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
            }
 
          /* Fill in the gaps with the default.  */
@@ -5576,10 +5678,9 @@ expand_end_case (orig_index)
   else
     end_cleanup_deferral ();
 
-  if (thiscase->exit_label)
+  if (thiscase->exit_label && !exit_done)
     emit_label (thiscase->exit_label);
 
-  free_case_nodes (case_stack->data.case_stmt.case_list);
   POPSTACK (case_stack);
 
   free_temp_slots ();
@@ -5707,6 +5808,54 @@ estimate_case_costs (node)
   return 1;
 }
 
+/* Determine whether two case labels branch to the same target.  */
+
+static bool
+same_case_target_p (l1, l2)
+     rtx l1, l2;
+{
+  rtx i1, i2;
+
+  if (l1 == l2)
+    return true;
+
+  i1 = next_real_insn (l1);
+  i2 = next_real_insn (l2);
+  if (i1 == i2)
+    return true;
+
+  if (i1 && simplejump_p (i1))
+    {
+      l1 = XEXP (SET_SRC (PATTERN (i1)), 0);
+    }
+
+  if (i2 && simplejump_p (i2))
+    {
+      l2 = XEXP (SET_SRC (PATTERN (i2)), 0);
+    }
+  return l1 == l2;
+}
+
+/* Delete nodes that branch to the default label from a list of
+   case nodes.  Eg. case 5: default: becomes just default:  */
+
+static void
+strip_default_case_nodes (prev, deflab)
+     case_node_ptr *prev;
+     rtx deflab;
+{
+  case_node_ptr ptr;
+
+  while (*prev)
+    {
+      ptr = *prev;
+      if (same_case_target_p (label_rtx (ptr->code_label), deflab))
+       *prev = ptr->right;
+      else
+       prev = &ptr->right;
+    }
+}
+
 /* Scan an ordered list of case nodes
    combining those with consecutive values or ranges.
 
@@ -5720,19 +5869,13 @@ group_case_nodes (head)
 
   while (node)
     {
-      rtx lb = next_real_insn (label_rtx (node->code_label));
-      rtx lb2;
+      rtx lab = label_rtx (node->code_label);
       case_node_ptr np = node;
 
       /* Try to group the successors of NODE with NODE.  */
       while (((np = np->right) != 0)
             /* Do they jump to the same place?  */
-            && ((lb2 = next_real_insn (label_rtx (np->code_label))) == lb
-                || (lb != 0 && lb2 != 0
-                    && simplejump_p (lb)
-                    && simplejump_p (lb2)
-                    && rtx_equal_p (SET_SRC (PATTERN (lb)),
-                                    SET_SRC (PATTERN (lb2)))))
+            && same_case_target_p (label_rtx (np->code_label), lab)
             /* Are their ranges consecutive?  */
             && tree_int_cst_equal (np->low,
                                    fold (build (PLUS_EXPR,
@@ -6349,7 +6492,7 @@ emit_case_nodes (index, node, default_label, index_type)
          else if (!low_bound && !high_bound)
            {
              /* Widen LOW and HIGH to the same width as INDEX.  */
-             tree type = type_for_mode (mode, unsignedp);
+             tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
              tree low = build1 (CONVERT_EXPR, type, node->low);
              tree high = build1 (CONVERT_EXPR, type, node->high);
              rtx low_rtx, new_index, new_bound;
@@ -6363,7 +6506,7 @@ emit_case_nodes (index, node, default_label, index_type)
              new_bound = expand_expr (fold (build (MINUS_EXPR, type,
                                                    high, low)),
                                       NULL_RTX, mode, 0);
-                               
+
              emit_cmp_and_jump_insns (new_index, new_bound, GT, NULL_RTX,
                                       mode, 1, default_label);
            }
@@ -6372,3 +6515,5 @@ emit_case_nodes (index, node, default_label, index_type)
        }
     }
 }
+
+#include "gt-stmt.h"