OSDN Git Service

* ChangeLog: Follow spelling conventions.
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index c5399bc..b2e2cad 100644 (file)
@@ -46,7 +46,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "expr.h"
 #include "libfuncs.h"
 #include "hard-reg-set.h"
-#include "obstack.h"
 #include "loop.h"
 #include "recog.h"
 #include "machmode.h"
@@ -54,10 +53,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "output.h"
 #include "ggc.h"
 #include "langhooks.h"
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-struct obstack stmt_obstack;
+#include "predict.h"
 
 /* Assume that case vectors are not pc-relative.  */
 #ifndef CASE_VECTOR_PC_RELATIVE
@@ -88,7 +84,7 @@ struct obstack stmt_obstack;
    and nodes on the right having higher values.  We then output the tree
    in order.  */
 
-struct case_node
+struct case_node GTY(())
 {
   struct case_node     *left;  /* Left son in binary tree */
   struct case_node     *right; /* Right son in binary tree; also node chain */
@@ -138,16 +134,22 @@ static int cost_table_initialized;
    The construct is visible if the `exit_label' field is non-null.
    In that case, the value should be a CODE_LABEL rtx.  */
 
-struct nesting
+struct nesting GTY(())
 {
   struct nesting *all;
   struct nesting *next;
   int depth;
   rtx exit_label;
-  union
+  enum nesting_desc {
+    COND_NESTING,
+    LOOP_NESTING,
+    BLOCK_NESTING,
+    CASE_NESTING
+  } desc;
+  union nesting_u
     {
       /* For conds (if-then and if-then-else statements).  */
-      struct
+      struct nesting_cond
        {
          /* Label for the end of the if construct.
             There is none if EXITFLAG was not set
@@ -156,9 +158,9 @@ struct nesting
          /* Label for the end of this alternative.
             This may be the end of the if or the next else/elseif.  */
          rtx next_label;
-       } cond;
+       } GTY ((tag ("COND_NESTING"))) cond;
       /* For loops.  */
-      struct
+      struct nesting_loop
        {
          /* Label at the top of the loop; place to loop back to.  */
          rtx start_label;
@@ -170,9 +172,9 @@ struct nesting
          /* Label for `continue' statement to jump to;
             this is in front of the stepper of the loop.  */
          rtx continue_label;
-       } loop;
+       } GTY ((tag ("LOOP_NESTING"))) loop;
       /* For variable binding contours.  */
-      struct
+      struct nesting_block
        {
          /* Sequence number of this binding contour within the function,
             in order of entry.  */
@@ -204,7 +206,7 @@ struct nesting
          struct label_chain *label_chain;
          /* Number of function calls seen, as of start of this block.  */
          int n_function_calls;
-         /* Nonzero if this is associated with a EH region.  */
+         /* Nonzero if this is associated with an EH region.  */
          int exception_region;
          /* The saved target_temp_slot_level from our outer block.
             We may reset target_temp_slot_level to be the level of
@@ -222,14 +224,10 @@ struct nesting
             the start of the last unconditional cleanup, and before any
             conditional branch points.  */
          rtx last_unconditional_cleanup;
-         /* When in a conditional context, this is the specific
-            cleanup list associated with last_unconditional_cleanup,
-            where we place the conditionalized cleanups.  */
-         tree *cleanup_ptr;
-       } block;
+       } GTY ((tag ("BLOCK_NESTING"))) block;
       /* For switch (C) or case (Pascal) statements,
         and also for dummies (see `expand_start_case_dummy').  */
-      struct
+      struct nesting_case
        {
          /* The insn after which the case dispatch should finally
             be emitted.  Zero for a dummy.  */
@@ -250,14 +248,14 @@ struct nesting
             We set this to -1 when we see the first case label in this
             case statement.  */
          int line_number_status;
-       } case_stmt;
-    } data;
+       } GTY ((tag ("CASE_NESTING"))) case_stmt;
+    } GTY ((desc ("%1.desc"))) data;
 };
 
 /* Allocate and return a new `struct nesting'.  */
 
 #define ALLOC_NESTING() \
- (struct nesting *) obstack_alloc (&stmt_obstack, sizeof (struct nesting))
+ (struct nesting *) ggc_alloc (sizeof (struct nesting))
 
 /* Pop the nesting stack element by element until we pop off
    the element which is at the top of STACK.
@@ -279,8 +277,7 @@ do { struct nesting *target = STACK;                        \
          if (case_stack == this)                       \
            case_stack = case_stack->next;              \
          nesting_depth = nesting_stack->depth - 1;     \
-         nesting_stack = this->all;                    \
-         obstack_free (&stmt_obstack, this); }         \
+         nesting_stack = this->all; }                  \
      while (this != target); } while (0)
 \f
 /* In some cases it is impossible to generate code for a forward goto
@@ -291,7 +288,7 @@ do { struct nesting *target = STACK;                        \
    we check each fixup.
    If the target label has now been defined, we can insert the proper code.  */
 
