OSDN Git Service

* config/h8300/h8300.c (h8300_adjust_insn_length): Clean up.
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 76fa439..b41b62b 100644 (file)
@@ -1,6 +1,6 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -110,7 +110,7 @@ static int cost_table_initialized;
 
 /* Special care is needed because we allow -1, but TREE_INT_CST_LOW
    is unsigned.  */
-#define COST_TABLE(I)  cost_table_[(unsigned HOST_WIDE_INT)((I) + 1)]
+#define COST_TABLE(I)  cost_table_[(unsigned HOST_WIDE_INT) ((I) + 1)]
 \f
 /* Stack of control and binding constructs we are currently inside.
 
@@ -397,6 +397,9 @@ struct stmt_status
 static int using_eh_for_cleanups_p = 0;
 
 static int n_occurrences               PARAMS ((int, const char *));
+static bool parse_input_constraint     PARAMS ((const char **, int, int, int,
+                                                int, const char * const *,
+                                                bool *, bool *));
 static void expand_goto_internal       PARAMS ((tree, rtx, rtx));
 static int expand_fixup                        PARAMS ((tree, rtx, rtx));
 static rtx expand_nl_handler_label     PARAMS ((rtx, rtx));
@@ -712,11 +715,6 @@ expand_computed_goto (exp)
 #endif
 
   emit_queue ();
-  /* Be sure the function is executable.  */
-  if (current_function_check_memory_usage)
-    emit_library_call (chkr_check_exec_libfunc, LCT_CONST_MAKE_BLOCK,
-                      VOIDmode, 1, x, ptr_mode);
-
   do_pending_stack_adjust ();
   emit_indirect_jump (x);
 
@@ -1290,12 +1288,6 @@ void
 expand_asm (body)
      tree body;
 {
-  if (current_function_check_memory_usage)
-    {
-      error ("`asm' cannot be used in function where memory usage is checked");
-      return;
-    }
-
   if (TREE_CODE (body) == ADDR_EXPR)
     body = TREE_OPERAND (body, 0);
 
@@ -1318,13 +1310,8 @@ expand_asm (body)
    Returns TRUE if all went well; FALSE if an error occurred.  */
 
 bool
-parse_output_constraint (constraint_p, 
-                        operand_num,
-                        ninputs,
-                        noutputs,
-                        allows_mem, 
-                        allows_reg, 
-                        is_inout)
+parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
+                        allows_mem, allows_reg, is_inout)
      const char **constraint_p;
      int operand_num;
      int ninputs;
@@ -1390,7 +1377,7 @@ parse_output_constraint (constraint_p,
       {
       case '+':
       case '=':
-       error ("operand constraint contains '+' or '=' at illegal position.");
+       error ("operand constraint contains incorrectly positioned '+' or '='");
        return false;
        
       case '%':
@@ -1455,6 +1442,131 @@ parse_output_constraint (constraint_p,
   return true;
 }
 
+/* Similar, but for input constraints.  */
+
+static bool
+parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
+                       constraints, allows_mem, allows_reg)
+     const char **constraint_p;
+     int input_num;
+     int ninputs;
+     int noutputs;
+     int ninout;
+     const char * const * constraints;
+     bool *allows_mem;
+     bool *allows_reg;
+{
+  const char *constraint = *constraint_p;
+  const char *orig_constraint = constraint;
+  size_t c_len = strlen (constraint);
+  size_t j;
+
+  /* Assume the constraint doesn't allow the use of either
+     a register or memory.  */
+  *allows_mem = false;
+  *allows_reg = false;
+
+  /* Make sure constraint has neither `=', `+', nor '&'.  */
+
+  for (j = 0; j < c_len; j++)
+    switch (constraint[j])
+      {
+      case '+':  case '=':  case '&':
+       if (constraint == orig_constraint)
+         {
+           error ("input operand constraint contains `%c'", constraint[j]);
+           return false;
+         }
+       break;
+
+      case '%':
+       if (constraint == orig_constraint
+           && input_num + 1 == ninputs - ninout)
+         {
+           error ("`%%' constraint used with last operand");
+           return false;
+         }
+       break;
+
+      case 'V':  case 'm':  case 'o':
+       *allows_mem = true;
+       break;
+
+      case '<':  case '>':
+      case '?':  case '!':  case '*':  case '#':
+      case 'E':  case 'F':  case 'G':  case 'H':
+      case 's':  case 'i':  case 'n':
+      case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
+      case 'N':  case 'O':  case 'P':  case ',':
+       break;
+
+       /* Whether or not a numeric constraint allows a register is
+          decided by the matching constraint, and so there is no need
+          to do anything special with them.  We must handle them in
+          the default case, so that we don't unnecessarily force
+          operands to memory.  */
+      case '0':  case '1':  case '2':  case '3':  case '4':
+      case '5':  case '6':  case '7':  case '8':  case '9':
+       {
+         char *end;
+         unsigned long match;
+
+         match = strtoul (constraint + j, &end, 10);
+         if (match >= (unsigned long) noutputs)
+           {
+             error ("matching constraint references invalid operand number");
+             return false;
+           }
+
+         /* Try and find the real constraint for this dup.  Only do this
+            if the matching constraint is the only alternative.  */
+         if (*end == '\0'
+             && (j == 0 || (j == 1 && constraint[0] == '%')))
+           {
+             constraint = constraints[match];
+             *constraint_p = constraint;
+             c_len = strlen (constraint);
+             j = 0;
+             break;
+           }
+         else
+           j = end - constraint;
+       }
+       /* Fall through.  */
+
+      case 'p':  case 'r':
+       *allows_reg = true;
+       break;
+
+      case 'g':  case 'X':
+       *allows_reg = true;
+       *allows_mem = true;
+       break;
+
+      default:
+       if (! ISALPHA (constraint[j]))
+         {
+           error ("invalid punctuation `%c' in constraint", constraint[j]);
+           return false;
+         }
+       if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
+         *allows_reg = true;
+#ifdef EXTRA_CONSTRAINT
+       else
+         {
+           /* Otherwise we can't assume anything about the nature of
+              the constraint except that it isn't purely registers.
+              Treat it like "g" and hope for the best.  */
+           *allows_reg = true;
+           *allows_mem = true;
+         }
+#endif
+       break;
+      }
+
+  return true;
+}
+
 /* Generate RTL for an asm statement with arguments.
    STRING is the instruction template.
    OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
@@ -1483,7 +1595,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   rtx body;
   int ninputs = list_length (inputs);
   int noutputs = list_length (outputs);
-  int ninout = 0;
+  int ninout;
   int nclobbers;
   tree tail;
   int i;
@@ -1503,12 +1615,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   if (noutputs == 0)
     vol = 1;
 
-  if (current_function_check_memory_usage)
-    {
-      error ("`asm' cannot be used in function where memory usage is checked");
-      return;
-    }
-
   if (! check_operand_nalternatives (outputs, inputs))
     return;
 
@@ -1520,7 +1626,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 #ifdef MD_ASM_CLOBBERS
   /* Sometimes we wish to automatically clobber registers across an asm.
      Case in point is when the i386 backend moved from cc0 to a hard reg --
-     maintaining source-level compatability means automatically clobbering
+     maintaining source-level compatibility means automatically clobbering
      the flags register.  */
   MD_ASM_CLOBBERS (clobbers);
 #endif
@@ -1541,10 +1647,15 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   last_expr_type = 0;
 
+  /* First pass over inputs and outputs checks validity and sets
+     mark_addressable if needed.  */
+
+  ninout = 0;
   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
     {
       tree val = TREE_VALUE (tail);
       tree type = TREE_TYPE (val);
+      const char *constraint;
       bool is_inout;
       bool allows_reg;
       bool allows_mem;
@@ -1553,22 +1664,67 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       if (type == error_mark_node)
        return;
 
-      /* Make sure constraint has `=' and does not have `+'.  Also, see
-        if it allows any register.  Be liberal on the latter test, since
-        the worst that happens if we get it wrong is we issue an error
-        message.  */
-
       /* Try to parse the output constraint.  If that fails, there's
         no point in going further.  */
-      if (!parse_output_constraint (&constraints[i],
-                                   i,
-                                   ninputs,
-                                   noutputs,
-                                   &allows_mem,
-                                   &allows_reg,
-                                   &is_inout))
+      constraint = constraints[i];
+      if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                   &allows_mem, &allows_reg, &is_inout))
        return;
 
