OSDN Git Service

Oops - forgot to include ChangeLog entry for m32r patch
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 760be9f..9a1df90 100644 (file)
@@ -1,6 +1,7 @@
 /* Expands front end tree to back end RTL for GCC
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -39,7 +40,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "expr.h"
 #include "libfuncs.h"
 #include "hard-reg-set.h"
-#include "loop.h"
 #include "recog.h"
 #include "machmode.h"
 #include "toplev.h"
@@ -111,7 +111,6 @@ static bool check_operand_nalternatives (tree, tree);
 static bool check_unique_operand_names (tree, tree);
 static char *resolve_operand_name_1 (char *, tree, tree);
 static void expand_null_return_1 (void);
-static rtx shift_return_value (rtx);
 static void expand_value_return (rtx);
 static void do_jump_if_equal (rtx, rtx, rtx, int);
 static int estimate_case_costs (case_node_ptr);
@@ -123,7 +122,8 @@ static int node_has_low_bound (case_node_ptr, tree);
 static int node_has_high_bound (case_node_ptr, tree);
 static int node_is_bounded (case_node_ptr, tree);
 static void emit_case_nodes (rtx, case_node_ptr, rtx, tree);
-static struct case_node *add_case_node (struct case_node *, tree, tree, tree);
+static struct case_node *add_case_node (struct case_node *, tree,
+                                       tree, tree, tree);
 
 \f
 /* Return the rtx-label that corresponds to a LABEL_DECL,
@@ -132,8 +132,7 @@ static struct case_node *add_case_node (struct case_node *, tree, tree, tree);
 rtx
 label_rtx (tree label)
 {
-  if (TREE_CODE (label) != LABEL_DECL)
-    abort ();
+  gcc_assert (TREE_CODE (label) == LABEL_DECL);
 
   if (!DECL_RTL_SET_P (label))
     {
@@ -155,8 +154,7 @@ force_label_rtx (tree label)
   tree function = decl_function_context (label);
   struct function *p;
 
-  if (!function)
-    abort ();
+  gcc_assert (function);
 
   if (function != current_function_decl)
     p = find_function_data (function);
@@ -241,8 +239,7 @@ expand_goto (tree label)
   /* Check for a nonlocal goto to a containing function.  Should have
      gotten translated to __builtin_nonlocal_goto.  */
   tree context = decl_function_context (label);
-  if (context != 0 && context != current_function_decl)
-    abort ();
+  gcc_assert (!context || context == current_function_decl);
 #endif
 
   emit_jump (label_rtx (label));
@@ -263,7 +260,7 @@ n_occurrences (int c, const char *s)
    or an ADDR_EXPR containing a STRING_CST.  VOL nonzero means the
    insn is volatile; don't optimize it.  */
 