-struct goto_fixup
+struct goto_fixup GTY(())
 {
   /* Points to following fixup.  */
   struct goto_fixup *next;
@@ -325,36 +322,36 @@ struct goto_fixup
 /* Within any binding contour that must restore a stack level,
    all labels are recorded with a chain of these structures.  */
 
-struct label_chain
+struct label_chain GTY(())
 {
   /* Points to following fixup.  */
   struct label_chain *next;
   tree label;
 };
 
-struct stmt_status
+struct stmt_status GTY(())
 {
   /* Chain of all pending binding contours.  */
-  struct nesting *x_block_stack;
+  struct nesting * x_block_stack;
 
   /* If any new stacks are added here, add them to POPSTACKS too.  */
 
   /* Chain of all pending binding contours that restore stack levels
      or have cleanups.  */
-  struct nesting *x_stack_block_stack;
+  struct nesting * x_stack_block_stack;
 
   /* Chain of all pending conditional statements.  */
-  struct nesting *x_cond_stack;
+  struct nesting * x_cond_stack;
 
   /* Chain of all pending loops.  */
-  struct nesting *x_loop_stack;
+  struct nesting * x_loop_stack;
 
   /* Chain of all pending case or switch statements.  */
-  struct nesting *x_case_stack;
+  struct nesting * x_case_stack;
 
   /* Separate chain including all of the above,
      chained through the `all' field.  */
-  struct nesting *x_nesting_stack;
+  struct nesting * x_nesting_stack;
 
   /* Number of entries on nesting_stack now.  */
   int x_nesting_depth;
@@ -414,6 +411,7 @@ static tree resolve_operand_names   PARAMS ((tree, tree, tree,
                                                 const char **));
 static char *resolve_operand_name_1    PARAMS ((char *, tree, tree));
 static void expand_null_return_1       PARAMS ((rtx));
+static enum br_predictor return_prediction PARAMS ((rtx));
 static void expand_value_return                PARAMS ((rtx));
 static int tail_recursion_args         PARAMS ((tree, tree));
 static void expand_cleanups            PARAMS ((tree, tree, int, int));
@@ -429,13 +427,6 @@ static int node_is_bounded         PARAMS ((case_node_ptr, tree));
 static void emit_jump_if_reachable     PARAMS ((rtx));
 static void emit_case_nodes            PARAMS ((rtx, case_node_ptr, rtx, tree));
 static struct case_node *case_tree2list        PARAMS ((case_node *, case_node *));
-static void mark_cond_nesting           PARAMS ((struct nesting *));
-static void mark_loop_nesting           PARAMS ((struct nesting *));
-static void mark_block_nesting          PARAMS ((struct nesting *));
-static void mark_case_nesting           PARAMS ((struct nesting *));
-static void mark_case_node             PARAMS ((struct case_node *));
-static void mark_goto_fixup             PARAMS ((struct goto_fixup *));
-static void free_case_nodes             PARAMS ((case_node_ptr));
 \f
 void
 using_eh_for_cleanups ()
@@ -443,176 +434,10 @@ using_eh_for_cleanups ()
   using_eh_for_cleanups_p = 1;
 }
 
-/* Mark N (known to be a cond-nesting) for GC.  */
-
-static void
-mark_cond_nesting (n)
-     struct nesting *n;
-{
-  while (n)
-    {
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.cond.endif_label);
-      ggc_mark_rtx (n->data.cond.next_label);
-
-      n = n->next;
-    }
-}
-
-/* Mark N (known to be a loop-nesting) for GC.  */
-
-static void
-mark_loop_nesting (n)
-     struct nesting *n;
-{
-
-  while (n)
-    {
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.loop.start_label);
-      ggc_mark_rtx (n->data.loop.end_label);
-      ggc_mark_rtx (n->data.loop.alt_end_label);
-      ggc_mark_rtx (n->data.loop.continue_label);
-
-      n = n->next;
-    }
-}
-
-/* Mark N (known to be a block-nesting) for GC.  */
-
-static void
-mark_block_nesting (n)
-     struct nesting *n;
-{
-  while (n)
-    {
-      struct label_chain *l;
-
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.block.stack_level);
-      ggc_mark_rtx (n->data.block.first_insn);
-      ggc_mark_tree (n->data.block.cleanups);
-      ggc_mark_tree (n->data.block.outer_cleanups);
-
-      for (l = n->data.block.label_chain; l != NULL; l = l->next) 
-       {
-         ggc_mark (l);
-         ggc_mark_tree (l->label);
-       }
-
-      ggc_mark_rtx (n->data.block.last_unconditional_cleanup);
-
-      /* ??? cleanup_ptr never points outside the stack, does it?  */
-
-      n = n->next;
-    }
-}
-
-/* Mark N (known to be a case-nesting) for GC.  */
-
-static void
-mark_case_nesting (n)
-     struct nesting *n;
-{
-  while (n)
-    {
-      ggc_mark_rtx (n->exit_label);
-      ggc_mark_rtx (n->data.case_stmt.start);
-
-      ggc_mark_tree (n->data.case_stmt.default_label);
-      ggc_mark_tree (n->data.case_stmt.index_expr);
-      ggc_mark_tree (n->data.case_stmt.nominal_type);
-
-      mark_case_node (n->data.case_stmt.case_list);
-      n = n->next;
-    }
-}
-
-/* Mark C for GC.  */
-
-static void
-mark_case_node (c)
-     struct case_node *c;
-{
-  if (c != 0)
-    {
-      ggc_mark_tree (c->low);
-      ggc_mark_tree (c->high);
-      ggc_mark_tree (c->code_label);
-
-      mark_case_node (c->right);
-      mark_case_node (c->left);
-    }
-}
-
-/* Mark G for GC.  */
-
-static void
-mark_goto_fixup (g)
-     struct goto_fixup *g;
-{
-  while (g)
-    {
-      ggc_mark (g);
-      ggc_mark_rtx (g->before_jump);
-      ggc_mark_tree (g->target);
-      ggc_mark_tree (g->context);
-      ggc_mark_rtx (g->target_rtl);
-      ggc_mark_rtx (g->stack_level);
-      ggc_mark_tree (g->cleanup_list_list);
-
-      g = g->next;
-    }
-}
-
-/* Clear out all parts of the state in F that can safely be discarded
-   after the function has been compiled, to let garbage collection
-   reclaim the memory.  */
-
-void
-free_stmt_status (f)
-     struct function *f;
-{
-  /* We're about to free the function obstack.  If we hold pointers to
-     things allocated there, then we'll try to mark them when we do
-     GC.  So, we clear them out here explicitly.  */
-  if (f->stmt)
-    free (f->stmt);
-  f->stmt = NULL;
-}
-
-/* Mark P for GC.  */
-
-void
-mark_stmt_status (p)
-     struct stmt_status *p;
-{
-  if (p == 0)
-    return;
-
-  mark_block_nesting (p->x_block_stack);
-  mark_cond_nesting (p->x_cond_stack);
-  mark_loop_nesting (p->x_loop_stack);
-  mark_case_nesting (p->x_case_stack);
-
-  ggc_mark_tree (p->x_last_expr_type);
-  /* last_epxr_value is only valid if last_expr_type is nonzero.  */
-  if (p->x_last_expr_type)
-    ggc_mark_rtx (p->x_last_expr_value);
-
-  mark_goto_fixup (p->x_goto_fixup_chain);
-}
-
-void
-init_stmt ()
-{
-  gcc_obstack_init (&stmt_obstack);
-}
-
 void
 init_stmt_for_function ()
 {
-  cfun->stmt = (struct stmt_status *) xmalloc (sizeof (struct stmt_status));
+  cfun->stmt = ((struct stmt_status *)ggc_alloc (sizeof (struct stmt_status)));
 
   /* We are not currently within any block, conditional, loop or case.  */
   block_stack = 0;
@@ -630,8 +455,7 @@ init_stmt_for_function ()
 
   /* We are not processing a ({...}) grouping.  */
   expr_stmts_for_value = 0;
-  last_expr_type = 0;
-  last_expr_value = NULL_RTX;
+  clear_last_expr ();
 }
 \f
 /* Return nonzero if anything is pushed on the loop, condition, or case
@@ -846,7 +670,7 @@ expand_goto (label)
          emit_indirect_jump (handler_slot);
        }
 
-      /* Search backwards to the jump insn and mark it as a 
+      /* Search backwards to the jump insn and mark it as a
         non-local goto.  */
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
        {
@@ -1045,8 +869,8 @@ expand_fixup (tree_label, rtl_label, last_insn)
         as a placeholder.  */
 
       {
-        rtx original_before_jump
-          = last_insn ? last_insn : get_last_insn ();
+       rtx original_before_jump
+         = last_insn ? last_insn : get_last_insn ();
        rtx start;
        rtx end;
        tree block;
@@ -1064,17 +888,17 @@ expand_fixup (tree_label, rtl_label, last_insn)
              = block;
          }
 
-        start_sequence ();
-        start = emit_note (NULL, NOTE_INSN_BLOCK_BEG);
+       start_sequence ();
+       start = emit_note (NULL, NOTE_INSN_BLOCK_BEG);
        if (cfun->x_whole_function_mode_p)
          NOTE_BLOCK (start) = block;
        fixup->before_jump = emit_note (NULL, NOTE_INSN_DELETED);
        end = emit_note (NULL, NOTE_INSN_BLOCK_END);
        if (cfun->x_whole_function_mode_p)
          NOTE_BLOCK (end) = block;
-        fixup->context = block;
-        end_sequence ();
-        emit_insns_after (start, original_before_jump);
+       fixup->context = block;
+       end_sequence ();
+       emit_insn_after (start, original_before_jump);
       }
 
       fixup->block_start_count = current_block_start_count;
