OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-nested.c
index 1a00ff3..b1ab217 100644 (file)
@@ -1,5 +1,5 @@
 /* Nested function decomposition for trees.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -55,7 +55,7 @@
 
    The implementation here is much more direct.  Everything that can be
    referenced by an inner function is a member of an explicitly created
-   structure herein called the "nonlocal frame struct".  The incomming
+   structure herein called the "nonlocal frame struct".  The incoming
    static chain for a nested function is a pointer to this struct in 
    the parent.  In this way, we settle on known offsets from a known
    base, and so are decoupled from the logic that places objects in the
@@ -132,20 +132,17 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix)
 {
   tree tmp_var;
 
-#if defined ENABLE_CHECKING
-  /* If the type is an array or a type which must be created by the
+  /* If the type is of variable size or a type which must be created by the
      frontend, something is wrong.  Note that we explicitly allow
      incomplete types here, since we create them ourselves here.  */
-  if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type))
-    abort ();
-  if (TYPE_SIZE_UNIT (type)
-      && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
-    abort ();
-#endif
+  gcc_assert (!TREE_ADDRESSABLE (type));
+  gcc_assert (!TYPE_SIZE_UNIT (type)
+             || TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
 
   tmp_var = create_tmp_var_raw (type, prefix);
   DECL_CONTEXT (tmp_var) = info->context;
   TREE_CHAIN (tmp_var) = info->new_local_var_chain;
+  DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
   info->new_local_var_chain = tmp_var;
 
   return tmp_var;
@@ -153,12 +150,14 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix)
 
 /* Take the address of EXP.  Mark it for addressability as necessary.  */
 
-static tree
+tree
 build_addr (tree exp)
 {
   tree base = exp;
-  while (TREE_CODE (base) == COMPONENT_REF || TREE_CODE (base) == ARRAY_REF)
+
+  while (handled_component_p (base))
     base = TREE_OPERAND (base, 0);
+
   if (DECL_P (base))
     TREE_ADDRESSABLE (base) = 1;
 
@@ -246,8 +245,7 @@ lookup_field_for_decl (struct nesting_info *info, tree decl,
   slot = htab_find_slot (info->var_map, &dummy, insert);
   if (!slot)
     {
-      if (insert == INSERT)
-       abort ();
+      gcc_assert (insert != INSERT);
       return NULL;
     }
   elt = *slot;
@@ -306,15 +304,16 @@ get_chain_decl (struct nesting_info *info)
 
       /* Note that this variable is *not* entered into any BIND_EXPR;
         the construction of this variable is handled specially in
-        expand_function_start and initialize_inlined_parameters.  */
-      decl = create_tmp_var_raw (type, "CHAIN");
+        expand_function_start and initialize_inlined_parameters.
+        Note also that it's represented as a parameter.  This is more
+        close to the truth, since the initial value does come from 
+        the caller.  */
+      decl = build_decl (PARM_DECL, create_tmp_var_name ("CHAIN"), type);
+      DECL_ARTIFICIAL (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
+      TREE_USED (decl) = 1;
       DECL_CONTEXT (decl) = info->context;
-      decl->decl.seen_in_bind_expr = 1;
-
-      /* The initialization of CHAIN is not visible to the tree-ssa
-        analyzers and optimizers.  Thus we do not want to issue
-        warnings for CHAIN.  */
-      TREE_NO_WARNING (decl) = 1;
+      DECL_ARG_TYPE (decl) = type;
 
       /* Tell tree-inline.c that we never write to this variable, so
         it can copy-prop the replacement value immediately.  */
@@ -369,7 +368,7 @@ init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
 /* Similarly, but only do so to force EXP to satisfy is_gimple_val.  */
 
 static tree
-gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
 {
   if (is_gimple_val (exp))
     return exp;
@@ -377,6 +376,23 @@ gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
     return init_tmp_var (info, exp, tsi);
 }
 
+/* Similarly, but copy from the temporary and insert the statement
+   after the iterator.  */
+
+static tree
+save_tmp_var (struct nesting_info *info, tree exp,
+             tree_stmt_iterator *tsi)
+{
+  tree t, stmt;
+
+  t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
+  stmt = build (MODIFY_EXPR, TREE_TYPE (t), exp, t);
+  SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
+  tsi_link_after (tsi, stmt, TSI_SAME_STMT);
+
+  return t;
+}
+
 /* Build or return the type used to represent a nested function trampoline.  */
 
 static GTY(()) tree trampoline_type;
@@ -401,7 +417,7 @@ get_trampoline_type (void)
       align = STACK_BOUNDARY;
     }
 
-  t = build_index_type (build_int_2 (size - 1, 0));
+  t = build_index_type (build_int_cst (NULL_TREE, size - 1));
   t = build_array_type (char_type_node, t);
   t = build_decl (FIELD_DECL, get_identifier ("__data"), t);
   DECL_ALIGN (t) = align;
@@ -430,8 +446,7 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl,
   slot = htab_find_slot (info->var_map, &dummy, insert);
   if (!slot)
     {
-      if (insert == INSERT)
-       abort ();
+      gcc_assert (insert != INSERT);
       return NULL;
     }
   elt = *slot;
@@ -473,7 +488,7 @@ get_nl_goto_field (struct nesting_info *info)
 
       /* For __builtin_nonlocal_goto, we need N words.  The first is the
         frame pointer, the rest is for the target's stack pointer save
-        area.  The number of words is controled by STACK_SAVEAREA_MODE;
+        area.  The number of words is controlled by STACK_SAVEAREA_MODE;
         not the best interface, but it'll do for now.  */
       if (Pmode == ptr_mode)
        type = ptr_type_node;
@@ -484,7 +499,8 @@ get_nl_goto_field (struct nesting_info *info)
       size = size / GET_MODE_SIZE (Pmode);
       size = size + 1;
 
-      type = build_array_type (type, build_index_type (build_int_2 (size, 0)));
+      type = build_array_type
+       (type, build_index_type (build_int_cst (NULL_TREE, size)));
 
       field = make_node (FIELD_DECL);
       DECL_NAME (field) = get_identifier ("__nl_goto_buf");
@@ -518,6 +534,8 @@ struct walk_stmt_info
   tree_stmt_iterator tsi;
   struct nesting_info *info;
   bool val_only;
+  bool is_lhs;
+  bool changed;
 };
 
 /* A subroutine of walk_function.  Iterate over all sub-statements of *TP.  */
@@ -549,6 +567,7 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp)
       break;
     case CATCH_EXPR:
       walk_stmts (wi, &CATCH_BODY (t));
+      break;
     case EH_FILTER_EXPR:
       walk_stmts (wi, &EH_FILTER_FAILURE (t));
       break;
@@ -566,12 +585,18 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp)
       break;
 
     case MODIFY_EXPR:
