OSDN Git Service

* c-decl.c (finish_decl): When setting the DECL_ASSEMBLER_NAME
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 45ac350..fa87140 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,
 /* 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, 2002 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 
 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 "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "tree.h"
 
 #include "rtl.h"
 #include "tree.h"
@@ -54,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "ggc.h"
 #include "langhooks.h"
 #include "predict.h"
 #include "ggc.h"
 #include "langhooks.h"
 #include "predict.h"
+#include "optabs.h"
 
 /* Assume that case vectors are not pc-relative.  */
 #ifndef CASE_VECTOR_PC_RELATIVE
 
 /* Assume that case vectors are not pc-relative.  */
 #ifndef CASE_VECTOR_PC_RELATIVE
@@ -166,9 +169,6 @@ struct nesting GTY(())
          rtx start_label;
          /* Label at the end of the whole construct.  */
          rtx end_label;
          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;
          /* Label for `continue' statement to jump to;
             this is in front of the stepper of the loop.  */
          rtx continue_label;
@@ -204,8 +204,6 @@ struct nesting GTY(())
          /* Chain of labels defined inside this binding contour.
             For contours that have stack levels or cleanups.  */
          struct label_chain *label_chain;
          /* Chain of labels defined inside this binding contour.
             For contours that have stack levels or cleanups.  */
          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 an EH region.  */
          int exception_region;
          /* The saved target_temp_slot_level from our outer block.
          /* Nonzero if this is associated with an EH region.  */
          int exception_region;
          /* The saved target_temp_slot_level from our outer block.
@@ -368,10 +366,9 @@ struct stmt_status GTY(())
      always compute a value for each expr-stmt in case it is the last one.  */
   int x_expr_stmts_for_value;
 
      always compute a value for each expr-stmt in case it is the last one.  */
   int x_expr_stmts_for_value;
 
-  /* Filename and line number of last line-number note,
-     whether we actually emitted it or not.  */
-  const char *x_emit_filename;
-  int x_emit_lineno;
+  /* Location of last line-number note, whether we actually
+     emitted it or not.  */
+  location_t x_emit_locus;
 
   struct goto_fixup *x_goto_fixup_chain;
 };
 
   struct goto_fixup *x_goto_fixup_chain;
 };
@@ -387,11 +384,10 @@ struct stmt_status GTY(())
 #define last_expr_type (cfun->stmt->x_last_expr_type)
 #define last_expr_value (cfun->stmt->x_last_expr_value)
 #define expr_stmts_for_value (cfun->stmt->x_expr_stmts_for_value)
 #define last_expr_type (cfun->stmt->x_last_expr_type)
 #define last_expr_value (cfun->stmt->x_last_expr_value)
 #define expr_stmts_for_value (cfun->stmt->x_expr_stmts_for_value)
-#define emit_filename (cfun->stmt->x_emit_filename)
-#define emit_lineno (cfun->stmt->x_emit_lineno)
+#define emit_locus (cfun->stmt->x_emit_locus)
 #define goto_fixup_chain (cfun->stmt->x_goto_fixup_chain)
 
 #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 int using_eh_for_cleanups_p = 0;
 
 static int n_occurrences               PARAMS ((int, const char *));
@@ -415,10 +411,16 @@ 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 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 expand_cleanups            PARAMS ((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 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));
 static void group_case_nodes           PARAMS ((case_node_ptr));
 static void balance_case_nodes         PARAMS ((case_node_ptr *,
                                               case_node_ptr));
@@ -459,14 +461,6 @@ init_stmt_for_function ()
   clear_last_expr ();
 }
 \f
   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)
 /* Record the current file and line.  Called from emit_line_note.  */
 void
 set_file_and_line_for_stmt (file, line)
@@ -478,8 +472,8 @@ set_file_and_line_for_stmt (file, line)
      update it.  */
   if (cfun->stmt)
     {
      update it.  */
   if (cfun->stmt)
     {
-      emit_filename = file;
-      emit_lineno = line;
+      emit_locus.file = file;
+      emit_locus.line = line;
     }
 }
 
     }
 }
 
@@ -514,6 +508,29 @@ label_rtx (label)
   return DECL_RTL (label);
 }
 
   return DECL_RTL (label);
 }
 
+/* As above, but also put it on the forced-reference list of the
+   function that contains it.  */
+rtx
+force_label_rtx (label)
+     tree label;
+{
+  rtx ref = label_rtx (label);
+  tree function = decl_function_context (label);
+  struct function *p;
+
+  if (!function)
+    abort ();
+
+  if (function != current_function_decl
+      && function != inline_function_decl)
+    p = find_function_data (function);
+  else
+    p = cfun;
+
+  p->expr->x_forced_labels = gen_rtx_EXPR_LIST (VOIDmode, ref,
+                                               p->expr->x_forced_labels);
+  return ref;
+}
 
 /* Add an unconditional jump to LABEL as the next sequential instruction.  */
 
 
 /* Add an unconditional jump to LABEL as the next sequential instruction.  */
 