+      if (! allows_reg
+         && (allows_mem
+             || is_inout
+             || (DECL_P (val)
+                 && GET_CODE (DECL_RTL (val)) == REG
+                 && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
+       mark_addressable (val);
+
+      if (is_inout)
+       ninout++;
+    }
+
+  ninputs += ninout;
+  if (ninputs + noutputs > MAX_RECOG_OPERANDS)
+    {
+      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
+      return;
+    }
+
+  for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail))
+    {
+      bool allows_reg, allows_mem;
+      const char *constraint;
+
+      /* If there's an erroneous arg, emit no insn, because the ASM_INPUT
+        would get VOIDmode and that could cause a crash in reload.  */
+      if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
+       return;
+
+      constraint = constraints[i + noutputs];
+      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                   constraints, &allows_mem, &allows_reg))
+       return;
+
+      if (! allows_reg && allows_mem)
+       mark_addressable (TREE_VALUE (tail));
+    }
+
+  /* Second pass evaluates arguments.  */
+
+  ninout = 0;
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+    {
+      tree val = TREE_VALUE (tail);
+      tree type = TREE_TYPE (val);
+      bool is_inout;
+      bool allows_reg;
+      bool allows_mem;
+
+      if (!parse_output_constraint (&constraints[i], i, ninputs,
+                                   noutputs, &allows_mem, &allows_reg,
+                                   &is_inout))
+       abort ();
+
       /* If an output operand is not a decl or indirect ref and our constraint
         allows a register, make a temporary to act as an intermediate.
         Make the asm insn write into that, then our caller will copy it to
@@ -1586,12 +1742,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          || ! allows_reg
          || is_inout)
        {
-         if (! allows_reg)
-           mark_addressable (TREE_VALUE (tail));
-
-         output_rtx[i]
-           = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
-                          EXPAND_MEMORY_USE_WO);
+         output_rtx[i] = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
          if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
            error ("output number %d not directly addressable", i);
@@ -1614,18 +1765,11 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       if (is_inout)
        {
-         inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
+         inout_mode[ninout] = TYPE_MODE (type);
          inout_opnum[ninout++] = i;
        }
     }
 
-  ninputs += ninout;
-  if (ninputs + noutputs > MAX_RECOG_OPERANDS)
-    {
-      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
-      return;
-    }
-
   /* Make vectors for the expression-rtx, constraint strings,
      and named operands.  */
 
@@ -1645,154 +1789,40 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
     {
-      int j;
-      int allows_reg = 0, allows_mem = 0;
-      const char *constraint, *orig_constraint;
-      int c_len;
+      bool allows_reg, allows_mem;
+      const char *constraint;
+      tree val, type;
       rtx op;
 
-      /* If there's an erroneous arg, emit no insn,
-        because the ASM_INPUT would get VOIDmode
-        and that could cause a crash in reload.  */
-      if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
-       return;
-
-      /* ??? Can this happen, and does the error message make any sense? */
-      if (TREE_PURPOSE (tail) == NULL_TREE)
-       {
-         error ("hard register `%s' listed as input operand to `asm'",
-                TREE_STRING_POINTER (TREE_VALUE (tail)) );
-         return;
-       }
-
-      orig_constraint = constraint = constraints[i + noutputs];
-      c_len = strlen (constraint);
-
-      /* Make sure constraint has neither `=', `+', nor '&'.  */
-
-      for (j = 0; j < c_len; j++)
-       switch (constraint[j])
-         {
-         case '+':  case '=':  case '&':
-           if (constraint == orig_constraint)
-             {
-               error ("input operand constraint contains `%c'",
-                      constraint[j]);
-               return;
-             }
-           break;
-
-         case '%':
-           if (constraint == orig_constraint
-               && i + 1 == ninputs - ninout)
-             {
-               error ("`%%' constraint used with last operand");
-               return;
-             }
-           break;
-
-         case 'V':  case 'm':  case 'o':
-           allows_mem = 1;
-           break;
-
-         case '<':  case '>':
-         case '?':  case '!':  case '*':  case '#':
-         case 'E':  case 'F':  case 'G':  case 'H':
-         case 's':  case 'i':  case 'n':
-         case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
-         case 'N':  case 'O':  case 'P':  case ',':
-           break;
-
-           /* Whether or not a numeric constraint allows a register is
-              decided by the matching constraint, and so there is no need
-              to do anything special with them.  We must handle them in
-              the default case, so that we don't unnecessarily force
-              operands to memory.  */
-         case '0':  case '1':  case '2':  case '3':  case '4':
-         case '5':  case '6':  case '7':  case '8':  case '9':
-           {
-             char *end;
-             unsigned long match;
-
-             match = strtoul (constraint + j, &end, 10);
-             if (match >= (unsigned long) noutputs)
-               {
-                 error ("matching constraint references invalid operand number");
-                 return;
-               }
-
-             /* Try and find the real constraint for this dup.  Only do
-                this if the matching constraint is the only alternative.  */
-             if (*end == '\0'
-                 && (j == 0 || (j == 1 && constraint[0] == '%')))
-               {
-                 constraint = constraints[match];
-                 c_len = strlen (constraint);
-                 j = 0;
-                 break;
-               }
-             else
-               j = end - constraint;
-           }
-           /* Fall through.  */
-
-         case 'p':  case 'r':
-           allows_reg = 1;
-           break;
-
-         case 'g':  case 'X':
-           allows_reg = 1;
-           allows_mem = 1;
-           break;
-
-         default:
-           if (! ISALPHA (constraint[j]))
-             {
-               error ("invalid punctuation `%c' in constraint",
-                      constraint[j]);
-               return;
-             }
-           if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
-             allows_reg = 1;
-#ifdef EXTRA_CONSTRAINT
-           else
-             {
-               /* Otherwise we can't assume anything about the nature of
-                  the constraint except that it isn't purely registers.
-                  Treat it like "g" and hope for the best.  */
-               allows_reg = 1;
-               allows_mem = 1;
-             }
-#endif
-           break;
-         }
+      constraint = constraints[i + noutputs];
+      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                   constraints, &allows_mem, &allows_reg))
+       abort ();
 