@@ -1219,7 +1043,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
          (*lang_hooks.decls.poplevel) (1, 0, 0);
 
          end_sequence ();
-         emit_insns_after (cleanup_insns, f->before_jump);
+         emit_insn_after (cleanup_insns, f->before_jump);
 
          f->before_jump = 0;
        }
@@ -1259,7 +1083,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
              end_sequence ();
              if (cleanup_insns != 0)
                f->before_jump
-                 = emit_insns_after (cleanup_insns, f->before_jump);
+                 = emit_insn_after (cleanup_insns, f->before_jump);
 
              f->cleanup_list_list = TREE_CHAIN (lists);
            }
@@ -1294,7 +1118,7 @@ expand_asm (body)
 
   emit_insn (gen_rtx_ASM_INPUT (VOIDmode,
                                TREE_STRING_POINTER (body)));
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 
 /* Parse the output constraint pointed to by *CONSTRAINT_P.  It is the
@@ -1380,7 +1204,7 @@ parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
       case '=':
        error ("operand constraint contains incorrectly positioned '+' or '='");
        return false;
-       
+
       case '%':
        if (operand_num + 1 == ninputs + noutputs)
          {
@@ -1417,7 +1241,7 @@ parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
        *allows_reg = true;
        *allows_mem = true;
        break;
-       
+
       case 'p': case 'r':
        *allows_reg = true;
        break;
@@ -1428,6 +1252,10 @@ parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
        if (REG_CLASS_FROM_LETTER (*p) != NO_REGS)
          *allows_reg = true;
 #ifdef EXTRA_CONSTRAINT
+       else if (EXTRA_ADDRESS_CONSTRAINT (*p))
+         *allows_reg = true;
+       else if (EXTRA_MEMORY_CONSTRAINT (*p))
+         *allows_mem = true;
        else
          {
            /* Otherwise we can't assume anything about the nature of
@@ -1553,6 +1381,10 @@ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
        if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
          *allows_reg = true;
 #ifdef EXTRA_CONSTRAINT
+       else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j]))
+         *allows_reg = true;
+       else if (EXTRA_MEMORY_CONSTRAINT (constraint[j]))
+         *allows_mem = true;
        else
          {
            /* Otherwise we can't assume anything about the nature of
@@ -1573,7 +1405,7 @@ parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
    OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
    Each output or input has an expression in the TREE_VALUE and
    and a tree list in TREE_PURPOSE which in turn contains a constraint
-   name in TREE_VALUE (or NULL_TREE) and a constraint string 
+   name in TREE_VALUE (or NULL_TREE) and a constraint string
    in TREE_PURPOSE.
    CLOBBERS is a list of STRING_CST nodes each naming a hard register
    that is clobbered by this insn.
@@ -1646,7 +1478,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
        error ("unknown register name `%s' in `asm'", regname);
     }
 
-  last_expr_type = 0;
+  clear_last_expr ();
 
   /* First pass over inputs and outputs checks validity and sets
      mark_addressable if needed.  */
