c-common.c (truthvalue_conversion): Rename, update.
[platform/upstream/gcc.git] / gcc / stmt.c
index c87612a..4f0cb17 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.
 
@@ -53,6 +53,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "output.h"
 #include "ggc.h"
+#include "langhooks.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -110,7 +111,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.
 
@@ -1054,7 +1055,7 @@ expand_fixup (tree_label, rtl_label, last_insn)
        TREE_USED (block) = 1;
 
        if (!cfun->x_whole_function_mode_p)
-         insert_block (block);
+         (*lang_hooks.decls.insert_block) (block);
        else
          {
            BLOCK_CHAIN (block)
@@ -1175,8 +1176,8 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
             logically be inserting the fixup code.  We do this for the
             sake of getting the debugging information right.  */
 
-         pushlevel (0);
-         set_block (f->context);
+         (*lang_hooks.decls.pushlevel) (0);
+         (*lang_hooks.decls.set_block) (f->context);
 
          /* Expand the cleanups for blocks this jump exits.  */
          if (f->cleanup_list_list)
@@ -1215,7 +1216,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
             destructed are still "in scope".  */
 
          cleanup_insns = get_insns ();
-         poplevel (1, 0, 0);
+         (*lang_hooks.decls.poplevel) (1, 0, 0);
 
          end_sequence ();
          emit_insns_after (cleanup_insns, f->before_jump);
@@ -1249,12 +1250,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
          if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups)
            {
              start_sequence ();
-             pushlevel (0);
-             set_block (f->context);
+             (*lang_hooks.decls.pushlevel) (0);
+             (*lang_hooks.decls.set_block) (f->context);
              expand_cleanups (TREE_VALUE (lists), NULL_TREE, 1, 1);
              do_pending_stack_adjust ();
              cleanup_insns = get_insns ();
-             poplevel (1, 0, 0);
+             (*lang_hooks.decls.poplevel) (1, 0, 0);
              end_sequence ();
              if (cleanup_insns != 0)
                f->before_jump
@@ -1677,7 +1678,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
              || (DECL_P (val)
                  && GET_CODE (DECL_RTL (val)) == REG
                  && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
-       mark_addressable (val);
+       (*lang_hooks.mark_addressable) (val);
 
       if (is_inout)
        ninout++;
@@ -1706,7 +1707,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
        return;
 
       if (! allows_reg && allows_mem)
-       mark_addressable (TREE_VALUE (tail));
+       (*lang_hooks.mark_addressable) (TREE_VALUE (tail));
     }
 
   /* Second pass evaluates arguments.  */
@@ -2149,15 +2150,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';
@@ -2182,16 +2191,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))
        {
@@ -2207,34 +2239,31 @@ expand_expr_stmt (exp)
 
   /* If EXP is of function type and we are expanding statements for
      value, convert it to pointer-to-function.  */
-  if (expr_stmts_for_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
+  if (want_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
     exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
 
   /* The call to `expand_expr' could cause last_expr_type and
      last_expr_value to get reset.  Therefore, we set last_expr_value
      and last_expr_type *after* calling expand_expr.  */
-  last_expr_value = expand_expr (exp,
-                                (expr_stmts_for_value
-                                 ? NULL_RTX : const0_rtx),
-                                VOIDmode, 0);
-  last_expr_type = TREE_TYPE (exp);
+  value = expand_expr (exp, want_value ? NULL_RTX : const0_rtx,
+                      VOIDmode, 0);
+  type = TREE_TYPE (exp);
 
   /* If all we do is reference a volatile value in memory,
      copy it to a register to be sure it is actually touched.  */
-  if (last_expr_value != 0 && GET_CODE (last_expr_value) == MEM
-      && TREE_THIS_VOLATILE (exp))
+  if (value && GET_CODE (value) == MEM && TREE_THIS_VOLATILE (exp))
     {
-      if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)
+      if (TYPE_MODE (type) == VOIDmode)
        ;
-      else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
-       copy_to_reg (last_expr_value);
+      else if (TYPE_MODE (type) != BLKmode)
+       value = copy_to_reg (value);
       else
        {
          rtx lab = gen_label_rtx ();
 
          /* Compare the value with itself to reference it.  */
-         emit_cmp_and_jump_insns (last_expr_value, last_expr_value, EQ,
-                                  expand_expr (TYPE_SIZE (last_expr_type),
+         emit_cmp_and_jump_insns (value, value, EQ,
+                                  expand_expr (TYPE_SIZE (type),
                                                NULL_RTX, VOIDmode, 0),
                                   BLKmode, 0, lab);
          emit_label (lab);
@@ -2243,13 +2272,19 @@ expand_expr_stmt (exp)
 
   /* If this expression is part of a ({...}) and is in memory, we may have
      to preserve temporaries.  */
-  preserve_temp_slots (last_expr_value);
+  preserve_temp_slots (value);
 
   /* Free any temporaries used to evaluate this expression.  Any temporary
      used as a result of this expression will already have been preserved
      above.  */
   free_temp_slots ();
 
+  if (want_value)
+    {
+      last_expr_value = value;
+      last_expr_type = type;
+    }
+
   emit_queue ();
 }
 
@@ -2269,10 +2304,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:
@@ -2332,7 +2363,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
@@ -2355,7 +2386,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;
@@ -2386,6 +2421,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;
 }
 
@@ -2407,15 +2443,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);
@@ -2619,8 +2651,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)
@@ -2628,296 +2660,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.
+     If the loop presently looks like this (in pseudo-C):
 
-     In more detail, if the loop presently looks like this (in pseudo-C):
-
-         start_label:
-         if (test) goto end_label;
-        body;
-        goto start_label;
-        end_label:
+       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);
@@ -3005,6 +2875,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
@@ -3781,9 +3667,7 @@ expand_nl_goto_receivers (thisblock)
   if (any_invalid)
     {
       expand_nl_goto_receiver ();
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), LCT_NORETURN,
-                        VOIDmode, 0);
-      emit_barrier ();
+      expand_builtin_trap ();
     }
 
   nonlocal_goto_handler_labels = label_list;