-      if (! allows_reg && allows_mem)
-       mark_addressable (TREE_VALUE (tail));
+      generating_concat_p = 0;
 
-      op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
+      val = TREE_VALUE (tail);
+      type = TREE_TYPE (val);
+      op = expand_expr (val, NULL_RTX, VOIDmode, 0);
 
       /* Never pass a CONCAT to an ASM.  */
-      generating_concat_p = 0;
       if (GET_CODE (op) == CONCAT)
        op = force_reg (GET_MODE (op), op);
 
       if (asm_operand_ok (op, constraint) <= 0)
        {
          if (allows_reg)
-           op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
+           op = force_reg (TYPE_MODE (type), op);
          else if (!allows_mem)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
          else if (CONSTANT_P (op))
-           op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                                 op);
+           op = force_const_mem (TYPE_MODE (type), op);
          else if (GET_CODE (op) == REG
                   || GET_CODE (op) == SUBREG
                   || GET_CODE (op) == ADDRESSOF
                   || GET_CODE (op) == CONCAT)
            {
-             tree type = TREE_TYPE (TREE_VALUE (tail));
              tree qual_type = build_qualified_type (type,
                                                     (TYPE_QUALS (type)
                                                      | TYPE_QUAL_CONST));
@@ -1803,9 +1833,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            }
 
          else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
-           /* We won't recognize volatile memory as available a
-              memory_operand at this point.  Ignore it.  */
-           ;
+           {
+             /* We won't recognize volatile memory as available a
+                memory_operand at this point.  Ignore it.  */
+           }
          else if (queued_subexp_p (op))
            ;
          else
@@ -1815,12 +1846,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
        }
+
       generating_concat_p = old_generating_concat_p;
       ASM_OPERANDS_INPUT (body, i) = op;
 
       ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
-       = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                            orig_constraint);
+       = gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
     }
 
   /* Protect all the operands from the queue now that they have all been
@@ -2049,8 +2080,16 @@ resolve_operand_names (string, outputs, inputs, pconstraints)
   p = buffer;
   while ((p = strchr (p, '%')) != NULL)
     {
-      if (*++p != '[')
-       continue;
+      if (p[1] == '[')
+       p += 1;
+      else if (ISALPHA (p[1]) && p[2] == '[')
+       p += 2;
+      else
+       {
+         p += 1;
+         continue;
+       }
+
       p = resolve_operand_name_1 (p, outputs, inputs);
     }
 
@@ -2110,15 +2149,23 @@ resolve_operand_name_1 (p, outputs, inputs)
   /* Resolve the name to a number.  */
   for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
     {
-      const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
-      if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
-       goto found;
+      tree id = TREE_PURPOSE (TREE_PURPOSE (t));
+      if (id)
+       {
+         const char *c = IDENTIFIER_POINTER (id);
+         if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+           goto found;
+       }
     }
   for (t = inputs; t ; t = TREE_CHAIN (t), op++)
     {
-      const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
-      if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
-       goto found;
+      tree id = TREE_PURPOSE (TREE_PURPOSE (t));
+      if (id)
+       {
+         const char *c = IDENTIFIER_POINTER (id);
+         if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+           goto found;
+       }
     }
 
   *q = '\0';