-      /* The immediate arguments of a MODIFY_EXPR may use COMPONENT_REF.  */
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
-      wi->val_only = false;
+      /* A formal temporary lhs may use a COMPONENT_REF rhs.  */
+      wi->val_only = !is_gimple_formal_tmp_var (TREE_OPERAND (t, 0));
       walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL);
+
+      /* If the rhs is appropriate for a memory, we may use a
+        COMPONENT_REF on the lhs.  */
+      wi->val_only = !is_gimple_mem_rhs (TREE_OPERAND (t, 1));
+      wi->is_lhs = true;
+      walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
+
       wi->val_only = true;
+      wi->is_lhs = false;
       break;
 
     default:
@@ -610,8 +635,49 @@ walk_all_functions (walk_tree_fn callback, struct nesting_info *root)
     }
   while (root);
 }
-
 \f
+/* We have to check for a fairly pathological case.  The operands of function
+   nested function are to be interpreted in the context of the enclosing
+   function.  So if any are variably-sized, they will get remapped when the
+   enclosing function is inlined.  But that remapping would also have to be
+   done in the types of the PARM_DECLs of the nested function, meaning the
+   argument types of that function will disagree with the arguments in the
+   calls to that function.  So we'd either have to make a copy of the nested
+   function corresponding to each time the enclosing function was inlined or
+   add a VIEW_CONVERT_EXPR to each such operand for each call to the nested
+   function.  The former is not practical.  The latter would still require
+   detecting this case to know when to add the conversions.  So, for now at
+   least, we don't inline such an enclosing function.
+
+   We have to do that check recursively, so here return indicating whether
+   FNDECL has such a nested function.  ORIG_FN is the function we were
+   trying to inline to use for checking whether any argument is variably
+   modified by anything in it.
+
+   It would be better to do this in tree-inline.c so that we could give
+   the appropriate warning for why a function can't be inlined, but that's
+   too late since the nesting structure has already been flattened and
+   adding a flag just to record this fact seems a waste of a flag.  */
+
+static bool
+check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
+{
+  struct cgraph_node *cgn = cgraph_node (fndecl);
+  tree arg;
+
+  for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+    {
+      for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg))
+       if (variably_modified_type_p (TREE_TYPE (arg), 0), orig_fndecl)
+         return true;
+
+      if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl))
+       return true;
+    }
+
+  return false;
+}
+
 /* Construct our local datastructure describing the function nesting
    tree rooted by CGN.  */
 