@@ -541,10 +558,23 @@ expand_computed_goto (exp)
 #endif
 
   emit_queue ();
 #endif
 
   emit_queue ();
-  do_pending_stack_adjust ();
-  emit_indirect_jump (x);
 
 
-  current_function_has_computed_jump = 1;
+  if (! cfun->computed_goto_common_label)
+    {
+      cfun->computed_goto_common_reg = copy_to_mode_reg (Pmode, x);
+      cfun->computed_goto_common_label = gen_label_rtx ();
+      emit_label (cfun->computed_goto_common_label);
+  
+      do_pending_stack_adjust ();
+      emit_indirect_jump (cfun->computed_goto_common_reg);
+
+      current_function_has_computed_jump = 1;
+    }
+  else
+    {
+      emit_move_insn (cfun->computed_goto_common_reg, x);
+      emit_jump (cfun->computed_goto_common_label);
+    }
 }
 \f
 /* Handle goto statements and the labels that they can go to.  */
 }
 \f
 /* Handle goto statements and the labels that they can go to.  */
@@ -724,7 +754,7 @@ expand_goto_internal (body, label, last_insn)
          /* Execute the cleanups for blocks we are exiting.  */
          if (block->data.block.cleanups != 0)
            {
          /* Execute the cleanups for blocks we are exiting.  */
          if (block->data.block.cleanups != 0)
            {
-             expand_cleanups (block->data.block.cleanups, NULL_TREE, 1, 1);
+             expand_cleanups (block->data.block.cleanups, 1, 1);
              do_pending_stack_adjust ();
            }
        }
              do_pending_stack_adjust ();
            }
        }
@@ -936,9 +966,9 @@ expand_fixups (first_insn)
    Gotos that jump out of this contour must restore the
    stack level and do the cleanups before actually jumping.
 
    Gotos that jump out of this contour must restore the
    stack level and do the cleanups before actually jumping.
 
-   DONT_JUMP_IN nonzero means report error there is a jump into this
-   contour from before the beginning of the contour.
-   This is also done if STACK_LEVEL is nonzero.  */
+   DONT_JUMP_IN positive means report error if there is a jump into this
+   contour from before the beginning of the contour.  This is also done if
+   STACK_LEVEL is nonzero unless DONT_JUMP_IN is negative.  */
 
 static void
 fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
 
 static void
 fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
@@ -980,7 +1010,8 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
             It detects only a problem with the innermost block
             around the label.  */
          if (f->target != 0
             It detects only a problem with the innermost block
             around the label.  */
          if (f->target != 0
-             && (dont_jump_in || stack_level || cleanup_list)
+             && (dont_jump_in > 0 || (dont_jump_in == 0 && stack_level)
+                 || cleanup_list)
              && INSN_UID (first_insn) < INSN_UID (f->target_rtl)
              && INSN_UID (first_insn) > INSN_UID (f->before_jump)
              && ! DECL_ERROR_ISSUED (f->target))
              && INSN_UID (first_insn) < INSN_UID (f->target_rtl)
              && INSN_UID (first_insn) > INSN_UID (f->before_jump)
              && ! DECL_ERROR_ISSUED (f->target))
@@ -1014,7 +1045,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
                if (TREE_ADDRESSABLE (lists)
                    && TREE_VALUE (lists) != 0)
                  {
                if (TREE_ADDRESSABLE (lists)
                    && TREE_VALUE (lists) != 0)
                  {
-                   expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1);
+                   expand_cleanups (TREE_VALUE (lists), 1, 1);
                    /* Pop any pushes done in the cleanups,
                       in case function is about to return.  */
                    do_pending_stack_adjust ();
                    /* Pop any pushes done in the cleanups,
                       in case function is about to return.  */
                    do_pending_stack_adjust ();
@@ -1077,7 +1108,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
              start_sequence ();
              (*lang_hooks.decls.pushlevel) (0);
              (*lang_hooks.decls.set_block) (f->context);
              start_sequence ();
              (*lang_hooks.decls.pushlevel) (0);
              (*lang_hooks.decls.set_block) (f->context);
-             expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1);
+             expand_cleanups (TREE_VALUE (lists), 1, 1);
              do_pending_stack_adjust ();
              cleanup_insns = get_insns ();
              (*lang_hooks.decls.poplevel) (1, 0, 0);
              do_pending_stack_adjust ();
              cleanup_insns = get_insns ();
              (*lang_hooks.decls.poplevel) (1, 0, 0);
@@ -1107,18 +1138,26 @@ n_occurrences (c, s)
 }
 \f
 /* Generate RTL for an asm statement (explicit assembler code).
 }
 \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
 
 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));
+
+  MEM_VOLATILE_P (body) = vol;
 
 
-  emit_insn (gen_rtx_ASM_INPUT (VOIDmode,
-                               TREE_STRING_POINTER (body)));
+  emit_insn (body);
+  
   clear_last_expr ();
 }
 
   clear_last_expr ();
 }
 
@@ -1131,7 +1170,7 @@ 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
    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.  */
 
 
    Returns TRUE if all went well; FALSE if an error occurred.  */
 