@@ -1740,48 +1572,25 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
              && (allows_mem || GET_CODE (DECL_RTL (val)) == REG)
              && ! (GET_CODE (DECL_RTL (val)) == REG
                    && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
+         || ! allows_reg
          || is_inout)
        {
-         enum { do_not_copy, do_copy_reg, do_copy_mem } do_copy;
-         rtx op;
+         output_rtx[i] = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
-         op = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
-         output_rtx[i] = op;
-
-         if (! allows_reg && GET_CODE (op) != MEM)
+         if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
            error ("output number %d not directly addressable", i);
-
-         do_copy = do_not_copy;
-         if (! allows_mem && GET_CODE (op) == MEM)
-           do_copy = do_copy_reg;
-         else if (GET_CODE (op) == CONCAT)
-           do_copy = do_copy_reg;
-         else if (asm_operand_ok (op, constraints[i]) <= 0)
-           {
-             if (allows_reg && !register_operand (op, VOIDmode))
-               do_copy = do_copy_reg;
-             else if (allows_mem && GET_CODE (op) != MEM)
-               do_copy = do_copy_mem;
-             else
-               warning ("asm operand %d probably doesn't match constraints", i);
-           }
-
-         if (do_copy == do_copy_reg)
-           {
-             real_output_rtx[i] = protect_from_queue (op, 1);
-             output_rtx[i] = gen_reg_rtx (GET_MODE (op));
-           }
-         else if (do_copy == do_copy_mem)
+         if ((! allows_mem && GET_CODE (output_rtx[i]) == MEM)
+             || GET_CODE (output_rtx[i]) == CONCAT)
            {
-             real_output_rtx[i] = op;
-             output_rtx[i] = assign_temp (type, 0, 1, 1);
+             real_output_rtx[i] = protect_from_queue (output_rtx[i], 1);
+             output_rtx[i] = gen_reg_rtx (GET_MODE (output_rtx[i]));
+             if (is_inout)
+               emit_move_insn (output_rtx[i], real_output_rtx[i]);
            }
-         if (do_copy && is_inout)
-           emit_move_insn (output_rtx[i], real_output_rtx[i]);
        }
       else
        {
-         output_rtx[i] = assign_temp (type, 0, !allows_reg, 1);
+         output_rtx[i] = assign_temp (type, 0, 0, 1);
          TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
        }
 