@@ -2143,16 +2190,39 @@ resolve_operand_name_1 (p, outputs, inputs)
 }
 \f
 /* Generate RTL to evaluate the expression EXP
-   and remember it in case this is the VALUE in a ({... VALUE; }) constr.  */
+   and remember it in case this is the VALUE in a ({... VALUE; }) constr.
+   Provided just for backward-compatibility.  expand_expr_stmt_value()
+   should be used for new code.  */
 
 void
 expand_expr_stmt (exp)
      tree exp;
 {
+  expand_expr_stmt_value (exp, -1, 1);
+}
+
+/* Generate RTL to evaluate the expression EXP.  WANT_VALUE tells
+   whether to (1) save the value of the expression, (0) discard it or
+   (-1) use expr_stmts_for_value to tell.  The use of -1 is
+   deprecated, and retained only for backward compatibility.  */
+
+void
+expand_expr_stmt_value (exp, want_value, maybe_last)
+     tree exp;
+     int want_value, maybe_last;
+{
+  rtx value;
+  tree type;
+
+  if (want_value == -1)
+    want_value = expr_stmts_for_value != 0;
+
   /* If -W, warn about statements with no side effects,
      except for an explicit cast to void (e.g. for assert()), and
-     except inside a ({...}) where they may be useful.  */
-  if (expr_stmts_for_value == 0 && exp != error_mark_node)
+     except for last statement in ({...}) where they may be useful.  */
+  if (! want_value
+      && (expr_stmts_for_value == 0 || ! maybe_last)
+      && exp != error_mark_node)
     {
       if (! TREE_SIDE_EFFECTS (exp))
        {
@@ -2168,51 +2238,52 @@ expand_expr_stmt (exp)
 
   /* If EXP is of function type and we are expanding statements for
      value, convert it to pointer-to-function.  */
-  if (expr_stmts_for_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
+  if (want_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
     exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
 
   /* The call to `expand_expr' could cause last_expr_type and
      last_expr_value to get reset.  Therefore, we set last_expr_value
      and last_expr_type *after* calling expand_expr.  */
-  last_expr_value = expand_expr (exp,
-                                (expr_stmts_for_value
-                                 ? NULL_RTX : const0_rtx),
-                                VOIDmode, 0);
-  last_expr_type = TREE_TYPE (exp);
+  value = expand_expr (exp, want_value ? NULL_RTX : const0_rtx,
+                      VOIDmode, 0);
+  type = TREE_TYPE (exp);
 
   /* If all we do is reference a volatile value in memory,
      copy it to a register to be sure it is actually touched.  */
-  if (last_expr_value != 0 && GET_CODE (last_expr_value) == MEM
-      && TREE_THIS_VOLATILE (exp))
+  if (value && GET_CODE (value) == MEM && TREE_THIS_VOLATILE (exp))
     {
-      if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)
+      if (TYPE_MODE (type) == VOIDmode)
        ;
-      else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
-       copy_to_reg (last_expr_value);
+      else if (TYPE_MODE (type) != BLKmode)
+       value = copy_to_reg (value);
       else
        {
          rtx lab = gen_label_rtx ();
 
          /* Compare the value with itself to reference it.  */
-         emit_cmp_and_jump_insns (last_expr_value, last_expr_value, EQ,
-                                  expand_expr (TYPE_SIZE (last_expr_type),
+         emit_cmp_and_jump_insns (value, value, EQ,
+                                  expand_expr (TYPE_SIZE (type),
                                                NULL_RTX, VOIDmode, 0),
-                                  BLKmode, 0,
-                                  TYPE_ALIGN (last_expr_type) / BITS_PER_UNIT,
-                                  lab);
+                                  BLKmode, 0, lab);
          emit_label (lab);
        }
     }
 
   /* If this expression is part of a ({...}) and is in memory, we may have
      to preserve temporaries.  */
-  preserve_temp_slots (last_expr_value);
+  preserve_temp_slots (value);
 
   /* Free any temporaries used to evaluate this expression.  Any temporary
      used as a result of this expression will already have been preserved
      above.  */
   free_temp_slots ();
 
+  if (want_value)
+    {
+      last_expr_value = value;
+      last_expr_type = type;
+    }
+
   emit_queue ();
 }
 
@@ -2232,10 +2303,6 @@ warn_if_unused_value (exp)
   if (VOID_TYPE_P (TREE_TYPE (exp)))
     return 0;
 
-  /* If this is an expression with side effects, don't warn.  */
-  if (TREE_SIDE_EFFECTS (exp))
-    return 0;
-
   switch (TREE_CODE (exp))
     {
     case PREINCREMENT_EXPR:
@@ -2295,7 +2362,7 @@ warn_if_unused_value (exp)
            || TREE_CODE (tem) == CALL_EXPR)
          return 0;
       }
-      goto warn;
+      goto maybe_warn;
 
     case INDIRECT_REF:
       /* Don't warn about automatic dereferencing of references, since
@@ -2318,7 +2385,11 @@ warn_if_unused_value (exp)
          && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
        return 0;
 
-    warn:
+    maybe_warn:
+      /* If this is an expression with side effects, don't warn.  */
+      if (TREE_SIDE_EFFECTS (exp))
+       return 0;
+
       warning_with_file_and_line (emit_filename, emit_lineno,
                                  "value computed is not used");
       return 1;
@@ -2349,6 +2420,7 @@ expand_start_stmt_expr ()
   start_sequence_for_rtl_expr (t);
   NO_DEFER_POP;
   expr_stmts_for_value++;
+  last_expr_value = NULL_RTX;
   return t;
 }
 
@@ -2370,15 +2442,11 @@ expand_end_stmt_expr (t)
 {
   OK_DEFER_POP;
 
-  if (last_expr_type == 0)
+  if (! last_expr_value || ! last_expr_type)
     {
-      last_expr_type = void_type_node;
       last_expr_value = const0_rtx;
+      last_expr_type = void_type_node;
     }
-  else if (last_expr_value == 0)
-    /* There are some cases where this can happen, such as when the
-       statement is void type.  */
-    last_expr_value = const0_rtx;
   else if (GET_CODE (last_expr_value) != REG && ! CONSTANT_P (last_expr_value))
     /* Remove any possible QUEUED.  */
     last_expr_value = protect_from_queue (last_expr_value, 0);
@@ -2582,8 +2650,8 @@ void
 expand_end_loop ()
 {
   rtx start_label = loop_stack->data.loop.start_label;
-  rtx insn = get_last_insn ();
-  int needs_end_jump = 1;
+  rtx etc_note;
+  int eh_regions, debug_blocks;
 
   /* Mark the continue-point at the top of the loop if none elsewhere.  */
   if (start_label == loop_stack->data.loop.continue_label)
@@ -2591,296 +2659,134 @@ expand_end_loop ()
 
   do_pending_stack_adjust ();
 
-  /* If optimizing, perhaps reorder the loop.
-     First, try to use a condjump near the end.
-     expand_exit_loop_if_false ends loops with unconditional jumps,
-     like this:
-
-     if (test) goto label;
-     optional: cleanup
-     goto loop_stack->data.loop.end_label
-     barrier
-     label:
-
-     If we find such a pattern, we can end the loop earlier.  */
-
-  if (optimize
-      && GET_CODE (insn) == CODE_LABEL
-      && LABEL_NAME (insn) == NULL
-      && GET_CODE (PREV_INSN (insn)) == BARRIER)
-    {
-      rtx label = insn;
-      rtx jump = PREV_INSN (PREV_INSN (label));
-
-      if (GET_CODE (jump) == JUMP_INSN
-         && GET_CODE (PATTERN (jump)) == SET
-         && SET_DEST (PATTERN (jump)) == pc_rtx
-         && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
-         && (XEXP (SET_SRC (PATTERN (jump)), 0)
-             == loop_stack->data.loop.end_label))
-       {
-         rtx prev;
-
-         /* The test might be complex and reference LABEL multiple times,
-            like the loop in loop_iterations to set vtop.  To handle this,
-            we move LABEL.  */
-         insn = PREV_INSN (label);
-         reorder_insns (label, label, start_label);
-
-         for (prev = PREV_INSN (jump);; prev = PREV_INSN (prev))
-           {
-             /* We ignore line number notes, but if we see any other note,
-                in particular NOTE_INSN_BLOCK_*, NOTE_INSN_EH_REGION_*,
-                NOTE_INSN_LOOP_*, we disable this optimization.  */
-             if (GET_CODE (prev) == NOTE)
-               {
-                 if (NOTE_LINE_NUMBER (prev) < 0)
-                   break;
-                 continue;
-               }
-             if (GET_CODE (prev) == CODE_LABEL)
-               break;
-             if (GET_CODE (prev) == JUMP_INSN)
-               {
-                 if (GET_CODE (PATTERN (prev)) == SET
-                     && SET_DEST (PATTERN (prev)) == pc_rtx
-                     && GET_CODE (SET_SRC (PATTERN (prev))) == IF_THEN_ELSE
-                     && (GET_CODE (XEXP (SET_SRC (PATTERN (prev)), 1))
-                         == LABEL_REF)
-                     && XEXP (XEXP (SET_SRC (PATTERN (prev)), 1), 0) == label)
-                   {
-                     XEXP (XEXP (SET_SRC (PATTERN (prev)), 1), 0)
-                       = start_label;
-                     emit_note_after (NOTE_INSN_LOOP_END, prev);
-                     needs_end_jump = 0;
-                   }
-                 break;
-               }
-          }
-       }
-    }
-
-     /* If the loop starts with a loop exit, roll that to the end where
+  /* If the loop starts with a loop exit, roll that to the end where
      it will optimize together with the jump back.
 
-     We look for the conditional branch to the exit, except that once
-     we find such a branch, we don't look past 30 instructions.
-
-     In more detail, if the loop presently looks like this (in pseudo-C):
+     If the loop presently looks like this (in pseudo-C):
 
-         start_label:
-         if (test) goto end_label;
-        body;
-        goto start_label;
-        end_label:
+       LOOP_BEG
+       start_label:
+         if (test) goto end_label;
+       LOOP_END_TOP_COND
+         body;
+         goto start_label;
+       end_label:
 
      transform it to look like:
 
-         goto start_label;
-         newstart_label:
-        body;
-        start_label:
-        if (test) goto end_label;
-        goto newstart_label;
-        end_label:
-
-     Here, the `test' may actually consist of some reasonably complex
-     code, terminating in a test.  */
-
-  if (optimize
-      && needs_end_jump
-      &&
-      ! (GET_CODE (insn) == JUMP_INSN
-        && GET_CODE (PATTERN (insn)) == SET
-        && SET_DEST (PATTERN (insn)) == pc_rtx
-        && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
-    {
-      int eh_regions = 0;
-      int num_insns = 0;
-      rtx last_test_insn = NULL_RTX;
-
-      /* Scan insns from the top of the loop looking for a qualified
-        conditional exit.  */
-      for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn;
-          insn = NEXT_INSN (insn))
-       {
-         if (GET_CODE (insn) == NOTE)
-           {
-             if (optimize < 2
-                 && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-                     || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
-               /* The code that actually moves the exit test will
-                  carefully leave BLOCK notes in their original
-                  location.  That means, however, that we can't debug
-                  the exit test itself.  So, we refuse to move code
-                  containing BLOCK notes at low optimization levels.  */
-               break;
-
-             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
-               ++eh_regions;
-             else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
-               {
-                 --eh_regions;
-                 if (eh_regions < 0)
-                   /* We've come to the end of an EH region, but
-                      never saw the beginning of that region.  That
-                      means that an EH region begins before the top
-                      of the loop, and ends in the middle of it.  The
-                      existence of such a situation violates a basic
-                      assumption in this code, since that would imply
-                      that even when EH_REGIONS is zero, we might
-                      move code out of an exception region.  */
-                   abort ();
-               }
-
-             /* We must not walk into a nested loop.  */
-             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-               break;
-
-             /* We already know this INSN is a NOTE, so there's no
-                point in looking at it to see if it's a JUMP.  */
-             continue;
-           }
-
-         if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
-           num_insns++;
+       LOOP_BEG
+         goto start_label;
+       top_label:
+         body;
+       start_label:
+         if (test) goto end_label;
+         goto top_label;
+       end_label:
+
+     We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
+     the end of the entry condtional.  Without this, our lexical scan
+     can't tell the difference between an entry conditional and a
+     body conditional that exits the loop.  Mistaking the two means
+     that we can misplace the NOTE_INSN_LOOP_CONT note, which can 
+     screw up loop unrolling.
+
+     Things will be oh so much better when loop optimization is done
+     off of a proper control flow graph...  */
+
+  /* Scan insns from the top of the loop looking for the END_TOP_COND note.  */
+
+  eh_regions = debug_blocks = 0;
+  for (etc_note = start_label; etc_note ; etc_note = NEXT_INSN (etc_note))
+    if (GET_CODE (etc_note) == NOTE)
+      {
+       if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_END_TOP_COND)
+         break;
 
-         if (last_test_insn && num_insns > 30)
+       /* We must not walk into a nested loop.  */
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG)
+         {
+           etc_note = NULL_RTX;
            break;
+         }
 
-         if (eh_regions > 0)
-           /* We don't want to move a partial EH region.  Consider:
-
-                 while ( ( { try {
-                               if (cond ()) 0;
-                               else {
-                                 bar();
-                                 1;
-                               }
-                             } catch (...) {
-                               1;
-                             } )) {
-                    body;
-                 }
-
-               This isn't legal C++, but here's what it's supposed to
-               mean: if cond() is true, stop looping.  Otherwise,
-               call bar, and keep looping.  In addition, if cond
-               throws an exception, catch it and keep looping. Such
-               constructs are certainy legal in LISP.
-
-               We should not move the `if (cond()) 0' test since then
-               the EH-region for the try-block would be broken up.
-               (In this case we would the EH_BEG note for the `try'
-               and `if cond()' but not the call to bar() or the
-               EH_END note.)
-
-               So we don't look for tests within an EH region.  */
-           continue;
-
-         if (GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == SET
-             && SET_DEST (PATTERN (insn)) == pc_rtx)
-           {
-             /* This is indeed a jump.  */
-             rtx dest1 = NULL_RTX;
-             rtx dest2 = NULL_RTX;
-             rtx potential_last_test;
-             if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
-               {
-                 /* A conditional jump.  */
-                 dest1 = XEXP (SET_SRC (PATTERN (insn)), 1);
-                 dest2 = XEXP (SET_SRC (PATTERN (insn)), 2);
-                 potential_last_test = insn;
-               }
-             else
-               {
-                 /* An unconditional jump.  */
-                 dest1 = SET_SRC (PATTERN (insn));
-                 /* Include the BARRIER after the JUMP.  */
-                 potential_last_test = NEXT_INSN (insn);
-               }
-
-             do {
-               if (dest1 && GET_CODE (dest1) == LABEL_REF
-                   && ((XEXP (dest1, 0)
-                        == loop_stack->data.loop.alt_end_label)
-                       || (XEXP (dest1, 0)
-                           == loop_stack->data.loop.end_label)))
-                 {
-                   last_test_insn = potential_last_test;
-                   break;
-                 }
+       /* At the same time, scan for EH region notes, as we don't want
+          to scrog region nesting.  This shouldn't happen, but...  */
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG)
+         eh_regions++;
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_END)
+         {
+           if (--eh_regions < 0)
+             /* We've come to the end of an EH region, but never saw the
+                beginning of that region.  That means that an EH region
+                begins before the top of the loop, and ends in the middle
+                of it.  The existence of such a situation violates a basic
+                assumption in this code, since that would imply that even
+                when EH_REGIONS is zero, we might move code out of an
+                exception region.  */
+             abort ();
+         }
 
-               /* If this was a conditional jump, there may be
-                  another label at which we should look.  */
-               dest1 = dest2;
-               dest2 = NULL_RTX;
-             } while (dest1);
-           }
-       }
+       /* Likewise for debug scopes.  In this case we'll either (1) move
+          all of the notes if they are properly nested or (2) leave the
+          notes alone and only rotate the loop at high optimization 
+          levels when we expect to scrog debug info.  */
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_BEG)
+         debug_blocks++;
+       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_END)
+         debug_blocks--;
+      }
 
-      if (last_test_insn != 0 && last_test_insn != get_last_insn ())
+  if (etc_note
+      && optimize
+      && eh_regions == 0
+      && (debug_blocks == 0 || optimize >= 2)
+      && NEXT_INSN (etc_note) != NULL_RTX
+      && ! any_condjump_p (get_last_insn ()))
+    {
+      /* We found one.  Move everything from START to ETC to the end
+        of the loop, and add a jump from the top of the loop.  */
+      rtx top_label = gen_label_rtx ();
+      rtx start_move = start_label;
+
+      /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
+        then we want to move this note also.  */
+      if (GET_CODE (PREV_INSN (start_move)) == NOTE
+         && NOTE_LINE_NUMBER (PREV_INSN (start_move)) == NOTE_INSN_LOOP_CONT)
+       start_move = PREV_INSN (start_move);
+
+      emit_label_before (top_label, start_move);
+
+      /* Actually move the insns.  If the debug scopes are nested, we
+        can move everything at once.  Otherwise we have to move them
+        one by one and squeeze out the block notes.  */
+      if (debug_blocks == 0)
+       reorder_insns (start_move, etc_note, get_last_insn ());
+      else
        {
-         /* We found one.  Move everything from there up
-            to the end of the loop, and add a jump into the loop
-            to jump to there.  */
-         rtx newstart_label = gen_label_rtx ();
-         rtx start_move = start_label;
-         rtx next_insn;
-
-         /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
-            then we want to move this note also.  */
-         if (GET_CODE (PREV_INSN (start_move)) == NOTE
-             && (NOTE_LINE_NUMBER (PREV_INSN (start_move))
-                 == NOTE_INSN_LOOP_CONT))
-           start_move = PREV_INSN (start_move);
-
-         emit_label_after (newstart_label, PREV_INSN (start_move));
-
-         /* Actually move the insns.  Start at the beginning, and
-            keep copying insns until we've copied the
-            last_test_insn.  */
+         rtx insn, next_insn;
          for (insn = start_move; insn; insn = next_insn)
            {
              /* Figure out which insn comes after this one.  We have
                 to do this before we move INSN.  */
-             if (insn == last_test_insn)
-               /* We've moved all the insns.  */
-               next_insn = NULL_RTX;
-             else
-               next_insn = NEXT_INSN (insn);
+             next_insn = (insn == etc_note ? NULL : NEXT_INSN (insn));
 
              if (GET_CODE (insn) == NOTE
                  && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
                      || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
-               /* We don't want to move NOTE_INSN_BLOCK_BEGs or
-                  NOTE_INSN_BLOCK_ENDs because the correct generation
-                  of debugging information depends on these appearing
-                  in the same order in the RTL and in the tree
-                  structure, where they are represented as BLOCKs.
-                  So, we don't move block notes.  Of course, moving
-                  the code inside the block is likely to make it
-                  impossible to debug the instructions in the exit
-                  test, but such is the price of optimization.  */
                continue;
 
-             /* Move the INSN.  */
              reorder_insns (insn, insn, get_last_insn ());
            }
-
-         emit_jump_insn_after (gen_jump (start_label),
-                               PREV_INSN (newstart_label));
-         emit_barrier_after (PREV_INSN (newstart_label));
-         start_label = newstart_label;
        }
-    }
 
-  if (needs_end_jump)
-    {
-      emit_jump (start_label);
-      emit_note (NULL, NOTE_INSN_LOOP_END);
+      /* Add the jump from the top of the loop.  */
+      emit_jump_insn_before (gen_jump (start_label), top_label);
+      emit_barrier_before (top_label);
+      start_label = top_label;
     }
+
+  emit_jump (start_label);
+  emit_note (NULL, NOTE_INSN_LOOP_END);
   emit_label (loop_stack->data.loop.end_label);
 
   POPSTACK (loop_stack);
@@ -2968,6 +2874,22 @@ expand_exit_loop_if_false (whichloop, cond)
   return 1;
 }
 
+/* Like expand_exit_loop_if_false except also emit a note marking
+   the end of the conditional.  Should only be used immediately 
+   after expand_loop_start.  */
+
+int
+expand_exit_loop_top_cond (whichloop, cond)
+     struct nesting *whichloop;
+     tree cond;
+{
+  if (! expand_exit_loop_if_false (whichloop, cond))
+    return 0;
+
+  emit_note (NULL, NOTE_INSN_LOOP_END_TOP_COND);
+  return 1;
+}
+
 /* Return nonzero if the loop nest is empty.  Else return zero.  */
 
 int
@@ -3039,7 +2961,7 @@ expand_null_return ()
 
   /* If this function was declared to return a value, but we
      didn't, clobber the return registers so that they are not
-     propogated live to the rest of the function.  */
+     propagated live to the rest of the function.  */
   clobber_return_register ();
 
   expand_null_return_1 (last_insn);
@@ -3071,8 +2993,7 @@ expand_value_return (val)
        val = convert_modes (mode, old_mode, val, unsignedp);
 #endif
       if (GET_CODE (return_reg) == PARALLEL)
-       emit_group_load (return_reg, val, int_size_in_bytes (type),
-                        TYPE_ALIGN (type));
+       emit_group_load (return_reg, val, int_size_in_bytes (type));
       else
        emit_move_insn (return_reg, val);
     }