@@ -1198,7 +1237,7 @@ parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
     }
 
   /* Loop through the constraint string.  */
     }
 
   /* Loop through the constraint string.  */
-  for (p = constraint + 1; *p; ++p)
+  for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
     switch (*p)
       {
       case '+':
     switch (*p)
       {
       case '+':
@@ -1250,12 +1289,12 @@ parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
       default:
        if (!ISALPHA (*p))
          break;
       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;
          *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT
-       else if (EXTRA_ADDRESS_CONSTRAINT (*p))
+#ifdef EXTRA_CONSTRAINT_STR
+       else if (EXTRA_ADDRESS_CONSTRAINT (*p, p))
          *allows_reg = true;
          *allows_reg = true;
-       else if (EXTRA_MEMORY_CONSTRAINT (*p))
+       else if (EXTRA_MEMORY_CONSTRAINT (*p, p))
          *allows_mem = true;
        else
          {
          *allows_mem = true;
        else
          {
@@ -1298,7 +1337,7 @@ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
 
   /* Make sure constraint has neither `=', `+', nor '&'.  */
 
 
   /* Make sure constraint has neither `=', `+', nor '&'.  */
 
-  for (j = 0; j < c_len; j++)
+  for (j = 0; j < c_len; j += CONSTRAINT_LEN (constraint[j], constraint+j))
     switch (constraint[j])
       {
       case '+':  case '=':  case '&':
     switch (constraint[j])
       {
       case '+':  case '=':  case '&':
@@ -1357,10 +1396,16 @@ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
              *constraint_p = constraint;
              c_len = strlen (constraint);
              j = 0;
              *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;
              break;
            }
          else
            j = end - constraint;
+         /* Anticipate increment at end of loop.  */
+         j--;
        }
        /* Fall through.  */
 
        }
        /* Fall through.  */
 
@@ -1379,12 +1424,13 @@ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
            error ("invalid punctuation `%c' in constraint", constraint[j]);
            return false;
          }
            error ("invalid punctuation `%c' in constraint", constraint[j]);
            return false;
          }
-       if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
+       if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
+           != NO_REGS)
          *allows_reg = true;
          *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT
-       else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j]))
+#ifdef EXTRA_CONSTRAINT_STR
+       else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j], constraint + j))
          *allows_reg = true;
          *allows_reg = true;
-       else if (EXTRA_MEMORY_CONSTRAINT (constraint[j]))
+       else if (EXTRA_MEMORY_CONSTRAINT (constraint[j], constraint + j))
          *allows_mem = true;
        else
          {
          *allows_mem = true;
        else
          {
@@ -1414,6 +1460,7 @@ decl_conflicts_with_clobbers_p (decl, clobbered_regs)
      list are not allowed.  */
   if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
       && DECL_REGISTER (decl)
      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);
       && REGNO (DECL_RTL (decl)) < FIRST_PSEUDO_REGISTER)
     {
       rtx reg = DECL_RTL (decl);
@@ -1479,8 +1526,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 *));
     = (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.  */
   int old_generating_concat_p = generating_concat_p;
 
   /* An ASM with no outputs needs to be treated as volatile, for now.  */
@@ -1519,7 +1564,16 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       /* Mark clobbered registers.  */
       if (i >= 0)
 
       /* Mark clobbered registers.  */
       if (i >= 0)
-       SET_HARD_REG_BIT (clobbered_regs, i);
+        {
+         /* 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);
+       }
     }
 
   clear_last_expr ();
     }
 
   clear_last_expr ();
@@ -1596,6 +1650,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       bool is_inout;
       bool allows_reg;
       bool allows_mem;
       bool is_inout;
       bool allows_reg;
       bool allows_mem;
+      rtx op;
 
       if (!parse_output_constraint (&constraints[i], i, ninputs,
                                    noutputs, &allows_mem, &allows_reg,
 
       if (!parse_output_constraint (&constraints[i], i, ninputs,
                                    noutputs, &allows_mem, &allows_reg,
@@ -1619,24 +1674,28 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          || ! allows_reg
          || is_inout)
        {
          || ! allows_reg
          || is_inout)
        {
-         output_rtx[i] = expand_expr (val, 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);
            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)
              if (is_inout)
-               emit_move_insn (output_rtx[i], real_output_rtx[i]);
+               emit_move_insn (op, real_output_rtx[i]);
            }
        }
       else
        {
            }
        }
       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;
 
 
       generating_concat_p = old_generating_concat_p;
 
@@ -1688,6 +1747,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       /* Never pass a CONCAT to an ASM.  */
       if (GET_CODE (op) == CONCAT)
        op = force_reg (GET_MODE (op), op);
       /* Never pass a CONCAT to an ASM.  */
       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 (asm_operand_ok (op, constraint) <= 0)
        {
@@ -1697,7 +1758,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
          else if (CONSTANT_P (op))
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
          else if (CONSTANT_P (op))
-           op = force_const_mem (TYPE_MODE (type), 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
          else if (GET_CODE (op) == REG
                   || GET_CODE (op) == SUBREG
                   || GET_CODE (op) == ADDRESSOF
@@ -1707,7 +1771,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
                                                     (TYPE_QUALS (type)
                                                      | TYPE_QUAL_CONST));
              rtx memloc = assign_temp (qual_type, 1, 1, 1);
                                                     (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;
            }
              emit_move_insn (memloc, op);
              op = memloc;
            }
@@ -1773,13 +1837,13 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   if (noutputs == 1 && nclobbers == 0)
     {
       ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
   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.  */
     }
 
   else if (noutputs == 0 && nclobbers == 0)
     {
       /* No output operands: put in a raw ASM_OPERANDS rtx.  */
-      insn = emit_insn (body);
+      emit_insn (body);
     }
 
   else
     }
 
   else
@@ -1866,7 +1930,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            = gen_rtx_CLOBBER (VOIDmode, clobbered_reg);
        }
 
            = gen_rtx_CLOBBER (VOIDmode, clobbered_reg);
        }
 