@@ -1802,7 +1611,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
                                : GET_MODE (output_rtx[0])),
-                              TREE_STRING_POINTER (string), 
+                              TREE_STRING_POINTER (string),
                               empty_string, 0, argvec, constraintvec,
                               filename, line);
 
@@ -1835,9 +1644,9 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       if (asm_operand_ok (op, constraint) <= 0)
        {
-         if (allows_reg && !register_operand (op, VOIDmode))
+         if (allows_reg)
            op = force_reg (TYPE_MODE (type), op);
-         else if (!allows_mem || GET_CODE (op) == MEM)
+         else if (!allows_mem)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
          else if (CONSTANT_P (op))
@@ -2057,7 +1866,7 @@ check_unique_operand_names (outputs, inputs)
        continue;
 
       for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
-       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+       if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
          goto failure;
     }
 
@@ -2068,10 +1877,10 @@ check_unique_operand_names (outputs, inputs)
        continue;
 
       for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
-       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+       if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
          goto failure;
       for (j = outputs; j ; j = TREE_CHAIN (j))
-       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+       if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
          goto failure;
     }
 
@@ -2079,7 +1888,7 @@ check_unique_operand_names (outputs, inputs)
 
  failure:
   error ("duplicate asm operand name '%s'",
-        IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
+        TREE_STRING_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
   return false;
 }
 
@@ -2148,7 +1957,7 @@ resolve_operand_names (string, outputs, inputs, pconstraints)
 
 /* A subroutine of resolve_operand_names.  P points to the '[' for a
    potential named operand of the form [<name>].  In place, replace
-   the name and brackets with a number.  Return a pointer to the 
+   the name and brackets with a number.  Return a pointer to the
    balance of the string after substitution.  */
 
 static char *