-void
+static void
 expand_asm (tree string, int vol)
 {
   rtx body;
@@ -271,7 +268,8 @@ expand_asm (tree string, int vol)
   if (TREE_CODE (string) == ADDR_EXPR)
     string = TREE_OPERAND (string, 0);
 
-  body = gen_rtx_ASM_INPUT (VOIDmode, TREE_STRING_POINTER (string));
+  body = gen_rtx_ASM_INPUT (VOIDmode,
+                           ggc_strdup (TREE_STRING_POINTER (string)));
 
   MEM_VOLATILE_P (body) = vol;
 
@@ -316,7 +314,7 @@ parse_output_constraint (const char **constraint_p, int operand_num,
      message.  */
   if (!p)
     {
-      error ("output operand constraint lacks `='");
+      error ("output operand constraint lacks %<=%>");
       return false;
     }
 
@@ -325,13 +323,14 @@ parse_output_constraint (const char **constraint_p, int operand_num,
   *is_inout = (*p == '+');
 
   /* Canonicalize the output constraint so that it begins with `='.  */
-  if (p != constraint || is_inout)
+  if (p != constraint || *is_inout)
     {
       char *buf;
       size_t c_len = strlen (constraint);
 
       if (p != constraint)
-       warning ("output constraint `%c' for operand %d is not at the beginning",
+       warning ("output constraint %qc for operand %d "
+                "is not at the beginning",
                 *p, operand_num);
 
       /* Make a copy of the constraint.  */
@@ -353,13 +352,14 @@ parse_output_constraint (const char **constraint_p, int operand_num,
       {
       case '+':
       case '=':
-       error ("operand constraint contains incorrectly positioned '+' or '='");
+       error ("operand constraint contains incorrectly positioned "
+              "%<+%> or %<=%>");
        return false;
 
       case '%':
        if (operand_num + 1 == ninputs + noutputs)
          {
-           error ("`%%' constraint used with last operand");
+           error ("%<%%%> constraint used with last operand");
            return false;
          }
        break;
@@ -449,7 +449,7 @@ parse_input_constraint (const char **constraint_p, int input_num,
       case '+':  case '=':  case '&':
        if (constraint == orig_constraint)
          {
-           error ("input operand constraint contains `%c'", constraint[j]);
+           error ("input operand constraint contains %qc", constraint[j]);
            return false;
          }
        break;
@@ -458,7 +458,7 @@ parse_input_constraint (const char **constraint_p, int input_num,
        if (constraint == orig_constraint
            && input_num + 1 == ninputs - ninout)
          {
-           error ("`%%' constraint used with last operand");
+           error ("%<%%%> constraint used with last operand");
            return false;
          }
        break;
@@ -529,7 +529,7 @@ parse_input_constraint (const char **constraint_p, int input_num,
       default:
        if (! ISALPHA (constraint[j]))
          {
-           error ("invalid punctuation `%c' in constraint", constraint[j]);
+           error ("invalid punctuation %qc in constraint", constraint[j]);
            return false;
          }
        if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
@@ -558,33 +558,6 @@ parse_input_constraint (const char **constraint_p, int input_num,
   return true;
 }
 
-/* INPUT is one of the input operands from EXPR, an ASM_EXPR.  Returns true
-   if it is an operand which must be passed in memory (i.e. an "m"
-   constraint), false otherwise.  */
-
-bool
-asm_op_is_mem_input (tree input, tree expr)
-{
-  const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (input)));
-  tree outputs = ASM_OUTPUTS (expr);
-  int noutputs = list_length (outputs);
-  const char **constraints
-    = (const char **) alloca ((noutputs) * sizeof (const char *));
-  int i = 0;
-  bool allows_mem, allows_reg;
-  tree t;
-
-  /* Collect output constraints.  */
-  for (t = outputs; t ; t = TREE_CHAIN (t), i++)
-    constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
-
-  /* We pass 0 for input_num, ninputs and ninout; they are only used for
-     error checking which will be done at expand time.  */
-  parse_input_constraint (&constraint, 0, 0, noutputs, 0, constraints,
-                         &allows_mem, &allows_reg);
-  return (!allows_reg && allows_mem);
-}
-
 /* Check for overlap between registers marked in CLOBBERED_REGS and
    anything inappropriate in DECL.  Emit error and return TRUE for error,
    FALSE for ok.  */
@@ -608,7 +581,8 @@ decl_conflicts_with_clobbers_p (tree decl, const HARD_REG_SET clobbered_regs)
           regno++)
        if (TEST_HARD_REG_BIT (clobbered_regs, regno))
          {
-           error ("asm-specifier for variable `%s' conflicts with asm clobber list",
+           error ("asm-specifier for variable %qs conflicts with "
+                  "asm clobber list",
                   IDENTIFIER_POINTER (DECL_NAME (decl)));
 
            /* Reset registerness to stop multiple errors emitted for a
@@ -637,7 +611,7 @@ decl_conflicts_with_clobbers_p (tree decl, const HARD_REG_SET clobbered_regs)
 
    VOL nonzero means the insn is volatile; don't optimize it.  */
 
-void
+static void
 expand_asm_operands (tree string, tree outputs, tree inputs,
                     tree clobbers, int vol, location_t locus)
 {
@@ -696,15 +670,15 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
       if (i >= 0 || i == -4)
        ++nclobbers;
       else if (i == -2)
-       error ("unknown register name `%s' in `asm'", regname);
+       error ("unknown register name %qs in %<asm%>", regname);
 
       /* Mark clobbered registers.  */
       if (i >= 0)
         {
-         /* Clobbering the PIC register is an error */
+         /* Clobbering the PIC register is an error */
          if (i == (int) PIC_OFFSET_TABLE_REGNUM)
            {
-             error ("PIC register `%s' clobbered in `asm'", regname);
+             error ("PIC register %qs clobbered in %<asm%>", regname);
              return;
            }
 
@@ -751,7 +725,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
   ninputs += ninout;
   if (ninputs + noutputs > MAX_RECOG_OPERANDS)
     {
-      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
+      error ("more than %d operands in %<asm%>", MAX_RECOG_OPERANDS);
       return;
     }
 
@@ -785,11 +759,12 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
       bool allows_reg;
       bool allows_mem;
       rtx op;
+      bool ok;
 
-      if (!parse_output_constraint (&constraints[i], i, ninputs,
+      ok = parse_output_constraint (&constraints[i], i, ninputs,
                                    noutputs, &allows_mem, &allows_reg,
-                                   &is_inout))
-       abort ();
+                                   &is_inout);
+      gcc_assert (ok);
 
       /* 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.
@@ -851,7 +826,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
 
   body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
                                : GET_MODE (output_rtx[0])),
-                              TREE_STRING_POINTER (string),
+                              ggc_strdup (TREE_STRING_POINTER (string)),
                               empty_string, 0, argvec, constraintvec,
                               locus);
 
@@ -866,11 +841,12 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
       const char *constraint;
       tree val, type;
       rtx op;
+      bool ok;
 
       constraint = constraints[i + noutputs];
-      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
-                                   constraints, &allows_mem, &allows_reg))
-       abort ();
+      ok = parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                  constraints, &allows_mem, &allows_reg);
+      gcc_assert (ok);
 
       generating_concat_p = 0;
 
@@ -891,7 +867,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
          if (allows_reg)
            op = force_reg (TYPE_MODE (type), op);
          else if (!allows_mem)
-           warning ("asm operand %d probably doesn't match constraints",
+           warning ("asm operand %d probably doesn%'t match constraints",
                     i + noutputs);
          else if (MEM_P (op))
            {
@@ -931,7 +907,8 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
       ASM_OPERANDS_INPUT (body, i) = op;
 
       ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
-       = gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
+       = gen_rtx_ASM_INPUT (TYPE_MODE (type), 
+                            ggc_strdup (constraints[i + noutputs]));
 
       if (decl_conflicts_with_clobbers_p (val, clobbered_regs))
        clobber_conflict_found = 1;
@@ -965,7 +942,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
 
   if (noutputs == 1 && nclobbers == 0)
     {
-      ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
+      ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]);
       emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
     }
 
@@ -993,9 +970,9 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
                           output_rtx[i],
                           gen_rtx_ASM_OPERANDS
                           (GET_MODE (output_rtx[i]),
-                           TREE_STRING_POINTER (string),
-                           constraints[i], i, argvec, constraintvec,
-                           locus));
+                           ggc_strdup (TREE_STRING_POINTER (string)),
+                           ggc_strdup (constraints[i]),
+                           i, argvec, constraintvec, locus));
 
          MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
        }
@@ -1104,7 +1081,7 @@ expand_asm_expr (tree exp)
     {
       if (o[i] != TREE_VALUE (tail))
        {
-         expand_assignment (o[i], TREE_VALUE (tail), 0);
+         expand_assignment (o[i], TREE_VALUE (tail));
          free_temp_slots ();
 
          /* Restore the original value so that it's correct the next
@@ -1129,7 +1106,7 @@ check_operand_nalternatives (tree outputs, tree inputs)
 
       if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
        {
-         error ("too many alternatives in `asm'");
+         error ("too many alternatives in %<asm%>");
          return false;
        }
 
@@ -1141,7 +1118,8 @@ check_operand_nalternatives (tree outputs, tree inputs)
 
          if (n_occurrences (',', constraint) != nalternatives)
            {
-             error ("operand constraints for `asm' differ in number of alternatives");
+             error ("operand constraints for %<asm%> differ "
+                    "in number of alternatives");
              return false;
            }
 
@@ -1193,7 +1171,7 @@ check_unique_operand_names (tree outputs, tree inputs)
   return true;
 
  failure:
-  error ("duplicate asm operand name '%s'",
+  error ("duplicate asm operand name %qs",
         TREE_STRING_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
   return false;
 }
@@ -1319,7 +1297,7 @@ resolve_operand_name_1 (char *p, tree outputs, tree inputs)
     }
 
   *q = '\0';
-  error ("undefined named operand '%s'", p + 1);
+  error ("undefined named operand %qs", p + 1);
   op = 0;
  found:
 
@@ -1330,8 +1308,7 @@ resolve_operand_name_1 (char *p, tree outputs, tree inputs)
   p = strchr (p, '\0');
 
   /* Verify the no extra buffer space assumption.  */
-  if (p > q)
-    abort ();
+  gcc_assert (p <= q);
 
   /* Shift the rest of the buffer down to fill the gap.  */
   memmove (p, q + 1, strlen (q + 1) + 1);
@@ -1470,16 +1447,14 @@ warn_if_unused_value (tree exp, location_t locus)
 
     default:
       /* Referencing a volatile value is a side effect, so don't warn.  */
-      if ((DECL_P (exp)
-          || TREE_CODE_CLASS (TREE_CODE (exp)) == 'r')
+      if ((DECL_P (exp) || REFERENCE_CLASS_P (exp))
          && TREE_THIS_VOLATILE (exp))
        return 0;
 
       /* If this is an expression which has no operands, there is no value
         to be unused.  There are no such language-independent codes,
         but front ends may define such.  */
-      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'e'
-         && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
+      if (EXPRESSION_CLASS_P (exp) && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
        return 0;
 
     maybe_warn:
@@ -1525,33 +1500,6 @@ expand_naked_return (void)
   emit_jump (end_label);
 }
 
-/* If the current function returns values in the most significant part
-   of a register, shift return value VAL appropriately.  The mode of
-   the function's return type is known not to be BLKmode.  */
-
-static rtx
-shift_return_value (rtx val)
-{
-  tree type;
-
-  type = TREE_TYPE (DECL_RESULT (current_function_decl));
-  if (targetm.calls.return_in_msb (type))
-    {
-      rtx target;
-      HOST_WIDE_INT shift;
-
-      target = DECL_RTL (DECL_RESULT (current_function_decl));
-      shift = (GET_MODE_BITSIZE (GET_MODE (target))
-              - BITS_PER_UNIT * int_size_in_bytes (type));
-      if (shift > 0)
-       val = expand_shift (LSHIFT_EXPR, GET_MODE (target),
-                           gen_lowpart (GET_MODE (target), val),
-                           build_int_cst (NULL_TREE, shift, 0), target, 1);
-    }
-  return val;
-}
-
-
 /* Generate RTL to return from the current function, with value VAL.  */
 
 static void
@@ -1589,15 +1537,9 @@ expand_value_return (rtx val)
 static void
 expand_null_return_1 (void)
 {
-  rtx end_label;
-
   clear_pending_stack_adjust ();
   do_pending_stack_adjust ();
-
-  end_label = return_label;
-  if (end_label == 0)
-     end_label = return_label = gen_label_rtx ();
-  emit_jump (end_label);
+  emit_jump (return_label);
 }
 \f
 /* Generate RTL to evaluate the expression RETVAL and return it
@@ -1733,9 +1675,8 @@ expand_return (tree retval)
            if (GET_MODE_SIZE (tmpmode) >= bytes)
              break;
 
-         /* No suitable mode found.  */
-         if (tmpmode == VOIDmode)
-           abort ();
+         /* A suitable mode should have been found.  */
+         gcc_assert (tmpmode != VOIDmode);
 
          PUT_MODE (result_rtl, tmpmode);
        }
@@ -1769,7 +1710,7 @@ expand_return (tree retval)
       val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
       val = force_not_mem (val);
       /* Return the calculated value.  */
-      expand_value_return (shift_return_value (val));
+      expand_value_return (val);
     }
   else
     {
@@ -1956,8 +1897,6 @@ expand_decl (tree decl)
            mark_reg_pointer (DECL_RTL (decl),
                              TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
        }
-
-      maybe_set_unchanging (DECL_RTL (decl), decl);
     }
 
   else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
@@ -1976,9 +1915,8 @@ expand_decl (tree decl)
         to the proper address.  */
       if (DECL_RTL_SET_P (decl))
        {
-         if (!MEM_P (DECL_RTL (decl))
-             || !REG_P (XEXP (DECL_RTL (decl), 0)))
-           abort ();
+         gcc_assert (MEM_P (DECL_RTL (decl)));
+         gcc_assert (REG_P (XEXP (DECL_RTL (decl), 0)));
          oldaddr = XEXP (DECL_RTL (decl), 0);
        }
 
@@ -2055,48 +1993,6 @@ expand_stack_restore (tree var)
   emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX);
 }
 \f
-/* Emit code to perform the initialization of a declaration DECL.  */
-
-void
-expand_decl_init (tree decl)
-{
-  int was_used = TREE_USED (decl);
-
-  /* If this is a CONST_DECL, we don't have to generate any code.  Likewise
-     for static decls.  */
-  if (TREE_CODE (decl) == CONST_DECL
-      || TREE_STATIC (decl))
-    return;
-
-  /* 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 (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
-         || code == POINTER_TYPE || code == REFERENCE_TYPE)
-       expand_assignment (decl, convert (TREE_TYPE (decl), integer_zero_node),
-                          0);
-    }
-  else if (DECL_INITIAL (decl) && TREE_CODE (DECL_INITIAL (decl)) != TREE_LIST)
-    {
-      emit_line_note (DECL_SOURCE_LOCATION (decl));
-      expand_assignment (decl, DECL_INITIAL (decl), 0);
-    }
-
-  /* Don't let the initialization count as "using" the variable.  */
-  TREE_USED (decl) = was_used;
-
-  /* Free any temporaries we made while initializing the decl.  */
-  preserve_temp_slots (NULL_RTX);
-  free_temp_slots ();
-  pop_temp_slots ();
-}
-
-\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.
    In each, the TREE_VALUE is a VAR_DECL, and the TREE_PURPOSE a cleanup.  */
@@ -2124,6 +2020,7 @@ expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
     {
       tree decl_elt = TREE_VALUE (t);
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
+      rtx decl_rtl;
 
       /* If any of the elements are addressable, so is the entire
         union.  */
@@ -2141,43 +2038,79 @@ expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
        DECL_MODE (decl_elt) = mode
          = mode_for_size_tree (DECL_SIZE (decl_elt), MODE_INT, 1);
 
-      /* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
-         instead create a new MEM rtx with the proper mode.  */
-      if (MEM_P (x))
+      if (mode == GET_MODE (x))
+       decl_rtl = x;
+      else if (MEM_P (x))
+        /* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
+           instead create a new MEM rtx with the proper mode.  */
+       decl_rtl = adjust_address_nv (x, mode, 0);
+      else
        {
-         if (mode == GET_MODE (x))
-           SET_DECL_RTL (decl_elt, x);
-         else
-           SET_DECL_RTL (decl_elt, adjust_address_nv (x, mode, 0));
+         gcc_assert (REG_P (x));
+         decl_rtl = gen_lowpart_SUBREG (mode, x);
        }
-      else if (REG_P (x))
-       {
-         if (mode == GET_MODE (x))
-           SET_DECL_RTL (decl_elt, x);
-         else
-           SET_DECL_RTL (decl_elt, gen_lowpart_SUBREG (mode, x));
-       }
-      else
-       abort ();
+      SET_DECL_RTL (decl_elt, decl_rtl);
     }
 }
 \f
 /* Do the insertion of a case label into case_list.  The labels are
    fed to us in descending order from the sorted vector of case labels used
    in the tree part of the middle end.  So the list we construct is
-   sorted in ascending order.  */
+   sorted in ascending order.  The bounds on the case range, LOW and HIGH,
+   are converted to case's index type TYPE.  */
 
-struct case_node *
-add_case_node (struct case_node *head, tree low, tree high, tree label)
+static struct case_node *
+add_case_node (struct case_node *head, tree type, tree low, tree high,
+              tree label)
 {
+  tree min_value, max_value;
   struct case_node *r;
 
+  gcc_assert (TREE_CODE (low) == INTEGER_CST);
+  gcc_assert (!high || TREE_CODE (high) == INTEGER_CST);
+
+  min_value = TYPE_MIN_VALUE (type);
+  max_value = TYPE_MAX_VALUE (type);
+
   /* If there's no HIGH value, then this is not a case range; it's
      just a simple case label.  But that's just a degenerate case
      range.
      If the bounds are equal, turn this into the one-value case.  */
   if (!high || tree_int_cst_equal (low, high))
-    high = low;
+    {
+      /* If the simple case value is unreachable, ignore it.  */
+      if ((TREE_CODE (min_value) == INTEGER_CST
+            && tree_int_cst_compare (low, min_value) < 0)
+         || (TREE_CODE (max_value) == INTEGER_CST
+             && tree_int_cst_compare (low, max_value) > 0))
+       return head;
+      low = fold_convert (type, low);
+      high = low;
+    }
+  else
+    {
+      /* If the entire case range is unreachable, ignore it.  */
+      if ((TREE_CODE (min_value) == INTEGER_CST
+            && tree_int_cst_compare (high, min_value) < 0)
+         || (TREE_CODE (max_value) == INTEGER_CST
+             && tree_int_cst_compare (low, max_value) > 0))
+       return head;
+
+      /* If the lower bound is less than the index type's minimum
+        value, truncate the range bounds.  */
+      if (TREE_CODE (min_value) == INTEGER_CST
+            && tree_int_cst_compare (low, min_value) < 0)
+       low = min_value;
+      low = fold_convert (type, low);
+
+      /* If the upper bound is greater than the index type's maximum
+        value, truncate the range bounds.  */
+      if (TREE_CODE (max_value) == INTEGER_CST
+         && tree_int_cst_compare (high, max_value) > 0)
+       high = max_value;
+      high = fold_convert (type, high);
+    }
+
 
   /* Add this label to the chain.  */
   r = ggc_alloc (sizeof (struct case_node));
@@ -2282,10 +2215,9 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
 
       if (i == count)
        {
-         if (count >= MAX_CASE_BIT_TESTS)
-           abort ();
-          test[i].hi = 0;
-          test[i].lo = 0;
+         gcc_assert (count < MAX_CASE_BIT_TESTS);
+         test[i].hi = 0;
+         test[i].lo = 0;
          test[i].label = label;
          test[i].bits = 1;
          count++;
@@ -2307,8 +2239,8 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
   qsort (test, count, sizeof(*test), case_bit_test_cmp);
 
   index_expr = fold (build2 (MINUS_EXPR, index_type,
-                            convert (index_type, index_expr),
-                            convert (index_type, minval)));
+                            fold_convert (index_type, index_expr),
+                            fold_convert (index_type, minval)));
   index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
   do_pending_stack_adjust ();
 
@@ -2352,13 +2284,13 @@ expand_case (tree exp)
 {
   tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
   rtx default_label = 0;
-  struct case_node *n, *m;
+  struct case_node *n;
   unsigned int count, uniq;
   rtx index;
   rtx table_label;
   int ncases;
   rtx *labelvec;
-  int i;
+  int i, fail;
   rtx before_case, end, lab;
 
   tree vec = SWITCH_LABELS (exp);
@@ -2376,71 +2308,61 @@ expand_case (tree exp)
   struct case_node *case_list = 0;
 
   /* Label to jump to if no case matches.  */
-  tree default_label_decl = 0;
+  tree default_label_decl;
 
   /* The switch body is lowered in gimplify.c, we should never have
      switches with a non-NULL SWITCH_BODY here.  */
-  if (SWITCH_BODY (exp) || !SWITCH_LABELS (exp))
-    abort ();
+  gcc_assert (!SWITCH_BODY (exp));
+  gcc_assert (SWITCH_LABELS (exp));
 
-  for (i = TREE_VEC_LENGTH (vec); --i >= 0; )
+  do_pending_stack_adjust ();
+
+  /* An ERROR_MARK occurs for various reasons including invalid data type.  */
+  if (index_type != error_mark_node)
     {
-      tree elt = TREE_VEC_ELT (vec, i);
+      tree elt;
+      bitmap label_bitmap;
 
-      /* Handle default labels specially.  */
-      if (!CASE_HIGH (elt) && !CASE_LOW (elt))
-       {
-#ifdef ENABLE_CHECKING
-          if (default_label_decl != 0)
-            abort ();
-#endif
-          default_label_decl = CASE_LABEL (elt);
-        }
-      else
-        case_list = add_case_node (case_list, CASE_LOW (elt), CASE_HIGH (elt),
-                                  CASE_LABEL (elt));
-    }
+      /* cleanup_tree_cfg removes all SWITCH_EXPR with their index
+        expressions being INTEGER_CST.  */
+      gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
 
-  do_pending_stack_adjust ();
+      /* The default case is at the end of TREE_VEC.  */
+      elt = TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec) - 1);
+      gcc_assert (!CASE_HIGH (elt));
+      gcc_assert (!CASE_LOW (elt));
+      default_label_decl = CASE_LABEL (elt);
 
-  /* Make sure start points to something that won't need any transformation
-     before the end of this function.  */
-  if (!NOTE_P (get_last_insn ()))
-    emit_note (NOTE_INSN_DELETED);
+      for (i = TREE_VEC_LENGTH (vec) - 1; --i >= 0; )
+       {
+         elt = TREE_VEC_ELT (vec, i);
+         gcc_assert (CASE_LOW (elt));
+         case_list = add_case_node (case_list, index_type,
+                                    CASE_LOW (elt), CASE_HIGH (elt),
+                                    CASE_LABEL (elt));
+       }
 
-  start = get_last_insn ();
 
-  /* An ERROR_MARK occurs for various reasons including invalid data type.  */
-  if (index_type != error_mark_node)
-    {
-      /* If we don't have a default-label, create one here,
-        after the body of the switch.  */
-      if (default_label_decl == 0)
+      /* Make sure start points to something that won't need any
+        transformation before the end of this function.  */
+      start = get_last_insn ();
+      if (! NOTE_P (start))
        {
-         default_label_decl
-           = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-         expand_label (default_label_decl);
+         emit_note (NOTE_INSN_DELETED);
+         start = get_last_insn ();
        }
+
       default_label = label_rtx (default_label_decl);
 
       before_case = get_last_insn ();
 
-      /* 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.  */
 
       uniq = 0;
       count = 0;
+      label_bitmap = BITMAP_ALLOC (NULL);
       for (n = case_list; n; n = n->right)
        {
-         /* Check low and high label values are integers.  */
-         if (TREE_CODE (n->low) != INTEGER_CST)
-           abort ();
-         if (TREE_CODE (n->high) != INTEGER_CST)
-           abort ();
-
-         n->low = convert (index_type, n->low);
-         n->high = convert (index_type, n->high);
-
          /* Count the elements and track the largest and smallest
             of them (treating them as signed even if they are not).  */
          if (count++ == 0)
@@ -2459,38 +2381,42 @@ expand_case (tree exp)
          if (! tree_int_cst_equal (n->low, n->high))
            count++;
 
-         /* Count the number of unique case node targets.  */
-          uniq++;
+         /* If we have not seen this label yet, then increase the
+            number of unique case node targets seen.  */
          lab = label_rtx (n->code_label);
-          for (m = case_list; m != n; m = m->right)
-            if (label_rtx (m->code_label) == lab)
-              {
-                uniq--;
-                break;
-              }
+         if (!bitmap_bit_p (label_bitmap, CODE_LABEL_NUMBER (lab)))
+           {
+             bitmap_set_bit (label_bitmap, CODE_LABEL_NUMBER (lab));
+             uniq++;
+           }
        }
 
-      /* Compute span of values.  */
-      if (count != 0)
-       range = fold (build2 (MINUS_EXPR, index_type, maxval, minval));
+      BITMAP_FREE (label_bitmap);
 
+      /* cleanup_tree_cfg removes all SWITCH_EXPR with a single
+        destination, such as one with a default case only.  However,
+        it doesn't remove cases that are out of range for the switch
+        type, so we may still get a zero here.  */
       if (count == 0)
        {
-         expand_expr (index_expr, const0_rtx, VOIDmode, 0);
          emit_jump (default_label);
+         return;
        }
 
+      /* Compute span of values.  */
+      range = fold (build2 (MINUS_EXPR, index_type, maxval, minval));
+
       /* 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)))
+      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,
@@ -2498,7 +2424,7 @@ expand_case (tree exp)
          if (compare_tree_int (minval, 0) > 0
              && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
            {
-             minval = integer_zero_node;
+             minval = fold_convert (index_type, integer_zero_node);
              range = maxval;
            }
          emit_case_bit_tests (index_type, index_expr, minval, range,
@@ -2548,57 +2474,26 @@ expand_case (tree exp)
 
          if (MEM_P (index))
            index = copy_to_reg (index);
-         if (GET_CODE (index) == CONST_INT
-             || TREE_CODE (index_expr) == INTEGER_CST)
-           {
-             /* Make a tree node with the proper constant value
-                if we don't already have one.  */
-             if (TREE_CODE (index_expr) != INTEGER_CST)
-               {
-                 index_expr
-                   = build_int_cst (NULL_TREE, INTVAL (index),
-                                  unsignedp || INTVAL (index) >= 0 ? 0 : -1);
-                 index_expr = convert (index_type, index_expr);
-               }
 
-             /* For constant index expressions we need only
-                issue an unconditional branch to the appropriate
-                target code.  The job of removing any unreachable
-                code is left to the optimization phase if the
-                "-O" option is specified.  */
-             for (n = case_list; n; n = n->right)
-               if (! tree_int_cst_lt (index_expr, n->low)
-                   && ! tree_int_cst_lt (n->high, index_expr))
-                 break;
-
-             if (n)
-               emit_jump (label_rtx (n->code_label));
-             else
-               emit_jump (default_label);
-           }
-         else
-           {
-             /* If the index expression is not constant we generate
-                a binary decision tree to select the appropriate
-                target code.  This is done as follows:
+         /* We generate a binary decision tree to select the
+            appropriate target code.  This is done as follows:
 
-                The list of cases is rearranged into a binary tree,
-                nearly optimal assuming equal probability for each case.
+            The list of cases is rearranged into a binary tree,
+            nearly optimal assuming equal probability for each case.
 
-                The tree is transformed into RTL, eliminating
-                redundant test conditions at the same time.
+            The tree is transformed into RTL, eliminating
+            redundant test conditions at the same time.
 
-                If program flow could reach the end of the
-                decision tree an unconditional jump to the
-                default code is emitted.  */
+            If program flow could reach the end of the
+            decision tree an unconditional jump to the
+            default code is emitted.  */
 
-             use_cost_table
-               = (TREE_CODE (orig_type) != ENUMERAL_TYPE
-                  && estimate_case_costs (case_list));
-             balance_case_nodes (&case_list, NULL);
-             emit_case_nodes (index, case_list, default_label, index_type);
-             emit_jump (default_label);
-           }
+         use_cost_table
+           = (TREE_CODE (orig_type) != ENUMERAL_TYPE
+              && estimate_case_costs (case_list));
+         balance_case_nodes (&case_list, NULL);
+         emit_case_nodes (index, case_list, default_label, index_type);
+         emit_jump (default_label);
        }
       else
        {
@@ -2606,7 +2501,7 @@ expand_case (tree exp)
          if (! try_casesi (index_type, index_expr, minval, range,
                            table_label, default_label))
            {
-             index_type = integer_type_node;
+             bool ok;
 
              /* Index jumptables from zero for suitable values of
                  minval to avoid a subtraction.  */
@@ -2614,13 +2509,13 @@ expand_case (tree exp)
                  && compare_tree_int (minval, 0) > 0
                  && compare_tree_int (minval, 3) < 0)
                {
-                 minval = integer_zero_node;
+                 minval = fold_convert (index_type, integer_zero_node);
                  range = maxval;
                }
 
-             if (! try_tablejump (index_type, index_expr, minval, range,
-                                  table_label, default_label))
-               abort ();
+             ok = try_tablejump (index_type, index_expr, minval, range,
+                                 table_label, default_label);
+             gcc_assert (ok);
            }
 
          /* Get table of labels to jump to, in order of case index.  */
@@ -2664,20 +2559,14 @@ expand_case (tree exp)
            emit_jump_insn (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
                                              gen_rtvec_v (ncases, labelvec)));
 
-         /* If the case insn drops through the table,
-            after the table we must jump to the default-label.
-            Otherwise record no drop-through after the table.  */
-#ifdef CASE_DROPS_THROUGH
-         emit_jump (default_label);
-#else
+         /* Record no drop-through after the table.  */
          emit_barrier ();
-#endif
        }
 
       before_case = NEXT_INSN (before_case);
       end = get_last_insn ();
-      if (squeeze_notes (&before_case, &end))
-       abort ();
+      fail = squeeze_notes (&before_case, &end);
+      gcc_assert (!fail);
       reorder_insns (before_case, end, start);
     }
 
@@ -2728,8 +2617,7 @@ static int
 estimate_case_costs (case_node_ptr node)
 {
   tree min_ascii = integer_minus_one_node;
-  tree max_ascii = convert (TREE_TYPE (node->high),
-                           build_int_cst (NULL_TREE, 127, 0));
+  tree max_ascii = build_int_cst (TREE_TYPE (node->high), 127);
   case_node_ptr n;
   int i;
 
@@ -3158,11 +3046,12 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
 
       else if (node->right != 0 && node->left == 0)
        {
-         /* Here we have a right child but no left so we issue conditional
+         /* Here we have a right child but no left so we issue conditional
             branch to default and process the right child.
 
-            Omit the conditional branch to default if we it avoid only one
-            right child; it costs too much space to save so little time.  */
+            Omit the conditional branch to default if the right child
+            does not have any children and is single valued; it would
+            cost too much space to save so little time.  */
 
          if (node->right->right || node->right->left
              || !tree_int_cst_equal (node->right->low, node->right->high))