-      insn = emit_insn (body);
+      emit_insn (body);
     }
 
   /* For any outputs that needed reloading into registers, spill them
     }
 
   /* For any outputs that needed reloading into registers, spill them
@@ -2122,7 +2186,7 @@ expand_expr_stmt_value (exp, want_value, maybe_last)
   if (want_value == -1)
     want_value = expr_stmts_for_value != 0;
 
   if (want_value == -1)
     want_value = expr_stmts_for_value != 0;
 
-  /* If -W, warn about statements with no side effects,
+  /* If -Wextra, warn about statements with no side effects,
      except for an explicit cast to void (e.g. for assert()), and
      except for last statement in ({...}) where they may be useful.  */
   if (! want_value
      except for an explicit cast to void (e.g. for assert()), and
      except for last statement in ({...}) where they may be useful.  */
   if (! want_value
@@ -2131,11 +2195,10 @@ expand_expr_stmt_value (exp, want_value, maybe_last)
     {
       if (! TREE_SIDE_EFFECTS (exp))
        {
     {
       if (! TREE_SIDE_EFFECTS (exp))
        {
-         if ((extra_warnings || warn_unused_value)
+         if (warn_unused_value
              && !(TREE_CODE (exp) == CONVERT_EXPR
                   && VOID_TYPE_P (TREE_TYPE (exp))))
              && !(TREE_CODE (exp) == CONVERT_EXPR
                   && VOID_TYPE_P (TREE_TYPE (exp))))
-           warning_with_file_and_line (emit_filename, emit_lineno,
-                                       "statement with no effect");
+           warning ("%Hstatement with no effect", &emit_locus);
        }
       else if (warn_unused_value)
        warn_if_unused_value (exp);
        }
       else if (warn_unused_value)
        warn_if_unused_value (exp);
@@ -2295,8 +2358,7 @@ warn_if_unused_value (exp)
       if (TREE_SIDE_EFFECTS (exp))
        return 0;
 
       if (TREE_SIDE_EFFECTS (exp))
        return 0;
 
-      warning_with_file_and_line (emit_filename, emit_lineno,
-                                 "value computed is not used");
+      warning ("%Hvalue computed is not used", &emit_locus);
       return 1;
     }
 }
       return 1;
     }
 }
@@ -2494,7 +2556,6 @@ expand_start_loop (exit_flag)
   thisloop->depth = ++nesting_depth;
   thisloop->data.loop.start_label = gen_label_rtx ();
   thisloop->data.loop.end_label = gen_label_rtx ();
   thisloop->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;
   thisloop->data.loop.continue_label = thisloop->data.loop.start_label;
   thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0;
   loop_stack = thisloop;
@@ -2536,7 +2597,6 @@ expand_start_null_loop ()
   thisloop->depth = ++nesting_depth;
   thisloop->data.loop.start_label = emit_note (NULL, NOTE_INSN_DELETED);
   thisloop->data.loop.end_label = gen_label_rtx ();
   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;
   thisloop->data.loop.continue_label = thisloop->data.loop.end_label;
   thisloop->exit_label = thisloop->data.loop.end_label;
   loop_stack = thisloop;
@@ -2567,6 +2627,7 @@ expand_end_loop ()
   rtx start_label = loop_stack->data.loop.start_label;
   rtx etc_note;
   int eh_regions, debug_blocks;
   rtx start_label = loop_stack->data.loop.start_label;
   rtx etc_note;
   int eh_regions, debug_blocks;