@@ -2173,20 +1982,20 @@ resolve_operand_name_1 (p, outputs, inputs)
   /* Resolve the name to a number.  */
   for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
     {
-      tree id = TREE_PURPOSE (TREE_PURPOSE (t));
-      if (id)
+      tree name = TREE_PURPOSE (TREE_PURPOSE (t));
+      if (name)
        {
-         const char *c = IDENTIFIER_POINTER (id);
+         const char *c = TREE_STRING_POINTER (name);
          if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
            goto found;
        }
     }
   for (t = inputs; t ; t = TREE_CHAIN (t), op++)
     {
-      tree id = TREE_PURPOSE (TREE_PURPOSE (t));
-      if (id)
+      tree name = TREE_PURPOSE (TREE_PURPOSE (t));
+      if (name)
        {
-         const char *c = IDENTIFIER_POINTER (id);
+         const char *c = TREE_STRING_POINTER (name);
          if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
            goto found;
        }
@@ -2425,15 +2234,20 @@ warn_if_unused_value (exp)
 void
 clear_last_expr ()
 {
-  last_expr_type = 0;
+  last_expr_type = NULL_TREE;
+  last_expr_value = NULL_RTX;
 }
 
-/* Begin a statement which will return a value.
-   Return the RTL_EXPR for this statement expr.
-   The caller must save that value and pass it to expand_end_stmt_expr.  */
+/* Begin a statement-expression, i.e., a series of statements which
+   may return a value.  Return the RTL_EXPR for this statement expr.
+   The caller must save that value and pass it to
+   expand_end_stmt_expr.  If HAS_SCOPE is nonzero, temporaries created
+   in the statement-expression are deallocated at the end of the
+   expression.  */
 
 tree
-expand_start_stmt_expr ()
+expand_start_stmt_expr (has_scope)
+     int has_scope;
 {
   tree t;
 
@@ -2441,10 +2255,12 @@ expand_start_stmt_expr ()
      so that rtl_expr_chain doesn't become garbage.  */
   t = make_node (RTL_EXPR);
   do_pending_stack_adjust ();
-  start_sequence_for_rtl_expr (t);
+  if (has_scope)
+    start_sequence_for_rtl_expr (t);
+  else
+    start_sequence ();
   NO_DEFER_POP;
   expr_stmts_for_value++;
-  last_expr_value = NULL_RTX;
   return t;
 }
 
@@ -2490,7 +2306,7 @@ expand_end_stmt_expr (t)
   /* Propagate volatility of the actual RTL expr.  */
   TREE_THIS_VOLATILE (t) = volatile_refs_p (last_expr_value);
 
-  last_expr_type = 0;
+  clear_last_expr ();
   expr_stmts_for_value--;
 
   return t;
@@ -2511,6 +2327,7 @@ expand_start_cond (cond, exitflag)
 
   /* Make an entry on cond_stack for the cond we are entering.  */
 
+  thiscond->desc = COND_NESTING;
   thiscond->next = cond_stack;
   thiscond->all = nesting_stack;
   thiscond->depth = ++nesting_depth;
@@ -2581,7 +2398,7 @@ expand_end_cond ()
     emit_label (thiscond->data.cond.endif_label);
 
   POPSTACK (cond_stack);
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 \f
 /* Generate RTL for the start of a loop.  EXIT_FLAG is nonzero if this
@@ -2599,6 +2416,7 @@ expand_start_loop (exit_flag)
 
   /* Make an entry on loop_stack for the loop we are entering.  */
 
+  thisloop->desc = LOOP_NESTING;
   thisloop->next = loop_stack;
   thisloop->all = nesting_stack;
   thisloop->depth = ++nesting_depth;
@@ -2640,6 +2458,7 @@ expand_start_null_loop ()
 
   /* Make an entry on loop_stack for the loop we are entering.  */
 
+  thisloop->desc = LOOP_NESTING;
   thisloop->next = loop_stack;
   thisloop->all = nesting_stack;
   thisloop->depth = ++nesting_depth;
@@ -2711,7 +2530,7 @@ expand_end_loop ()
      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 
+     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
@@ -2752,7 +2571,7 @@ expand_end_loop ()
 
        /* 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 
+          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++;
@@ -2815,7 +2634,7 @@ expand_end_loop ()
 
   POPSTACK (loop_stack);
 
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 
 /* Finish a null loop, aka do { } while (0).  */
@@ -2828,7 +2647,7 @@ expand_end_null_loop ()
 
   POPSTACK (loop_stack);
 
-  last_expr_type = 0;
+  clear_last_expr ();
 }
 
 /* Generate a jump to the current loop's continue-point.
@@ -2840,7 +2659,12 @@ int
 expand_continue_loop (whichloop)
      struct nesting *whichloop;
 {
-  last_expr_type = 0;
+  /* Emit information for branch prediction.  */
+  rtx note;
+
+  note = emit_note (NULL, NOTE_INSN_PREDICTION);
+  NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
+  clear_last_expr ();
   if (whichloop == 0)
     whichloop = loop_stack;
   if (whichloop == 0)