@@ -3217,7 +3138,9 @@ expand_return (retval)
         to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
         machine, this means we must skip the empty high order bytes when
         calculating the bit offset.  */
-      if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
+      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));
 
@@ -3236,8 +3159,8 @@ expand_return (retval)
              dst = gen_reg_rtx (word_mode);
              result_pseudos[xbitpos / BITS_PER_WORD] = dst;
 
-             /* Clobber the destination before we move anything into it.  */
-             emit_insn (gen_rtx_CLOBBER (VOIDmode, dst));
+             /* Clear the destination before we move anything into it.  */
+             emit_move_insn (dst, CONST0_RTX (GET_MODE (dst)));
            }
 
          /* We need a new source operand each time bitpos is on a word
@@ -3253,8 +3176,8 @@ expand_return (retval)
                           extract_bit_field (src, bitsize,
                                              bitpos % BITS_PER_WORD, 1,
                                              NULL_RTX, word_mode, word_mode,
-                                             bitsize, BITS_PER_WORD),
-                          bitsize, BITS_PER_WORD);
+                                             BITS_PER_WORD),
+                          BITS_PER_WORD);
        }
 
       /* Find the smallest integer mode large enough to hold the
@@ -3743,7 +3666,7 @@ expand_nl_goto_receivers (thisblock)
   if (any_invalid)
     {
       expand_nl_goto_receiver ();
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), LCT_NORETURN,
                         VOIDmode, 0);
       emit_barrier ();
     }
@@ -3990,9 +3913,7 @@ expand_decl (decl)
           && !(flag_float_store
                && TREE_CODE (type) == REAL_TYPE)
           && ! TREE_THIS_VOLATILE (decl)
-          && (DECL_REGISTER (decl) || optimize)
-          /* if -fcheck-memory-usage, check all variables.  */
-          && ! current_function_check_memory_usage)
+          && (DECL_REGISTER (decl) || optimize))
     {
       /* Automatic variable that can go in a register.  */
       int unsignedp = TREE_UNSIGNED (type);
@@ -4111,21 +4032,10 @@ expand_decl_init (decl)
 {
   int was_used = TREE_USED (decl);
 
-  /* If this is a CONST_DECL, we don't have to generate any code, but
-     if DECL_INITIAL is a constant, call expand_expr to force TREE_CST_RTL
-     to be set while in the obstack containing the constant.  If we don't
-     do this, we can lose if we have functions nested three deep and the middle
-     function makes a CONST_DECL whose DECL_INITIAL is a STRING_CST while
-     the innermost function is the first to expand that STRING_CST.  */
-  if (TREE_CODE (decl) == CONST_DECL)
-    {
-      if (DECL_INITIAL (decl) && TREE_CONSTANT (DECL_INITIAL (decl)))
-       expand_expr (DECL_INITIAL (decl), NULL_RTX, VOIDmode,
-                    EXPAND_INITIALIZER);
-      return;
-    }
-
-  if (TREE_STATIC (decl))
+  /* 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.  */
@@ -4291,6 +4201,11 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
       tree cleanup_elt = TREE_PURPOSE (t);
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
 
+      /* If any of the elements are addressable, so is the entire
+        union.  */
+      if (TREE_USED (decl_elt))
+       TREE_USED (decl) = 1;
+
       /* Propagate the union's alignment to the elements.  */
       DECL_ALIGN (decl_elt) = DECL_ALIGN (decl);
       DECL_USER_ALIGN (decl_elt) = DECL_USER_ALIGN (decl);
@@ -4974,20 +4889,20 @@ add_case_node (low, high, label, duplicate)
 /* Returns the number of possible values of TYPE.
    Returns -1 if the number is unknown, variable, or if the number does not
    fit in a HOST_WIDE_INT.
-   Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
+   Sets *SPARSENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
    do not increase monotonically (there may be duplicates);
    to 1 if the values increase monotonically, but not always by 1;
    otherwise sets it to 0.  */
 
 HOST_WIDE_INT
-all_cases_count (type, spareness)
+all_cases_count (type, sparseness)
      tree type;
-     int *spareness;
+     int *sparseness;
 {
   tree t;
   HOST_WIDE_INT count, minval, lastval;
 
-  *spareness = 0;
+  *sparseness = 0;
 
   switch (TREE_CODE (type))
     {
@@ -5026,11 +4941,12 @@ all_cases_count (type, spareness)
        {
          HOST_WIDE_INT thisval = tree_low_cst (TREE_VALUE (t), 0);
 
-         if (*spareness == 2 || thisval < lastval)
-           *spareness = 2;
+         if (*sparseness == 2 || thisval <= lastval)
+           *sparseness = 2;
          else if (thisval != minval + count)
-           *spareness = 1;
+           *sparseness = 1;
 
+         lastval = thisval;
          count++;
        }
     }
@@ -5311,13 +5227,15 @@ free_case_nodes (cn)
 
 /* Terminate a case (Pascal) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
+   If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
+   type as given in the source before any compiler conversions.
    Generate the code to test it and jump to the right place.  */
 
 void
-expand_end_case (orig_index)
-     tree orig_index;
+expand_end_case_type (orig_index, orig_type)
+     tree orig_index, orig_type;
 {
-  tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE, orig_minval;
+  tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
   rtx default_label = 0;
   struct case_node *n;
   unsigned int count;
@@ -5339,6 +5257,8 @@ expand_end_case (orig_index)
   index_expr = thiscase->data.case_stmt.index_expr;
   index_type = TREE_TYPE (index_expr);
   unsignedp = TREE_UNSIGNED (index_type);
+  if (orig_type == NULL)
+    orig_type = TREE_TYPE (orig_index);
 
   do_pending_stack_adjust ();
 
@@ -5359,9 +5279,9 @@ expand_end_case (orig_index)
         No sense trying this if there's a default case, however.  */
 
       if (!thiscase->data.case_stmt.default_label
-         && TREE_CODE (TREE_TYPE (orig_index)) == ENUMERAL_TYPE
+         && TREE_CODE (orig_type) == ENUMERAL_TYPE
          && TREE_CODE (index_expr) != INTEGER_CST)
-       check_for_full_enumeration_handling (TREE_TYPE (orig_index));
+       check_for_full_enumeration_handling (orig_type);
 
       /* If we don't have a default-label, create one here,
         after the body of the switch.  */
@@ -5417,8 +5337,6 @@ expand_end_case (orig_index)
            count++;
        }
 
-      orig_minval = minval;
-
       /* Compute span of values.  */
       if (count != 0)
        range = fold (build (MINUS_EXPR, index_type, maxval, minval));
@@ -5520,7 +5438,7 @@ expand_end_case (orig_index)
                 default code is emitted.  */
 
              use_cost_table
-               = (TREE_CODE (TREE_TYPE (orig_index)) != ENUMERAL_TYPE
+               = (TREE_CODE (orig_type) != ENUMERAL_TYPE
                   && estimate_case_costs (thiscase->data.case_stmt.case_list));
              balance_case_nodes (&thiscase->data.case_stmt.case_list, NULL);
              emit_case_nodes (index, thiscase->data.case_stmt.case_list,
@@ -5558,18 +5476,20 @@ expand_end_case (orig_index)
 
          for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
            {
-             HOST_WIDE_INT i
-               = TREE_INT_CST_LOW (n->low) - TREE_INT_CST_LOW (orig_minval);
-
-             while (1)
-               {
-                 labelvec[i]
-                   = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
-                 if (i + TREE_INT_CST_LOW (orig_minval)
-                     == TREE_INT_CST_LOW (n->high))
-                   break;
-                 i++;
-               }
+             /* Compute the low and high bounds relative to the minimum
+                value since that should fit in a HOST_WIDE_INT while the
+                actual values may not.  */
+             HOST_WIDE_INT i_low
+               = tree_low_cst (fold (build (MINUS_EXPR, index_type, 
+                                             n->low, minval)), 1);
+             HOST_WIDE_INT i_high
+               = tree_low_cst (fold (build (MINUS_EXPR, index_type, 
+                                             n->high, minval)), 1);
+             HOST_WIDE_INT i;
+
+             for (i = i_low; i <= i_high; i ++)
+               labelvec[i]
+                 = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
            }
 
          /* Fill in the gaps with the default.  */
@@ -5601,7 +5521,8 @@ expand_end_case (orig_index)
 
       before_case = NEXT_INSN (before_case);
       end = get_last_insn ();
-      squeeze_notes (&before_case, &end);
+      if (squeeze_notes (&before_case, &end))
+       abort ();
       reorder_insns (before_case, end,
                     thiscase->data.case_stmt.start);
     }
@@ -5647,20 +5568,16 @@ do_jump_if_equal (op1, op2, label, unsignedp)
      rtx op1, op2, label;
      int unsignedp;
 {
-  if (GET_CODE (op1) == CONST_INT
-      && GET_CODE (op2) == CONST_INT)
+  if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
     {
       if (INTVAL (op1) == INTVAL (op2))
        emit_jump (label);
     }
   else
-    {
-      enum machine_mode mode = GET_MODE (op1);
-      if (mode == VOIDmode)
-       mode = GET_MODE (op2);
-      emit_cmp_and_jump_insns (op1, op2, EQ, NULL_RTX, mode, unsignedp,
-                              0, label);
-    }
+    emit_cmp_and_jump_insns (op1, op2, EQ, NULL_RTX,
+                            (GET_MODE (op1) == VOIDmode
+                            ? GET_MODE (op2) : GET_MODE (op1)),
+                            unsignedp, label);
 }
 \f
 /* Not all case values are encountered equally.  This function
@@ -6103,7 +6020,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->high, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      GT, NULL_RTX, mode, unsignedp, 0,
+                                      GT, NULL_RTX, mode, unsignedp,
                                       label_rtx (node->right->code_label));
              emit_case_nodes (index, node->left, default_label, index_type);
            }
@@ -6116,7 +6033,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->high, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      LT, NULL_RTX, mode, unsignedp, 0,
+                                      LT, NULL_RTX, mode, unsignedp,
                                       label_rtx (node->left->code_label));
              emit_case_nodes (index, node->right, default_label, index_type);
            }
@@ -6135,7 +6052,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->high, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      GT, NULL_RTX, mode, unsignedp, 0,
+                                      GT, NULL_RTX, mode, unsignedp,
                                       label_rtx (test_label));
 
              /* Value must be on the left.
@@ -6170,7 +6087,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                            expand_expr (node->high, NULL_RTX,
                                                         VOIDmode, 0),
                                            unsignedp),
-                                          LT, NULL_RTX, mode, unsignedp, 0,
+                                          LT, NULL_RTX, mode, unsignedp,
                                           default_label);
                }
 
@@ -6203,7 +6120,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                            expand_expr (node->high, NULL_RTX,
                                                         VOIDmode, 0),
                                            unsignedp),
-                                          GT, NULL_RTX, mode, unsignedp, 0,
+                                          GT, NULL_RTX, mode, unsignedp,
                                           default_label);
                }
 
@@ -6246,7 +6163,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                      expand_expr (node->high, NULL_RTX,
                                                   VOIDmode, 0),
                                      unsignedp),
-                                    GT, NULL_RTX, mode, unsignedp, 0,
+                                    GT, NULL_RTX, mode, unsignedp,
                                     label_rtx (node->right->code_label));
          else
            {
@@ -6260,7 +6177,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->high, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      GT, NULL_RTX, mode, unsignedp, 0,
+                                      GT, NULL_RTX, mode, unsignedp,
                                       label_rtx (test_label));
            }
 
@@ -6272,7 +6189,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                    expand_expr (node->low, NULL_RTX,
                                                 VOIDmode, 0),
                                    unsignedp),
-                                  GE, NULL_RTX, mode, unsignedp, 0,
+                                  GE, NULL_RTX, mode, unsignedp,
                                   label_rtx (node->code_label));
 
          /* Handle the left-hand subtree.  */
@@ -6303,7 +6220,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->low, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      LT, NULL_RTX, mode, unsignedp, 0,
+                                      LT, NULL_RTX, mode, unsignedp,
                                       default_label);
            }
 
@@ -6315,7 +6232,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                    expand_expr (node->high, NULL_RTX,
                                                 VOIDmode, 0),
                                    unsignedp),
-                                  LE, NULL_RTX, mode, unsignedp, 0,
+                                  LE, NULL_RTX, mode, unsignedp,
                                   label_rtx (node->code_label));
 
          emit_case_nodes (index, node->right, default_label, index_type);