+  bool empty_test;
 
   /* Mark the continue-point at the top of the loop if none elsewhere.  */
   if (start_label == loop_stack->data.loop.continue_label)
 
   /* Mark the continue-point at the top of the loop if none elsewhere.  */
   if (start_label == loop_stack->data.loop.continue_label)
@@ -2599,7 +2660,7 @@ expand_end_loop ()
        end_label:
 
      We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
        end_label:
 
      We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
-     the end of the entry condtional.  Without this, our lexical scan
+     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
      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
@@ -2610,6 +2671,7 @@ expand_end_loop ()
 
   /* Scan insns from the top of the loop looking for the END_TOP_COND note.  */
 
 
   /* 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)
   eh_regions = debug_blocks = 0;
   for (etc_note = start_label; etc_note ; etc_note = NEXT_INSN (etc_note))
     if (GET_CODE (etc_note) == NOTE)
@@ -2650,9 +2712,12 @@ expand_end_loop ()
        else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_END)
          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
 
   if (etc_note
       && optimize
+      && ! empty_test
       && eh_regions == 0
       && (debug_blocks == 0 || optimize >= 2)
       && NEXT_INSN (etc_note) != NULL_RTX
       && eh_regions == 0
       && (debug_blocks == 0 || optimize >= 2)
       && NEXT_INSN (etc_note) != NULL_RTX
@@ -2734,8 +2799,11 @@ expand_continue_loop (whichloop)
   /* Emit information for branch prediction.  */
   rtx note;
 
   /* Emit information for branch prediction.  */
   rtx note;
 
-  note = emit_note (NULL, NOTE_INSN_PREDICTION);
-  NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
+  if (flag_guess_branch_prob)
+    {
+      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;
   clear_last_expr ();
   if (whichloop == 0)
     whichloop = loop_stack;
@@ -2771,22 +2839,32 @@ expand_exit_loop_if_false (whichloop, cond)
      struct nesting *whichloop;
      tree cond;
 {
      struct nesting *whichloop;
      tree cond;
 {
-  rtx label = gen_label_rtx ();
-  rtx last_insn;
+  rtx label;
   clear_last_expr ();
 
   if (whichloop == 0)
     whichloop = loop_stack;
   if (whichloop == 0)
     return 0;
   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.  */
 
   /* 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);
   expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
                        NULL_RTX);
   emit_label (label);
@@ -2810,17 +2888,6 @@ expand_exit_loop_top_cond (whichloop, cond)
   return 1;
 }
 
   return 1;
 }
 
-/* Return nonzero if the loop nest is empty.  Else return zero.  */
-
-int
-stmt_loop_nest_empty ()
-{
-  /* 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);
-}
-
 /* 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.
 /* 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.
@@ -2928,7 +2995,8 @@ expand_value_return (val)
   rtx return_reg;
   enum br_predictor pred;
 
   rtx return_reg;
   enum br_predictor pred;
 
-  if ((pred = return_prediction (val)) != PRED_NO_PREDICTION)
+  if (flag_guess_branch_prob
+      && (pred = return_prediction (val)) != PRED_NO_PREDICTION)
     {
       /* Emit information for branch prediction.  */
       rtx note;
     {
       /* Emit information for branch prediction.  */
       rtx note;
@@ -3105,7 +3173,6 @@ expand_return (retval)
         machine, this means we must skip the empty high order bytes when
         calculating the bit offset.  */
       if (BYTES_BIG_ENDIAN
         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));
          && bytes % UNITS_PER_WORD)
        big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
                                                  * BITS_PER_UNIT));
@@ -3204,18 +3271,6 @@ expand_return (retval)
       expand_value_return (result_rtl);
     }
 }
       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
 \f
 /* Attempt to optimize a potential tail recursion call into a goto.
    ARGUMENTS are the arguments to a CALL_EXPR; LAST_INSN indicates
@@ -3310,8 +3365,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
       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];
+         int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (a)));
+         promote_mode(TREE_TYPE (TREE_VALUE (a)), GET_MODE (tmp),
+                      &unsignedp, 0);
+         if (DECL_MODE (f) != GET_MODE (DECL_RTL (f)))
+           {
+             tmp = gen_reg_rtx (DECL_MODE (f));
+             convert_move (tmp, argvec[i], unsignedp);
+           }
+         convert_move (DECL_RTL (f), tmp, unsignedp);
+       }
     }
 
   free_temp_slots ();
     }
 
   free_temp_slots ();
@@ -3370,7 +3435,6 @@ expand_start_bindings_and_block (flags, block)
   thisblock->depth = ++nesting_depth;
   thisblock->data.block.stack_level = 0;
   thisblock->data.block.cleanups = 0;
   thisblock->depth = ++nesting_depth;
   thisblock->data.block.stack_level = 0;
   thisblock->data.block.cleanups = 0;
-  thisblock->data.block.n_function_calls = 0;
   thisblock->data.block.exception_region = 0;
   thisblock->data.block.block_target_temp_slot_level = target_temp_slot_level;
 
   thisblock->data.block.exception_region = 0;
   thisblock->data.block.block_target_temp_slot_level = target_temp_slot_level;
 
@@ -3667,8 +3731,10 @@ warn_about_unused_variables (vars)
    MARK_ENDS is nonzero if we should put a note at the beginning
    and end of this binding contour.
 
    MARK_ENDS is nonzero if we should put a note at the beginning
    and end of this binding contour.
 
-   DONT_JUMP_IN is nonzero if it is not valid to jump into this contour.
-   (That is true automatically if the contour has a saved stack level.)  */
+   DONT_JUMP_IN is positive if it is not valid to jump into this contour,
+   zero if we can jump into this contour only if it does not have a saved
+   stack level, and negative if we are not to check for invalid use of
+   labels (because the front end does that).  */
 
 void
 expand_end_bindings (vars, mark_ends, dont_jump_in)
 
 void
 expand_end_bindings (vars, mark_ends, dont_jump_in)