@@ -2857,7 +2681,7 @@ int
 expand_exit_loop (whichloop)
      struct nesting *whichloop;
 {
-  last_expr_type = 0;
+  clear_last_expr ();
   if (whichloop == 0)
     whichloop = loop_stack;
   if (whichloop == 0)
@@ -2877,7 +2701,7 @@ expand_exit_loop_if_false (whichloop, cond)
 {
   rtx label = gen_label_rtx ();
   rtx last_insn;
-  last_expr_type = 0;
+  clear_last_expr ();
 
   if (whichloop == 0)
     whichloop = loop_stack;
@@ -2899,7 +2723,7 @@ expand_exit_loop_if_false (whichloop, cond)
 }
 
 /* Like expand_exit_loop_if_false except also emit a note marking
-   the end of the conditional.  Should only be used immediately 
+   the end of the conditional.  Should only be used immediately
    after expand_loop_start.  */
 
 int
@@ -2964,7 +2788,7 @@ int
 expand_exit_something ()
 {
   struct nesting *n;
-  last_expr_type = 0;
+  clear_last_expr ();
   for (n = nesting_stack; n; n = n->all)
     if (n->exit_label != 0)
       {
@@ -2981,7 +2805,9 @@ expand_exit_something ()
 void
 expand_null_return ()
 {
-  rtx last_insn = get_last_insn ();
+  rtx last_insn;
+
+  last_insn = get_last_insn ();
 
   /* If this function was declared to return a value, but we
      didn't, clobber the return registers so that they are not
@@ -2991,14 +2817,58 @@ expand_null_return ()
   expand_null_return_1 (last_insn);
 }
 
+/* Try to guess whether the value of return means error code.  */
+static enum br_predictor
+return_prediction (val)
+     rtx val;
+{
+  /* Different heuristics for pointers and scalars.  */
+  if (POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
+    {
+      /* NULL is usually not returned.  */
+      if (val == const0_rtx)
+       return PRED_NULL_RETURN;
+    }
+  else
+    {
+      /* Negative return values are often used to indicate
+         errors.  */
+      if (GET_CODE (val) == CONST_INT
+         && INTVAL (val) < 0)
+       return PRED_NEGATIVE_RETURN;
+      /* Constant return values are also usually erors,
+         zero/one often mean booleans so exclude them from the
+        heuristics.  */
+      if (CONSTANT_P (val)
+         && (val != const0_rtx && val != const1_rtx))
+       return PRED_CONST_RETURN;
+    }
+  return PRED_NO_PREDICTION;
+}
+
 /* Generate RTL to return from the current function, with value VAL.  */
 
 static void
 expand_value_return (val)
      rtx val;
 {
-  rtx last_insn = get_last_insn ();
-  rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
+  rtx last_insn;
+  rtx return_reg;
+  enum br_predictor pred;
+
+  if ((pred = return_prediction (val)) != PRED_NO_PREDICTION)
+    {
+      /* Emit information for branch prediction.  */
+      rtx note;
+
+      note = emit_note (NULL, NOTE_INSN_PREDICTION);
+
+      NOTE_PREDICTION (note) = NOTE_PREDICT (pred, NOT_TAKEN);
+
+    }
+
+  last_insn = get_last_insn ();
+  return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
 
   /* Copy the value to the return location
      unless it's already there.  */
@@ -3036,7 +2906,7 @@ expand_null_return_1 (last_insn)
 
   clear_pending_stack_adjust ();
   do_pending_stack_adjust ();
-  last_expr_type = 0;
+  clear_last_expr ();
 
   if (end_label == 0)
      end_label = return_label = gen_label_rtx ();
@@ -3077,7 +2947,7 @@ expand_return (retval)
       /* Treat this like a return of no value from a function that
         returns a value.  */
       expand_null_return ();
-      return; 
+      return;
     }
   else if (TREE_CODE (retval) == RESULT_DECL)
     retval_rhs = retval;
@@ -3422,6 +3292,7 @@ expand_start_bindings_and_block (flags, block)
 
   /* Make an entry on block_stack for the block we are entering.  */
 
+  thisblock->desc = BLOCK_NESTING;
   thisblock->next = block_stack;
   thisblock->all = nesting_stack;
   thisblock->depth = ++nesting_depth;
@@ -3440,7 +3311,6 @@ expand_start_bindings_and_block (flags, block)
      instructions inserted after the last unconditional cleanup are
      never the last instruction.  */
   emit_note (NULL, NOTE_INSN_DELETED);
-  thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
 
   if (block_stack
       && !(block_stack->data.block.cleanups == NULL_TREE
@@ -3558,7 +3428,7 @@ expand_nl_handler_label (slot, before_insn)
   emit_move_insn (slot, gen_rtx_LABEL_REF (Pmode, handler_label));
   insns = get_insns ();
   end_sequence ();
-  emit_insns_before (insns, before_insn);
+  emit_insn_before (insns, before_insn);
 
   emit_label (handler_label);
 
@@ -3645,7 +3515,7 @@ expand_nl_goto_receivers (thisblock)
        emit_move_insn (save_receiver, XEXP (slot, 0));
        insns = get_insns ();
        end_sequence ();
-       emit_insns_before (insns, thisblock->data.block.first_insn);
+       emit_insn_before (insns, thisblock->data.block.first_insn);
       }
 
   /* Jump around the handlers; they run only when specially invoked.  */
@@ -4131,7 +4001,7 @@ expand_decl_cleanup (decl, cleanup)
          end_sequence ();
 
          thisblock->data.block.last_unconditional_cleanup
-           = emit_insns_after (set_flag_0,
+           = emit_insn_after (set_flag_0,
                                thisblock->data.block.last_unconditional_cleanup);
 
          emit_move_insn (flag, const1_rtx);
@@ -4146,7 +4016,7 @@ expand_decl_cleanup (decl, cleanup)
                           cleanup, integer_zero_node);
          cleanup = fold (cleanup);
 
-         cleanups = thisblock->data.block.cleanup_ptr;
+         cleanups = &thisblock->data.block.cleanups;
        }
 
       cleanup = unsave_expr (cleanup);
@@ -4173,8 +4043,8 @@ expand_decl_cleanup (decl, cleanup)
          end_sequence ();
          if (seq)
            thisblock->data.block.last_unconditional_cleanup
-             = emit_insns_after (seq,
-                                 thisblock->data.block.last_unconditional_cleanup);
+             = emit_insn_after (seq,
+                                thisblock->data.block.last_unconditional_cleanup);
        }
       else
        {
@@ -4187,7 +4057,6 @@ expand_decl_cleanup (decl, cleanup)
             instructions inserted after the last unconditional cleanup are
             never the last instruction.  */
          emit_note (NULL, NOTE_INSN_DELETED);
-         thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
        }
     }
   return 1;
@@ -4451,6 +4320,7 @@ expand_start_case (exit_flag, expr, type, printname)
 
   /* Make an entry on case_stack for the case we are entering.  */
 
+  thiscase->desc = CASE_NESTING;
   thiscase->next = case_stack;
   thiscase->all = nesting_stack;
   thiscase->depth = ++nesting_depth;
@@ -4488,6 +4358,7 @@ expand_start_case_dummy ()
 
   /* Make an entry on case_stack for the dummy.  */
 
+  thiscase->desc = CASE_NESTING;
   thiscase->next = case_stack;
   thiscase->all = nesting_stack;
   thiscase->depth = ++nesting_depth;
@@ -4739,7 +4610,7 @@ add_case_node (low, high, label, duplicate)
 
   /* Add this label to the chain, and succeed.  */
 
-  r = (struct case_node *) xmalloc (sizeof (struct case_node));
+  r = (struct case_node *) ggc_alloc (sizeof (struct case_node));
   r->low = low;
 
   /* If the bounds are equal, turn this into the one-value case.  */
@@ -5186,7 +5057,7 @@ check_for_full_enumeration_handling (type)
 
       /* The time complexity of this code is normally O(N), where
         N being the number of members in the enumerated type.
-        However, if type is a ENUMERAL_TYPE whose values do not
+        However, if type is an ENUMERAL_TYPE whose values do not
         increase monotonically, O(N*log(N)) time may be needed.  */
 
       mark_seen_cases (type, cases_seen, size, sparseness);
@@ -5214,7 +5085,7 @@ check_for_full_enumeration_handling (type)
           chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
           chain = TREE_CHAIN (chain))
        ;
-      
+
       if (!chain)
        {
          if (TYPE_NAME (type) == 0)
@@ -5234,7 +5105,7 @@ check_for_full_enumeration_handling (type)
               chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain));
               chain = TREE_CHAIN (chain))
            ;