@@ -630,6 +696,11 @@ create_nesting_tree (struct cgraph_node *cgn)
       info->inner = sub;
     }
 
+  /* See discussion at check_for_nested_with_variably_modified for a
+     discussion of why this has to be here.  */
+  if (check_for_nested_with_variably_modified (info->context, info->context))
+    DECL_UNINLINABLE (info->context) = true;
+
   return info;
 }
 
@@ -656,7 +727,7 @@ get_static_chain (struct nesting_info *info, tree target_context,
          tree field = get_chain_field (i);
 
          x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
-         x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+         x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
          x = init_tmp_var (info, x, tsi);
        }
     }
@@ -690,14 +761,14 @@ get_frame_field (struct nesting_info *info, tree target_context,
          tree field = get_chain_field (i);
 
          x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
-         x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+         x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
          x = init_tmp_var (info, x, tsi);
        }
 
       x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
     }
 
-  x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+  x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
   return x;
 }
 
@@ -731,6 +802,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
          tree target_context = decl_function_context (t);
          struct nesting_info *i;
          tree x;
+         wi->changed = true;
 
          for (i = info->outer; i->context != target_context; i = i->outer)
            continue;
@@ -741,8 +813,14 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
              x = init_tmp_var (info, x, &wi->tsi);
              x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
            }
+
          if (wi->val_only)
-           x = init_tmp_var (info, x, &wi->tsi);
+           {
+             if (wi->is_lhs)
+               x = save_tmp_var (info, x, &wi->tsi);
+             else
+               x = init_tmp_var (info, x, &wi->tsi);
+           }
 
          *tp = x;
        }
@@ -754,6 +832,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
        {
          *walk_subtrees = 1;
          wi->val_only = true;
+         wi->is_lhs = false;
        }
       break;
 
@@ -769,55 +848,72 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
     case ADDR_EXPR:
       {
        bool save_val_only = wi->val_only;
-       tree save_sub = TREE_OPERAND (t, 0);
 
        wi->val_only = false;
+       wi->is_lhs = false;
+       wi->changed = false;
        walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
        wi->val_only = true;
 
-       if (save_sub != TREE_OPERAND (t, 0))
+       if (wi->changed)
          {
            /* If we changed anything, then TREE_INVARIANT is be wrong,
               since we're no longer directly referencing a decl.  */
-           TREE_INVARIANT (t) = 0;
+           recompute_tree_invarant_for_addr_expr (t);
 
            /* If the callback converted the address argument in a context
               where we only accept variables (and min_invariant, presumably),
               then compute the address into a temporary.  */
            if (save_val_only)
-             *tp = gimplify_val (wi->info, t, &wi->tsi);
+             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
          }
       }
       break;
 
-    case COMPONENT_REF:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
-      wi->val_only = true;
-      break;
-
+    case COMPONENT_REF:
     case ARRAY_REF:
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
-      wi->val_only = true;
-      walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL);
-      break;
-
+    case ARRAY_RANGE_REF:
     case BIT_FIELD_REF:
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
+      /* Go down this entire nest and just look at the final prefix and
+        anything that describes the references.  Otherwise, we lose track
+        of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value.  */
       wi->val_only = true;
-      walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL);
-      walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, NULL);
+      wi->is_lhs = false;
+      for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
+       {
+         if (TREE_CODE (t) == COMPONENT_REF)
+           walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+                      NULL);
+         else if (TREE_CODE (t) == ARRAY_REF
+                  || TREE_CODE (t) == ARRAY_RANGE_REF)
+           {
+             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
+                        NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+                        NULL);
+             walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi,
+                        NULL);
+           }
+         else if (TREE_CODE (t) == BIT_FIELD_REF)
+           {
+             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
+                        NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+                        NULL);
+           }
+       }
+      wi->val_only = false;
+      walk_tree (tp, convert_nonlocal_reference, wi, NULL);
       break;
 
     default:
-      if (!DECL_P (t) && !TYPE_P (t))
+      if (!IS_TYPE_OR_DECL_P (t))
        {
          *walk_subtrees = 1;
           wi->val_only = true;
+         wi->is_lhs = false;
        }
       break;
     }