@@ -6333,7 +6250,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->high, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      GT, NULL_RTX, mode, unsignedp, 0,
+                                      GT, NULL_RTX, mode, unsignedp,
                                       default_label);
            }
 
@@ -6345,7 +6262,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                    expand_expr (node->low, NULL_RTX,
                                                 VOIDmode, 0),
                                    unsignedp),
-                                  GE, NULL_RTX, mode, unsignedp, 0,
+                                  GE, NULL_RTX, mode, unsignedp,
                                   label_rtx (node->code_label));
 
          emit_case_nodes (index, node->left, default_label, index_type);
@@ -6367,7 +6284,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->high, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      GT, NULL_RTX, mode, unsignedp, 0,
+                                      GT, NULL_RTX, mode, unsignedp,
                                       default_label);
            }
 
@@ -6379,7 +6296,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                        expand_expr (node->low, NULL_RTX,
                                                     VOIDmode, 0),
                                        unsignedp),
-                                      LT, NULL_RTX, mode, unsignedp, 0,
+                                      LT, NULL_RTX, mode, unsignedp,
                                       default_label);
            }
          else if (!low_bound && !high_bound)
@@ -6401,7 +6318,7 @@ emit_case_nodes (index, node, default_label, index_type)
                                       NULL_RTX, mode, 0);
                                
              emit_cmp_and_jump_insns (new_index, new_bound, GT, NULL_RTX,
-                                      mode, 1, 0, default_label);
+                                      mode, 1, default_label);
            }
 
          emit_jump (label_rtx (node->code_label));