-         
+
          if (!chain)
            {
              if (TYPE_NAME (type) == 0)
@@ -5252,20 +5123,6 @@ check_for_full_enumeration_handling (type)
     }
 }
 
-/* Free CN, and its children.  */
-
-static void 
-free_case_nodes (cn)
-     case_node_ptr cn;
-{
-  if (cn) 
-    {
-      free_case_nodes (cn->left);
-      free_case_nodes (cn->right);
-      free (cn);
-    }
-}
-
 \f
 
 /* Terminate a case (Pascal) or switch (C) statement
@@ -5500,21 +5357,21 @@ expand_end_case_type (orig_index, orig_type)
            {
              index_type = thiscase->data.case_stmt.nominal_type;
 
-              /* Index jumptables from zero for suitable values of
+             /* Index jumptables from zero for suitable values of
                  minval to avoid a subtraction.  */
-              if (! optimize_size
-                  && compare_tree_int (minval, 0) > 0
-                  && compare_tree_int (minval, 3) < 0)
-                {
-                  minval = integer_zero_node;
-                  range = maxval;
-                }
+             if (! optimize_size
+                 && compare_tree_int (minval, 0) > 0
+                 && compare_tree_int (minval, 3) < 0)
+               {
+                 minval = integer_zero_node;
+                 range = maxval;
+               }
 
              if (! try_tablejump (index_type, index_expr, minval, range,
                                   table_label, default_label))
                abort ();
            }
-         
+
          /* Get table of labels to jump to, in order of case index.  */
 
          ncases = tree_low_cst (range, 0) + 1;
@@ -5527,11 +5384,11 @@ expand_end_case_type (orig_index, orig_type)
                 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);
+               = 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);
+               = 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 ++)
@@ -5579,7 +5436,6 @@ expand_end_case_type (orig_index, orig_type)
   if (thiscase->exit_label)
     emit_label (thiscase->exit_label);
 
-  free_case_nodes (case_stack->data.case_stmt.case_list);
   POPSTACK (case_stack);
 
   free_temp_slots ();
@@ -6363,7 +6219,7 @@ emit_case_nodes (index, node, default_label, index_type)
              new_bound = expand_expr (fold (build (MINUS_EXPR, type,
                                                    high, low)),
                                       NULL_RTX, mode, 0);
-                               
+
              emit_cmp_and_jump_insns (new_index, new_bound, GT, NULL_RTX,
                                       mode, 1, default_label);
            }
@@ -6372,3 +6228,5 @@ emit_case_nodes (index, node, default_label, index_type)
        }
     }
 }
+
+#include "gt-stmt.h"