@@ -3690,8 +3756,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
 
   /* If necessary, make handlers for nonlocal gotos taking
      place in the function calls in this block.  */
 
   /* If necessary, make handlers for nonlocal gotos taking
      place in the function calls in this block.  */
-  if (function_call_count != thisblock->data.block.n_function_calls
-      && nonlocal_labels
+  if (function_call_count != 0 && nonlocal_labels
       /* Make handler for outermost block
         if there were any nonlocal gotos to this function.  */
       && (thisblock->next == 0 ? current_function_has_nonlocal_label
       /* Make handler for outermost block
         if there were any nonlocal gotos to this function.  */
       && (thisblock->next == 0 ? current_function_has_nonlocal_label
@@ -3703,8 +3768,8 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
 
   /* Don't allow jumping into a block that has a stack level.
      Cleanups are allowed, though.  */
 
   /* Don't allow jumping into a block that has a stack level.
      Cleanups are allowed, though.  */
-  if (dont_jump_in
-      || thisblock->data.block.stack_level != 0)
+  if (dont_jump_in > 0
+      || (dont_jump_in == 0 && thisblock->data.block.stack_level != 0))
     {
       struct label_chain *chain;
 
     {
       struct label_chain *chain;
 
@@ -3745,7 +3810,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       reachable = (! insn || GET_CODE (insn) != BARRIER);
 
       /* Do the cleanups.  */
       reachable = (! insn || GET_CODE (insn) != BARRIER);
 
       /* Do the cleanups.  */
-      expand_cleanups (thisblock->data.block.cleanups, NULL_TREE, 0, reachable);
+      expand_cleanups (thisblock->data.block.cleanups, 0, reachable);
       if (reachable)
        do_pending_stack_adjust ();
 
       if (reachable)
        do_pending_stack_adjust ();
 
@@ -3823,7 +3888,6 @@ void
 expand_decl (decl)
      tree decl;
 {
 expand_decl (decl)
      tree decl;
 {
-  struct nesting *thisblock;
   tree type;
 
   type = TREE_TYPE (decl);
   tree type;
 
   type = TREE_TYPE (decl);
@@ -3849,8 +3913,6 @@ expand_decl (decl)
   if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
     return;
 
   if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
     return;
 
-  thisblock = block_stack;
-
   /* Create the RTL representation for the variable.  */
 
   if (type == error_mark_node)
   /* Create the RTL representation for the variable.  */
 
   if (type == error_mark_node)
@@ -3877,6 +3939,7 @@ expand_decl (decl)
           && !(flag_float_store
                && TREE_CODE (type) == REAL_TYPE)
           && ! TREE_THIS_VOLATILE (decl)
           && !(flag_float_store
                && TREE_CODE (type) == REAL_TYPE)
           && ! TREE_THIS_VOLATILE (decl)
+          && ! DECL_NONLOCAL (decl)
           && (DECL_REGISTER (decl) || optimize))
     {
       /* Automatic variable that can go in a register.  */
           && (DECL_REGISTER (decl) || optimize))
     {
       /* Automatic variable that can go in a register.  */
@@ -3886,14 +3949,6 @@ expand_decl (decl)
 
       SET_DECL_RTL (decl, gen_reg_rtx (reg_mode));
 
 
       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))
       mark_user_reg (DECL_RTL (decl));
 
       if (POINTER_TYPE_P (type))
@@ -3904,7 +3959,7 @@ expand_decl (decl)
 
       /* If something wants our address, try to use ADDRESSOF.  */
       if (TREE_ADDRESSABLE (decl))
 
       /* If something wants our address, try to use ADDRESSOF.  */
       if (TREE_ADDRESSABLE (decl))
-       put_var_into_stack (decl);
+       put_var_into_stack (decl, /*rescan=*/false);
     }
 
   else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
     }
 
   else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
@@ -4004,6 +4059,8 @@ expand_decl_init (decl)
 
   /* Compute and store the initial value now.  */
 
 
   /* Compute and store the initial value now.  */
 
+  push_temp_slots ();
+
   if (DECL_INITIAL (decl) == error_mark_node)
     {
       enum tree_code code = TREE_CODE (TREE_TYPE (decl));
   if (DECL_INITIAL (decl) == error_mark_node)
     {
       enum tree_code code = TREE_CODE (TREE_TYPE (decl));
@@ -4027,6 +4084,7 @@ expand_decl_init (decl)
   /* Free any temporaries we made while initializing the decl.  */
   preserve_temp_slots (NULL_RTX);
   free_temp_slots ();
   /* Free any temporaries we made while initializing the decl.  */
   preserve_temp_slots (NULL_RTX);
   free_temp_slots ();
+  pop_temp_slots ();
 }
 
 /* CLEANUP is an expression to be executed at exit from this binding contour;
 }
 
 /* CLEANUP is an expression to be executed at exit from this binding contour;
@@ -4229,11 +4287,6 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
 /* Expand a list of cleanups LIST.
    Elements may be expressions or may be nested lists.
 
 /* Expand a list of cleanups LIST.
    Elements may be expressions or may be nested lists.
 
-   If DONT_DO is nonnull, then any list-element
-   whose TREE_PURPOSE matches DONT_DO is omitted.
-   This is sometimes used to avoid a cleanup associated with
-   a value that is being returned out of the scope.
-
    If IN_FIXUP is nonzero, we are generating this cleanup for a fixup
    goto and handle protection regions specially in that case.
 
    If IN_FIXUP is nonzero, we are generating this cleanup for a fixup
    goto and handle protection regions specially in that case.
 
@@ -4241,48 +4294,44 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
    code about this finalization.  */
 
 static void
    code about this finalization.  */
 
 static void
-expand_cleanups (list, dont_do, in_fixup, reachable)
+expand_cleanups (list, in_fixup, reachable)
      tree list;
      tree list;
-     tree dont_do;
      int in_fixup;
      int reachable;
 {
   tree tail;
   for (tail = list; tail; tail = TREE_CHAIN (tail))
      int in_fixup;
      int reachable;
 {
   tree tail;
   for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (dont_do == 0 || TREE_PURPOSE (tail) != dont_do)
+    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
+      expand_cleanups (TREE_VALUE (tail), in_fixup, reachable);
+    else
       {
       {
-       if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-         expand_cleanups (TREE_VALUE (tail), dont_do, in_fixup, reachable);
-       else
-         {
-           if (! in_fixup && using_eh_for_cleanups_p)
-             expand_eh_region_end_cleanup (TREE_VALUE (tail));
+       if (! in_fixup && using_eh_for_cleanups_p)
+         expand_eh_region_end_cleanup (TREE_VALUE (tail));
 
 
-           if (reachable && !CLEANUP_EH_ONLY (tail))
+       if (reachable && !CLEANUP_EH_ONLY (tail))
+         {
+           /* Cleanups may be run multiple times.  For example,
+              when exiting a binding contour, we expand the
+              cleanups associated with that contour.  When a goto
+              within that binding contour has a target outside that
+              contour, it will expand all cleanups from its scope to
+              the target.  Though the cleanups are expanded multiple
+              times, the control paths are non-overlapping so the
+              cleanups will not be executed twice.  */
+
+           /* We may need to protect from outer cleanups.  */
+           if (in_fixup && using_eh_for_cleanups_p)
              {
              {
-               /* Cleanups may be run multiple times.  For example,
-                  when exiting a binding contour, we expand the
-                  cleanups associated with that contour.  When a goto
-                  within that binding contour has a target outside that
-                  contour, it will expand all cleanups from its scope to
-                  the target.  Though the cleanups are expanded multiple
-                  times, the control paths are non-overlapping so the
-                  cleanups will not be executed twice.  */
-
-               /* We may need to protect from outer cleanups.  */
-               if (in_fixup && using_eh_for_cleanups_p)
-                 {
-                   expand_eh_region_start ();
+               expand_eh_region_start ();
 
 
-                   expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
+               expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
 
 
-                   expand_eh_region_end_fixup (TREE_VALUE (tail));
-                 }
-               else
-                 expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
-               free_temp_slots ();
+               expand_eh_region_end_fixup (TREE_VALUE (tail));
              }
              }
+           else
+             expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
+
+           free_temp_slots ();
          }
       }
 }
          }
       }
 }
@@ -4316,24 +4365,6 @@ end_cleanup_deferral ()
     --block_stack->data.block.conditional_code;
 }
 
     --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 ()
 {
 tree
 last_cleanup_this_contour ()
 {
@@ -4407,6 +4438,7 @@ expand_start_case (exit_flag, expr, type, printname)
   nesting_stack = thiscase;
 
   do_pending_stack_adjust ();
   nesting_stack = thiscase;
 
   do_pending_stack_adjust ();
+  emit_queue ();
 
   /* Make sure case_stmt.start points to something that won't
      need any transformation before expand_end_case.  */
 
   /* Make sure case_stmt.start points to something that won't
      need any transformation before expand_end_case.  */
@@ -4443,26 +4475,6 @@ expand_start_case_dummy ()
   nesting_stack = thiscase;
   start_cleanup_deferral ();
 }
   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 ()
 \f
 static void
 check_seenlabel ()
@@ -4491,10 +4503,13 @@ check_seenlabel ()
 
              /* If insn is zero, then there must have been a syntax error.  */
              if (insn)
 
              /* If insn is zero, then there must have been a syntax error.  */
              if (insn)
-               warning_with_file_and_line (NOTE_SOURCE_FILE (insn),
-                                           NOTE_LINE_NUMBER (insn),
-                                           "unreachable code at beginning of %s",
-                                           case_stack->data.case_stmt.printname);
+                {
+                  location_t locus;
+                  locus.file = NOTE_SOURCE_FILE (insn);
+                  locus.line = NOTE_LINE_NUMBER (insn);
+                  warning ("%Hunreachable code at beginning of %s", &locus,
+                           case_stack->data.case_stmt.printname);
+                }
              break;
            }
        }
              break;
            }
        }
@@ -5196,6 +5211,154 @@ check_for_full_enumeration_handling (type)
 }
 
 \f
 }
 
 \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 bool lshift_cheap_p ()