@@ -4085,7 +3969,7 @@ expand_decl (decl)
                           : GET_MODE_BITSIZE (DECL_MODE (decl)));
       DECL_USER_ALIGN (decl) = 0;
 
-      x = assign_temp (TREE_TYPE (decl), 1, 1, 1);
+      x = assign_temp (decl, 1, 1, 1);
       set_mem_attributes (x, decl, 1);
       SET_DECL_RTL (decl, x);
 
@@ -4229,12 +4113,13 @@ expand_decl_cleanup (decl, cleanup)
 
          emit_move_insn (flag, const1_rtx);
 
-         cond = build_decl (VAR_DECL, NULL_TREE, type_for_mode (word_mode, 1));
+         cond = build_decl (VAR_DECL, NULL_TREE,
+                            (*lang_hooks.types.type_for_mode) (word_mode, 1));
          SET_DECL_RTL (cond, flag);
 
          /* Conditionalize the cleanup.  */
          cleanup = build (COND_EXPR, void_type_node,
-                          truthvalue_conversion (cond),
+                          (*lang_hooks.truthvalue_conversion) (cond),
                           cleanup, integer_zero_node);
          cleanup = fold (cleanup);
 
@@ -4284,6 +4169,23 @@ expand_decl_cleanup (decl, cleanup)
     }
   return 1;
 }
+
+/* Like expand_decl_cleanup, but maybe only run the cleanup if an exception
+   is thrown.  */
+
+int
+expand_decl_cleanup_eh (decl, cleanup, eh_only)
+     tree decl, cleanup;
+     int eh_only;
+{
+  int ret = expand_decl_cleanup (decl, cleanup);
+  if (cleanup && ret)
+    {
+      tree node = block_stack->data.block.cleanups;
+      CLEANUP_EH_ONLY (node) = eh_only;
+    }
+  return ret;
+}
 \f
 /* DECL is an anonymous union.  CLEANUP is a cleanup for DECL.
    DECL_ELTS is the list of elements that belong to DECL's type.
@@ -4316,6 +4218,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);
@@ -4387,7 +4294,7 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
            if (! in_fixup && using_eh_for_cleanups_p)
              expand_eh_region_end_cleanup (TREE_VALUE (tail));
 
-           if (reachable)
+           if (reachable && !CLEANUP_EH_ONLY (tail))
              {
                /* Cleanups may be run multiple times.  For example,
                   when exiting a binding contour, we expand the
@@ -4999,20 +4906,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))
     {
@@ -5051,11 +4958,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++;
        }
     }
@@ -5202,16 +5110,23 @@ mark_seen_cases (type, cases_seen, count, sparseness)
     }
 }
 
-/* Called when the index of a switch statement is an enumerated type
-   and there is no default label.
+/* Given a switch statement with an expression that is an enumeration
+   type, warn if any of the enumeration type's literals are not
+   covered by the case expressions of the switch.  Also, warn if there
+   are any extra switch cases that are *not* elements of the
+   enumerated type.
 
-   Checks that all enumeration literals are covered by the case
-   expressions of a switch.  Also, warn if there are any extra
-   switch cases that are *not* elements of the enumerated type.
+   Historical note:
 
-   If all enumeration literals were covered by the case expressions,
-   turn one of the expressions into the default expression since it should
-   not be possible to fall through such a switch.  */
+   At one stage this function would: ``If all enumeration literals
+   were covered by the case expressions, turn one of the expressions
+   into the default expression since it should not be possible to fall
+   through such a switch.''
+
+   That code has since been removed as: ``This optimization is
+   disabled because it causes valid programs to fail.  ANSI C does not
+   guarantee that an expression with enum type will have a value that
+   is the same as one of the enumeration literals.''  */
 
 void
 check_for_full_enumeration_handling (type)
@@ -5233,9 +5148,6 @@ check_for_full_enumeration_handling (type)
   /* The allocated size of cases_seen, in chars.  */
   HOST_WIDE_INT bytes_needed;
 
-  if (! warn_switch)
-    return;
-
   size = all_cases_count (type, &sparseness);
   bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
 