@@ -834,7 +930,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = data;
   struct nesting_info *info = wi->info;
-  tree t = *tp, field, x, y;
+  tree t = *tp, field, x;
 
   switch (TREE_CODE (t))
     {
@@ -857,10 +953,18 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
          field = lookup_field_for_decl (info, t, NO_INSERT);
          if (!field)
            break;
+         wi->changed = true;
 
          x = get_frame_field (info, info->context, field, &wi->tsi);
+
          if (wi->val_only)
-           x = init_tmp_var (info, x, &wi->tsi);
+           {
+             if (wi->is_lhs)
+               x = save_tmp_var (info, x, &wi->tsi);
+             else
+               x = init_tmp_var (info, x, &wi->tsi);
+           }
+
          *tp = x;
        }
       break;
@@ -868,88 +972,73 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
     case ADDR_EXPR:
       {
        bool save_val_only = wi->val_only;
-       tree save_sub = TREE_OPERAND (t, 0);
 
        wi->val_only = false;
+       wi->is_lhs = false;
+       wi->changed = false;
        walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
        wi->val_only = save_val_only;
 
        /* If we converted anything ... */
-       if (TREE_OPERAND (t, 0) != save_sub)
+       if (wi->changed)
          {
            /* Then the frame decl is now addressable.  */
            TREE_ADDRESSABLE (info->frame_decl) = 1;
+           
+           recompute_tree_invarant_for_addr_expr (t);
 
            /* If we are in a context where we only accept values, then
               compute the address into a temporary.  */
            if (save_val_only)
-             *tp = gimplify_val (wi->info, t, &wi->tsi);
+             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
          }
       }
       break;
 
-    case CALL_EXPR:
-      *walk_subtrees = 1;
-
-      /* Ready for some fun?  We need to recognize
-           __builtin_stack_alloc (&x, n)
-        and insert
-           FRAME.x = &x
-        after that.  X should have use_pointer_in_frame set.  We can't
-        do this any earlier, since we can't meaningfully evaluate &x.  */
-
-      x = get_callee_fndecl (t);
-      if (!x || DECL_BUILT_IN_CLASS (x) != BUILT_IN_NORMAL)
-       break;
-      if (DECL_FUNCTION_CODE (x) != BUILT_IN_STACK_ALLOC)
-       break;
-      t = TREE_VALUE (TREE_OPERAND (t, 1));
-      if (TREE_CODE (t) != ADDR_EXPR)
-       abort ();
-      t = TREE_OPERAND (t, 0);
-      if (TREE_CODE (t) != VAR_DECL)
-       abort ();
-      field = lookup_field_for_decl (info, t, NO_INSERT);
-      if (!field)
-       break;
-      if (!use_pointer_in_frame (t))
-       abort ();
-
-      x = build_addr (t);
-      y = get_frame_field (info, info->context, field, &wi->tsi);
-      x = build (MODIFY_EXPR, void_type_node, y, x);
-      SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
-      tsi_link_after (&wi->tsi, x, TSI_SAME_STMT);
-      break;
-
-    case COMPONENT_REF:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
-      wi->val_only = true;
-      break;
-
+    case COMPONENT_REF:
     case ARRAY_REF:
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
-      wi->val_only = true;
-      walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL);
-      break;
-
+    case ARRAY_RANGE_REF:
     case BIT_FIELD_REF:
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
+      /* Go down this entire nest and just look at the final prefix and
+        anything that describes the references.  Otherwise, we lose track
+        of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value.  */
       wi->val_only = true;
-      walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL);
-      walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, NULL);
+      wi->is_lhs = false;
+      for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
+       {
+         if (TREE_CODE (t) == COMPONENT_REF)
+           walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+                      NULL);
+         else if (TREE_CODE (t) == ARRAY_REF
+                  || TREE_CODE (t) == ARRAY_RANGE_REF)
+           {
+             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+                        NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+                        NULL);
+             walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi,
+                        NULL);
+           }
+         else if (TREE_CODE (t) == BIT_FIELD_REF)
+           {
+             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+                        NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+                        NULL);
+           }
+       }
+      wi->val_only = false;
+      walk_tree (tp, convert_local_reference, wi, NULL);
       break;
 
     default:
-      if (!DECL_P (t) && !TYPE_P (t))
+      if (!IS_TYPE_OR_DECL_P (t))
        {
          *walk_subtrees = 1;
          wi->val_only = true;
+         wi->is_lhs = false;
        }
       break;
     }