+{
+  static bool init = false;
+  static bool cheap = true;
+
+  if (!init)
+    {
+      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;
+}
+
+/* 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.
 
 /* Terminate a case (Pascal) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
@@ -5209,23 +5372,23 @@ expand_end_case_type (orig_index, orig_type)
 {
   tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
   rtx default_label = 0;
 {
   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 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;
   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;
 
   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);
   index_expr = thiscase->data.case_stmt.index_expr;
   index_type = TREE_TYPE (index_expr);
   unsignedp = TREE_UNSIGNED (index_type);
@@ -5234,7 +5397,7 @@ expand_end_case_type (orig_index, orig_type)
 
   do_pending_stack_adjust ();
 
 
   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 /
      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 /
@@ -5265,6 +5428,13 @@ expand_end_case_type (orig_index, orig_type)
        {
          thiscase->data.case_stmt.default_label
            = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
        {
          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);
          expand_label (thiscase->data.case_stmt.default_label);
        }
       default_label = label_rtx (thiscase->data.case_stmt.default_label);
@@ -5278,10 +5448,13 @@ expand_end_case_type (orig_index, orig_type)
 
       /* Simplify the case-list before we count it.  */
       group_case_nodes (thiscase->data.case_stmt.case_list);
 
       /* 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.  */
 
 
       /* 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)
        {
       count = 0;
       for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
        {
@@ -5311,6 +5484,16 @@ expand_end_case_type (orig_index, orig_type)
          /* A range counts double, since it requires two compares.  */
          if (! tree_int_cst_equal (n->low, n->high))
            count++;
          /* 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.  */
        }
 
       /* Compute span of values.  */