@@ -5273,49 +5185,48 @@ check_for_full_enumeration_handling (type)
       && case_stack->data.case_stmt.case_list->left)
     case_stack->data.case_stmt.case_list
       = case_tree2list (case_stack->data.case_stmt.case_list, 0);
-  if (warn_switch)
-    for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
-      {
-       for (chain = TYPE_VALUES (type);
-            chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
-            chain = TREE_CHAIN (chain))
-         ;
-
-       if (!chain)
-         {
-           if (TYPE_NAME (type) == 0)
-             warning ("case value `%ld' not in enumerated type",
-                      (long) TREE_INT_CST_LOW (n->low));
-           else
-             warning ("case value `%ld' not in enumerated type `%s'",
-                      (long) TREE_INT_CST_LOW (n->low),
-                      IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
-                                           == IDENTIFIER_NODE)
-                                          ? TYPE_NAME (type)
-                                          : DECL_NAME (TYPE_NAME (type))));
-         }
-       if (!tree_int_cst_equal (n->low, n->high))
-         {
-           for (chain = TYPE_VALUES (type);
-                chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain));
-                chain = TREE_CHAIN (chain))
-             ;
-
-           if (!chain)
-             {
-               if (TYPE_NAME (type) == 0)
-                 warning ("case value `%ld' not in enumerated type",
-                          (long) TREE_INT_CST_LOW (n->high));
-               else
-                 warning ("case value `%ld' not in enumerated type `%s'",
-                          (long) TREE_INT_CST_LOW (n->high),
-                          IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
-                                               == IDENTIFIER_NODE)
-                                              ? TYPE_NAME (type)
-                                              : DECL_NAME (TYPE_NAME (type))));
-             }
-         }
-      }
+  for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
+    {
+      for (chain = TYPE_VALUES (type);
+          chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
+          chain = TREE_CHAIN (chain))
+       ;
+      
+      if (!chain)
+       {
+         if (TYPE_NAME (type) == 0)
+           warning ("case value `%ld' not in enumerated type",
+                    (long) TREE_INT_CST_LOW (n->low));
+         else
+           warning ("case value `%ld' not in enumerated type `%s'",
+                    (long) TREE_INT_CST_LOW (n->low),
+                    IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
+                                         == IDENTIFIER_NODE)
+                                        ? TYPE_NAME (type)
+                                        : DECL_NAME (TYPE_NAME (type))));
+       }
+      if (!tree_int_cst_equal (n->low, n->high))
+       {
+         for (chain = TYPE_VALUES (type);
+              chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain));
+              chain = TREE_CHAIN (chain))
+           ;
+         
+         if (!chain)
+           {
+             if (TYPE_NAME (type) == 0)
+               warning ("case value `%ld' not in enumerated type",
+                        (long) TREE_INT_CST_LOW (n->high));
+             else
+               warning ("case value `%ld' not in enumerated type `%s'",
+                        (long) TREE_INT_CST_LOW (n->high),
+                        IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
+                                             == IDENTIFIER_NODE)
+                                            ? TYPE_NAME (type)
+                                            : DECL_NAME (TYPE_NAME (type))));
+           }
+       }
+    }
 }
 
 /* Free CN, and its children.  */
@@ -5336,11 +5247,13 @@ 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;
   rtx default_label = 0;
@@ -5364,6 +5277,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 ();
 
@@ -5379,14 +5294,18 @@ expand_end_case (orig_index)
   /* An ERROR_MARK occurs for various reasons including invalid data type.  */
   if (index_type != error_mark_node)
     {
-      /* If switch expression was an enumerated type, check that all
-        enumeration literals are covered by the cases.
-        No sense trying this if there's a default case, however.  */
-
-      if (!thiscase->data.case_stmt.default_label
-         && TREE_CODE (TREE_TYPE (orig_index)) == ENUMERAL_TYPE
+      /* If the switch expression was an enumerated type, check that
+        exactly all enumeration literals are covered by the cases.
+        The check is made when -Wswitch was specified and there is no
+        default case, or when -Wswitch-enum was specified.  */
+      if (((warn_switch && !thiscase->data.case_stmt.default_label)
+          || warn_switch_enum)
+         && TREE_CODE (orig_type) == ENUMERAL_TYPE
          && TREE_CODE (index_expr) != INTEGER_CST)
-       check_for_full_enumeration_handling (TREE_TYPE (orig_index));
+       check_for_full_enumeration_handling (orig_type);
+
+      if (warn_switch_default && !thiscase->data.case_stmt.default_label)
+       warning ("switch missing default case");
 
       /* If we don't have a default-label, create one here,
         after the body of the switch.  */
@@ -5543,7 +5462,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,
@@ -6407,7 +6326,7 @@ emit_case_nodes (index, node, default_label, index_type)
          else if (!low_bound && !high_bound)
            {
              /* Widen LOW and HIGH to the same width as INDEX.  */
-             tree type = type_for_mode (mode, unsignedp);
+             tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
              tree low = build1 (CONVERT_EXPR, type, node->low);
              tree high = build1 (CONVERT_EXPR, type, node->high);
              rtx low_rtx, new_index, new_bound;