@@ -986,7 +1075,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
   /* The original user label may also be use for a normal goto, therefore
      we must create a new label that will actually receive the abnormal
      control transfer.  This new label will be marked LABEL_NONLOCAL; this
-     mark will trigger proper behaviour in the cfg, as well as cause the
+     mark will trigger proper behavior in the cfg, as well as cause the
      (hairy target-specific) non-local goto receiver code to be generated
      when we expand rtl.  */
   new_label = create_artificial_label ();
@@ -1004,7 +1093,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
   field = get_nl_goto_field (i);
   x = get_frame_field (info, target_context, field, &wi->tsi);
   x = build_addr (x);
-  x = gimplify_val (info, x, &wi->tsi);
+  x = tsi_gimplify_val (info, x, &wi->tsi);
   arg = tree_cons (NULL, x, NULL);
   x = build_addr (new_label);
   arg = tree_cons (NULL, x, arg);
@@ -1102,7 +1191,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       /* Compute the address of the field holding the trampoline.  */
       x = get_frame_field (info, target_context, x, &wi->tsi);
       x = build_addr (x);
-      x = gimplify_val (info, x, &wi->tsi);
+      x = tsi_gimplify_val (info, x, &wi->tsi);
       arg = tree_cons (NULL, x, NULL);
 
       /* Do machine-specific ugliness.  Normally this will involve
@@ -1125,7 +1214,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     default:
-      if (!DECL_P (t) && !TYPE_P (t))
+      if (!IS_TYPE_OR_DECL_P (t))
        *walk_subtrees = 1;
       break;
     }
@@ -1159,7 +1248,8 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
 
     case RETURN_EXPR:
     case MODIFY_EXPR:
-      /* Only return and modify may contain calls.  */
+    case WITH_SIZE_EXPR:
+      /* Only return modify and with_size_expr may contain calls.  */
       *walk_subtrees = 1;
       break;
 
@@ -1189,12 +1279,7 @@ convert_all_function_calls (struct nesting_info *root)
       if (root->outer && !root->chain_decl && !root->chain_field)
        DECL_NO_STATIC_CHAIN (root->context) = 1;
       else
-       {
-#ifdef ENABLE_CHECKING
-         if (DECL_NO_STATIC_CHAIN (root->context))
-           abort ();
-#endif
-       }
+       gcc_assert (!DECL_NO_STATIC_CHAIN (root->context));
 
       root = root->next;
     }
@@ -1212,6 +1297,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
   tree stmt_list = NULL;
   tree context = root->context;
   struct function *sf;
+  struct cgraph_node *node;
 
   /* If we created a non-local frame type or decl, we need to lay them
      out at this time.  */
@@ -1241,7 +1327,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
            x = p;
 
          y = build (COMPONENT_REF, TREE_TYPE (field),
-                    root->frame_decl, field);
+                    root->frame_decl, field, NULL_TREE);
          x = build (MODIFY_EXPR, TREE_TYPE (field), y, x);
          append_to_statement_list (x, &stmt_list);
        }
@@ -1251,9 +1337,8 @@ finalize_nesting_tree_1 (struct nesting_info *root)
      from chain_decl.  */
   if (root->chain_field)
     {
-      tree x;
-      x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
-                root->frame_decl, root->chain_field);
+      tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
+                     root->frame_decl, root->chain_field, NULL_TREE);
       x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
       append_to_statement_list (x, &stmt_list);
     }
@@ -1280,7 +1365,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
          arg = tree_cons (NULL, x, arg);
 
          x = build (COMPONENT_REF, TREE_TYPE (field),
-                    root->frame_decl, field);
+                    root->frame_decl, field, NULL_TREE);
          x = build_addr (x);
          arg = tree_cons (NULL, x, arg);
 
@@ -1315,7 +1400,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
       sf->has_nonlocal_label = 1;
     }
 
-  /* Make sure all new local variables get insertted into the
+  /* Make sure all new local variables get inserted into the
      proper BIND_EXPR.  */
   if (root->new_local_var_chain)
     declare_tmp_vars (root->new_local_var_chain,
@@ -1323,6 +1408,15 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 
   /* Dump the translated tree function.  */
   dump_function (TDI_nested, root->context);
+  node = cgraph_node (root->context);
+
+  /* For nested functions update the cgraph to reflect unnesting.
+     We also delay finalizing of these functions up to this point.  */
+  if (node->origin)
+    {
+       cgraph_unnest_node (cgraph_node (root->context));
+       cgraph_finalize_function (root->context, true);
+    }
 }
 
 static void