@@ -5326,6 +5509,32 @@ expand_end_case_type (orig_index, orig_type)
          emit_jump (default_label);
        }
 
          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
+              && compare_tree_int (range, 0) > 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
       /* 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
@@ -5339,9 +5548,7 @@ expand_end_case_type (orig_index, orig_type)
 #ifndef ASM_OUTPUT_ADDR_DIFF_ELT
               || flag_pic
 #endif
 #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);
 
        {
          index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
 
@@ -5424,6 +5631,7 @@ expand_end_case_type (orig_index, orig_type)
        }
       else
        {
        }
       else
        {
+         table_label = gen_label_rtx ();
          if (! try_casesi (index_type, index_expr, minval, range,
                            table_label, default_label))
            {
          if (! try_casesi (index_type, index_expr, minval, range,
                            table_label, default_label))
            {
@@ -5505,7 +5713,7 @@ expand_end_case_type (orig_index, orig_type)
   else
     end_cleanup_deferral ();
 
   else
     end_cleanup_deferral ();
 
-  if (thiscase->exit_label)
+  if (thiscase->exit_label && !exit_done)
     emit_label (thiscase->exit_label);
 
   POPSTACK (case_stack);
     emit_label (thiscase->exit_label);
 
   POPSTACK (case_stack);
@@ -5635,6 +5843,54 @@ estimate_case_costs (node)
   return 1;
 }
 
   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.
 
 /* Scan an ordered list of case nodes
    combining those with consecutive values or ranges.
 
@@ -5648,19 +5904,13 @@ group_case_nodes (head)
 
   while (node)
     {
 
   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?  */
       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,
             /* Are their ranges consecutive?  */
             && tree_int_cst_equal (np->low,
                                    fold (build (PLUS_EXPR,