OSDN Git Service

2007-06-05 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-nested.c
index 124bbf9..f26c9ba 100644 (file)
@@ -1,5 +1,5 @@
 /* Nested function decomposition for trees.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -15,8 +15,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -34,6 +34,7 @@
 #include "cgraph.h"
 #include "expr.h"
 #include "langhooks.h"
+#include "pointer-set.h"
 #include "ggc.h"
 
 
    been written as independent functions without change.  */
 
 
-struct var_map_elt
-{
-  tree old;
-  tree new;
-};
-
 struct nesting_info
 {
   struct nesting_info *outer;
   struct nesting_info *inner;
   struct nesting_info *next;
   
-  htab_t var_map;
+  struct pointer_map_t *field_map;
+  struct pointer_map_t *var_map;
+  bitmap suppress_expansion;
+
   tree context;
   tree new_local_var_chain;
+  tree debug_var_chain;
   tree frame_type;
   tree frame_decl;
   tree chain_field;
@@ -100,25 +99,13 @@ struct nesting_info
 
   bool any_parm_remapped;
   bool any_tramp_created;
+  char static_chain_added;
 };
 
 
-/* Hashing and equality functions for nesting_info->var_map.  */
-
-static hashval_t
-var_map_hash (const void *x)
-{
-  const struct var_map_elt *a = x;
-  return htab_hash_pointer (a->old);
-}
+/* Obstack used for the bitmaps in the struct above.  */
+static struct bitmap_obstack nesting_info_bitmap_obstack;
 
-static int
-var_map_eq (const void *x, const void *y)
-{
-  const struct var_map_elt *a = x;
-  const struct var_map_elt *b = y;
-  return a->old == b->old;
-}
 
 /* We're working in so many different function contexts simultaneously,
    that create_tmp_var is dangerous.  Prevent mishap.  */
@@ -143,6 +130,10 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *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;
+  if (TREE_CODE (type) == COMPLEX_TYPE
+      || TREE_CODE (type) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (tmp_var) = 1;
+
   info->new_local_var_chain = tmp_var;
 
   return tmp_var;
@@ -174,13 +165,13 @@ build_addr (tree exp, tree context)
   save_context = current_function_decl;
   current_function_decl = context;
   retval = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
-  current_function_decl = save_context;;
+  current_function_decl = save_context;
   return retval;
 }
 
 /* Insert FIELD into TYPE, sorted by alignment requirements.  */
 
-static void
+void
 insert_field_into_struct (tree type, tree field)
 {
   tree *p;
@@ -220,6 +211,14 @@ get_frame_type (struct nesting_info *info)
 
       info->frame_type = type;
       info->frame_decl = create_tmp_var_for (info, type, "FRAME");
+
+      /* ??? Always make it addressable for now, since it is meant to
+        be pointed to by the static chain pointer.  This pessimizes
+        when it turns out that no static chains are needed because
+        the nested functions referencing non-local variables are not
+        reachable, but the true pessimization is to create the non-
+        local frame structure in the first place.  */
+      TREE_ADDRESSABLE (info->frame_decl) = 1;
     }
   return type;
 }
@@ -251,22 +250,18 @@ static tree
 lookup_field_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
-  tree field;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, insert);
-  if (!slot)
+  if (insert == NO_INSERT)
     {
-      gcc_assert (insert != INSERT);
-      return NULL;
+      slot = pointer_map_contains (info->field_map, decl);
+      return slot ? *slot : NULL;
     }
-  elt = *slot;
 
-  if (!elt && insert == INSERT)
+  slot = pointer_map_insert (info->field_map, decl);
+  if (!*slot)
     {
-      field = make_node (FIELD_DECL);
+      tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
 
       if (use_pointer_in_frame (decl))
@@ -287,19 +282,13 @@ lookup_field_for_decl (struct nesting_info *info, tree decl,
        }
 
       insert_field_into_struct (get_frame_type (info), field);
-  
-      elt = xmalloc (sizeof (*elt));
-      elt->old = decl;
-      elt->new = field;
-      *slot = elt;
+      *slot = field;
 
       if (TREE_CODE (decl) == PARM_DECL)
        info->any_parm_remapped = true;
     }
-  else
-    field = elt ? elt->new : NULL;
 
-  return field;
+  return *slot;
 }
 
 /* Build or return the variable that holds the static chain within
@@ -372,7 +361,7 @@ init_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), t, exp);
+  stmt = build_gimple_modify_stmt (t, exp);
   SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
   tsi_link_before (tsi, stmt, TSI_SAME_STMT);
 
@@ -400,7 +389,7 @@ save_tmp_var (struct nesting_info *info, tree exp,
   tree t, stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build (MODIFY_EXPR, TREE_TYPE (t), exp, t);
+  stmt = build_gimple_modify_stmt (exp, t);
   SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
   tsi_link_after (tsi, stmt, TSI_SAME_STMT);
 
@@ -452,39 +441,29 @@ static tree
 lookup_tramp_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
-  tree field;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, insert);
-  if (!slot)
+  if (insert == NO_INSERT)
     {
-      gcc_assert (insert != INSERT);
-      return NULL;
+      slot = pointer_map_contains (info->var_map, decl);
+      return slot ? *slot : NULL;
     }
-  elt = *slot;
 
-  if (!elt && insert == INSERT)
+  slot = pointer_map_insert (info->var_map, decl);
+  if (!*slot)
     {
-      field = make_node (FIELD_DECL);
+      tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
       TREE_TYPE (field) = get_trampoline_type ();
       TREE_ADDRESSABLE (field) = 1;
 
       insert_field_into_struct (get_frame_type (info), field);
-
-      elt = xmalloc (sizeof (*elt));
-      elt->old = decl;
-      elt->new = field;
-      *slot = elt;
+      *slot = field;
 
       info->any_tramp_created = true;
     }
-  else
-    field = elt ? elt->new : NULL;
 
-  return field;
+  return *slot;
 } 
 
 /* Build or return the field within the non-local frame state that holds
@@ -530,37 +509,62 @@ get_nl_goto_field (struct nesting_info *info)
   return field;
 }
 \f
-/* Convenience routines to walk all statements of a gimple function.
-
-   For each statement, we invoke CALLBACK via walk_tree.  The passed
-   data is a walk_stmt_info structure.  Of note here is a TSI that
-   points to the current statement being walked.  The VAL_ONLY flag
-   that indicates whether the *TP being examined may be replaced 
-   with something that matches is_gimple_val (if true) or something
-   slightly more complicated (if false).  "Something" technically 
-   means the common subset of is_gimple_lvalue and is_gimple_rhs, 
-   but we never try to form anything more complicated than that, so
-   we don't bother checking.  */
-
-struct walk_stmt_info
+/* Helper function for walk_stmts.  Walk output operands of an ASM_EXPR.  */
+
+static void
+walk_asm_expr (struct walk_stmt_info *wi, tree stmt)
 {
-  walk_tree_fn callback;
-  tree_stmt_iterator tsi;
-  struct nesting_info *info;
-  bool val_only;
-  bool is_lhs;
-  bool changed;
-};
+  int noutputs = list_length (ASM_OUTPUTS (stmt));
+  const char **oconstraints
+    = (const char **) alloca ((noutputs) * sizeof (const char *));
+  int i;
+  tree link;
+  const char *constraint;
+  bool allows_mem, allows_reg, is_inout;
+
+  wi->is_lhs = true;
+  for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
+    {
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+      oconstraints[i] = constraint;
+      parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
+                              &allows_reg, &is_inout);
 
-/* A subroutine of walk_function.  Iterate over all sub-statements of *TP.  */
+      wi->val_only = (allows_reg || !allows_mem);
+      walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+    }
 
-static void
+  for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
+    {
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+      parse_input_constraint (&constraint, 0, 0, noutputs, 0,
+                             oconstraints, &allows_mem, &allows_reg);
+
+      wi->val_only = (allows_reg || !allows_mem);
+      /* Although input "m" is not really a LHS, we need a lvalue.  */
+      wi->is_lhs = !wi->val_only;
+      walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+    }
+
+  wi->is_lhs = false;
+  wi->val_only = true;
+}
+
+/* Iterate over all sub-statements of *TP calling walk_tree with
+   WI->CALLBACK for every sub-expression in each statement found.  */
+
+void
 walk_stmts (struct walk_stmt_info *wi, tree *tp)
 {
   tree t = *tp;
+  int walk_subtrees;
+
   if (!t)
     return;
 
+  if (wi->want_locations && EXPR_HAS_LOCATION (t))
+    input_location = EXPR_LOCATION (t);
+
   switch (TREE_CODE (t))
     {
     case STATEMENT_LIST:
@@ -590,29 +594,48 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp)
       walk_stmts (wi, &TREE_OPERAND (t, 0));
       walk_stmts (wi, &TREE_OPERAND (t, 1));
       break;
+
     case BIND_EXPR:
+      if (wi->want_bind_expr)
+       {
+         walk_subtrees = 1;
+         wi->callback (tp, &walk_subtrees, wi);
+         if (!walk_subtrees)
+           break;
+       }
       walk_stmts (wi, &BIND_EXPR_BODY (t));
       break;
 
     case RETURN_EXPR:
+      if (wi->want_return_expr)
+       {
+         walk_subtrees = 1;
+         wi->callback (tp, &walk_subtrees, wi);
+         if (!walk_subtrees)
+           break;
+       }
       walk_stmts (wi, &TREE_OPERAND (t, 0));
       break;
 
-    case MODIFY_EXPR:
+    case GIMPLE_MODIFY_STMT:
       /* 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);
+      wi->val_only = !is_gimple_formal_tmp_var (GIMPLE_STMT_OPERAND (t, 0));
+      walk_tree (&GIMPLE_STMT_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->val_only = !is_gimple_mem_rhs (GIMPLE_STMT_OPERAND (t, 1));
       wi->is_lhs = true;
-      walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 0), wi->callback, wi, NULL);
 
       wi->val_only = true;
       wi->is_lhs = false;
       break;
 
+    case ASM_EXPR:
+      walk_asm_expr (wi, *tp);
+      break;
+
     default:
       wi->val_only = true;
       walk_tree (tp, wi->callback, wi, NULL);
@@ -620,10 +643,10 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp)
     }
 }
 
-/* Invoke CALLBACK on all statements of INFO->CONTEXT.  */
+/* Invoke CALLBACK on all statements of *STMT_P.  */
 
 static void
-walk_function (walk_tree_fn callback, struct nesting_info *info)
+walk_body (walk_tree_fn callback, struct nesting_info *info, tree *stmt_p)
 {
   struct walk_stmt_info wi;
 
@@ -632,7 +655,15 @@ walk_function (walk_tree_fn callback, struct nesting_info *info)
   wi.info = info;
   wi.val_only = true;
 
-  walk_stmts (&wi, &DECL_SAVED_TREE (info->context));
+  walk_stmts (&wi, stmt_p);
+}
+
+/* Invoke CALLBACK on all statements of INFO->CONTEXT.  */
+
+static inline void
+walk_function (walk_tree_fn callback, struct nesting_info *info)
+{
+  walk_body (callback, info, &DECL_SAVED_TREE (info->context));
 }
 
 /* Similarly for ROOT and all functions nested underneath, depth first.  */
@@ -698,8 +729,10 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
 static struct nesting_info *
 create_nesting_tree (struct cgraph_node *cgn)
 {
-  struct nesting_info *info = xcalloc (1, sizeof (*info));
-  info->var_map = htab_create (7, var_map_hash, var_map_eq, free);
+  struct nesting_info *info = XCNEW (struct nesting_info);
+  info->field_map = pointer_map_create ();
+  info->var_map = pointer_map_create ();
+  info->suppress_expansion = BITMAP_ALLOC (&nesting_info_bitmap_obstack);
   info->context = cgn->decl;
 
   for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
@@ -741,7 +774,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, NULL_TREE);
+         x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
          x = init_tmp_var (info, x, tsi);
        }
     }
@@ -775,17 +808,84 @@ 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, NULL_TREE);
+         x = build3 (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, NULL_TREE);
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
   return x;
 }
 
+/* A subroutine of convert_nonlocal_reference.  Create a local variable
+   in the nested function with DECL_VALUE_EXPR set to reference the true
+   variable in the parent function.  This is used both for debug info 
+   and in OpenMP lowering.  */
+
+static tree
+get_nonlocal_debug_decl (struct nesting_info *info, tree decl)
+{
+  tree target_context;
+  struct nesting_info *i;
+  tree x, field, new_decl;
+  void **slot;
+
+  slot = pointer_map_insert (info->var_map, decl);
+
+  if (*slot)
+    return *slot;
+
+  target_context = decl_function_context (decl);
+
+  /* A copy of the code in get_frame_field, but without the temporaries.  */
+  if (info->context == target_context)
+    {
+      /* Make sure frame_decl gets created.  */
+      (void) get_frame_type (info);
+      x = info->frame_decl;
+      i = info;
+    }
+  else
+    {
+      x = get_chain_decl (info);
+      for (i = info->outer; i->context != target_context; i = i->outer)
+       {
+         field = get_chain_field (i);
+         x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+         x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+       }
+      x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+    }
+
+  field = lookup_field_for_decl (i, decl, INSERT);
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+  if (use_pointer_in_frame (decl))
+    x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+
+  /* ??? We should be remapping types as well, surely.  */
+  new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+  DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+  TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+  TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+  TREE_READONLY (new_decl) = TREE_READONLY (decl);
+  TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+  DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+
+  SET_DECL_VALUE_EXPR (new_decl, x);
+  DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
+
+  *slot = new_decl;
+  TREE_CHAIN (new_decl) = info->debug_var_chain;
+  info->debug_var_chain = new_decl;
+
+  return new_decl;
+}
+
 /* Called via walk_function+walk_tree, rewrite all references to VAR
    and PARM_DECLs that belong to outer functions.
 
@@ -794,12 +894,16 @@ get_frame_field (struct nesting_info *info, tree target_context,
    be CHAIN->FOO.  For two levels it'll be CHAIN->__chain->FOO.  Further
    indirections apply to decls for which use_pointer_in_frame is true.  */
 
+static bool convert_nonlocal_omp_clauses (tree *, struct walk_stmt_info *);
+
 static tree
 convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = data;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
   struct nesting_info *info = wi->info;
   tree t = *tp;
+  tree save_local_var_chain;
+  bitmap save_suppress;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -813,19 +917,23 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
     case PARM_DECL:
       if (decl_function_context (t) != info->context)
        {
-         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;
-         x = lookup_field_for_decl (i, t, INSERT);
-         x = get_frame_field (info, target_context, x, &wi->tsi);
-         if (use_pointer_in_frame (t))
+         x = get_nonlocal_debug_decl (info, t);
+         if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
            {
-             x = init_tmp_var (info, x, &wi->tsi);
-             x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+             tree target_context = decl_function_context (t);
+             struct nesting_info *i;
+             for (i = info->outer; i->context != target_context; i = i->outer)
+               continue;
+             x = lookup_field_for_decl (i, t, INSERT);
+             x = get_frame_field (info, target_context, x, &wi->tsi);
+             if (use_pointer_in_frame (t))
+               {
+                 x = init_tmp_var (info, x, &wi->tsi);
+                 x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+               }
            }
 
          if (wi->val_only)
@@ -871,9 +979,14 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
 
        if (wi->changed)
          {
+           tree save_context;
+
            /* If we changed anything, then TREE_INVARIANT is be wrong,
               since we're no longer directly referencing a decl.  */
-           recompute_tree_invarant_for_addr_expr (t);
+           save_context = current_function_decl;
+           current_function_decl = info->context;
+           recompute_tree_invariant_for_addr_expr (t);
+           current_function_decl = save_context;
 
            /* If the callback converted the address argument in a context
               where we only accept variables (and min_invariant, presumably),
@@ -922,6 +1035,44 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       walk_tree (tp, convert_nonlocal_reference, wi, NULL);
       break;
 
+    case OMP_PARALLEL:
+      save_suppress = info->suppress_expansion;
+      if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
+       {
+         tree c, decl;
+         decl = get_chain_decl (info);
+         c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
+         OMP_CLAUSE_DECL (c) = decl;
+         OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
+         OMP_PARALLEL_CLAUSES (t) = c;
+       }
+
+      save_local_var_chain = info->new_local_var_chain;
+      info->new_local_var_chain = NULL;
+
+      walk_body (convert_nonlocal_reference, info, &OMP_PARALLEL_BODY (t));
+
+      if (info->new_local_var_chain)
+       declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
+      info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case OMP_FOR:
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (&OMP_CLAUSES (t), wi);
+      walk_body (convert_nonlocal_reference, info, &OMP_BODY (t));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case OMP_SECTION:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+      walk_body (convert_nonlocal_reference, info, &OMP_BODY (t));
+      break;
+
     default:
       if (!IS_TYPE_OR_DECL_P (t))
        {
@@ -935,17 +1086,126 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+static bool
+convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+  struct nesting_info *info = wi->info;
+  bool need_chain = false;
+  tree clause, decl;
+  int dummy;
+  bitmap new_suppress;
+
+  new_suppress = BITMAP_GGC_ALLOC ();
+  bitmap_copy (new_suppress, info->suppress_expansion);
+
+  for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+    {
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_PRIVATE:
+       case OMP_CLAUSE_FIRSTPRIVATE:
+       case OMP_CLAUSE_LASTPRIVATE:
+       case OMP_CLAUSE_REDUCTION:
+       case OMP_CLAUSE_COPYPRIVATE:
+       case OMP_CLAUSE_SHARED:
+         decl = OMP_CLAUSE_DECL (clause);
+         if (decl_function_context (decl) != info->context)
+           {
+             bitmap_set_bit (new_suppress, DECL_UID (decl));
+             OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
+             need_chain = true;
+           }
+         break;
+
+       case OMP_CLAUSE_SCHEDULE:
+         if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
+           break;
+         /* FALLTHRU */
+       case OMP_CLAUSE_IF:
+       case OMP_CLAUSE_NUM_THREADS:
+         wi->val_only = true;
+         wi->is_lhs = false;
+         convert_nonlocal_reference (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
+                                     wi);
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_COPYIN:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  info->suppress_expansion = new_suppress;
+
+  return need_chain;
+}
+
+/* A subroutine of convert_local_reference.  Create a local variable
+   in the parent function with DECL_VALUE_EXPR set to reference the
+   field in FRAME.  This is used both for debug info and in OpenMP
+   lowering.  */
+
+static tree
+get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
+{
+  tree x, new_decl;
+  void **slot;
+
+  slot = pointer_map_insert (info->var_map, decl);
+  if (*slot)
+    return *slot;
+
+  /* Make sure frame_decl gets created.  */
+  (void) get_frame_type (info);
+  x = info->frame_decl;
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+
+  new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+  DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+  TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+  TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+  TREE_READONLY (new_decl) = TREE_READONLY (decl);
+  TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+  DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+
+  SET_DECL_VALUE_EXPR (new_decl, x);
+  DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
+  *slot = new_decl;
+
+  TREE_CHAIN (new_decl) = info->debug_var_chain;
+  info->debug_var_chain = new_decl;
+
+  /* Do not emit debug info twice.  */
+  DECL_IGNORED_P (decl) = 1;
+
+  return new_decl;
+}
+
 /* Called via walk_function+walk_tree, rewrite all references to VAR
    and PARM_DECLs that were referenced by inner nested functions.
    The rewrite will be a structure reference to the local frame variable.  */
 
+static bool convert_local_omp_clauses (tree *, struct walk_stmt_info *);
+
 static tree
 convert_local_reference (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = data;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
   struct nesting_info *info = wi->info;
   tree t = *tp, field, x;
+  bool save_val_only;
+  tree save_local_var_chain;
+  bitmap save_suppress;
 
+  *walk_subtrees = 0;
   switch (TREE_CODE (t))
     {
     case VAR_DECL:
@@ -969,7 +1229,9 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
            break;
          wi->changed = true;
 
-         x = get_frame_field (info, info->context, field, &wi->tsi);
+         x = get_local_debug_decl (info, t, field);
+         if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+           x = get_frame_field (info, info->context, field, &wi->tsi);
 
          if (wi->val_only)
            {
@@ -984,29 +1246,31 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case ADDR_EXPR:
-      {
-       bool save_val_only = wi->val_only;
+      save_val_only = wi->val_only;
+      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;
 
-       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 (wi->changed)
+       {
+         tree save_context;
 
-       /* If we converted anything ... */
-       if (wi->changed)
-         {
-           /* Then the frame decl is now addressable.  */
-           TREE_ADDRESSABLE (info->frame_decl) = 1;
+         /* 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 = tsi_gimplify_val (wi->info, t, &wi->tsi);
-         }
-      }
+         save_context = current_function_decl;
+         current_function_decl = info->context;
+         recompute_tree_invariant_for_addr_expr (t);
+         current_function_decl = save_context;
+
+         /* If we are in a context where we only accept values, then
+            compute the address into a temporary.  */
+         if (save_val_only)
+           *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+       }
       break;
 
     case REALPART_EXPR:
@@ -1018,6 +1282,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       /* 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.  */
+      save_val_only = wi->val_only;
       wi->val_only = true;
       wi->is_lhs = false;
       for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
@@ -1045,6 +1310,45 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
        }
       wi->val_only = false;
       walk_tree (tp, convert_local_reference, wi, NULL);
+      wi->val_only = save_val_only;
+      break;
+
+    case OMP_PARALLEL:
+      save_suppress = info->suppress_expansion;
+      if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
+       {
+         tree c;
+         (void) get_frame_type (info);
+         c = build_omp_clause (OMP_CLAUSE_SHARED);
+         OMP_CLAUSE_DECL (c) = info->frame_decl;
+         OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
+         OMP_PARALLEL_CLAUSES (t) = c;
+       }
+
+      save_local_var_chain = info->new_local_var_chain;
+      info->new_local_var_chain = NULL;
+
+      walk_body (convert_local_reference, info, &OMP_PARALLEL_BODY (t));
+
+      if (info->new_local_var_chain)
+       declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
+      info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case OMP_FOR:
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (&OMP_CLAUSES (t), wi);
+      walk_body (convert_local_reference, info, &OMP_BODY (t));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case OMP_SECTION:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+      walk_body (convert_local_reference, info, &OMP_BODY (t));
       break;
 
     default:
@@ -1060,6 +1364,70 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+static bool
+convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+  struct nesting_info *info = wi->info;
+  bool need_frame = false;
+  tree clause, decl;
+  int dummy;
+  bitmap new_suppress;
+
+  new_suppress = BITMAP_GGC_ALLOC ();
+  bitmap_copy (new_suppress, info->suppress_expansion);
+
+  for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+    {
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_PRIVATE:
+       case OMP_CLAUSE_FIRSTPRIVATE:
+       case OMP_CLAUSE_LASTPRIVATE:
+       case OMP_CLAUSE_REDUCTION:
+       case OMP_CLAUSE_COPYPRIVATE:
+       case OMP_CLAUSE_SHARED:
+         decl = OMP_CLAUSE_DECL (clause);
+         if (decl_function_context (decl) == info->context
+             && !use_pointer_in_frame (decl))
+           {
+             tree field = lookup_field_for_decl (info, decl, NO_INSERT);
+             if (field)
+               {
+                 bitmap_set_bit (new_suppress, DECL_UID (decl));
+                 OMP_CLAUSE_DECL (clause)
+                   = get_local_debug_decl (info, decl, field);
+                 need_frame = true;
+               }
+           }
+         break;
+
+       case OMP_CLAUSE_SCHEDULE:
+         if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
+           break;
+         /* FALLTHRU */
+       case OMP_CLAUSE_IF:
+       case OMP_CLAUSE_NUM_THREADS:
+         wi->val_only = true;
+         wi->is_lhs = false;
+         convert_local_reference (&OMP_CLAUSE_OPERAND (clause, 0), &dummy, wi);
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_COPYIN:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  info->suppress_expansion = new_suppress;
+
+  return need_frame;
+}
+
 /* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that 
    reference labels from outer functions.  The rewrite will be a 
    call to __builtin_nonlocal_goto.  */
@@ -1067,10 +1435,9 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
 static tree
 convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = data;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
   struct nesting_info *info = wi->info, *i;
-  tree t = *tp, label, new_label, target_context, x, arg, field;
-  struct var_map_elt *elt;
+  tree t = *tp, label, new_label, target_context, x, field;
   void **slot;
 
   *walk_subtrees = 0;
@@ -1091,28 +1458,25 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
      control transfer.  This new label will be marked LABEL_NONLOCAL; this
      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 ();
-  DECL_NONLOCAL (new_label) = 1;
-
-  /* Enter this association into var_map so that we can insert the new
-     label into the IL during a second pass.  */
-  elt = xmalloc (sizeof (*elt));
-  elt->old = label;
-  elt->new = new_label;
-  slot = htab_find_slot (i->var_map, elt, INSERT);
-  *slot = elt;
+     when we expand rtl.  Enter this association into var_map so that we
+     can insert the new label into the IL during a second pass.  */
+  slot = pointer_map_insert (i->var_map, label);
+  if (*slot == NULL)
+    {
+      new_label = create_artificial_label ();
+      DECL_NONLOCAL (new_label) = 1;
+      *slot = new_label;
+    }
+  else
+    new_label = *slot;
   
   /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field).  */
   field = get_nl_goto_field (i);
   x = get_frame_field (info, target_context, field, &wi->tsi);
   x = build_addr (x, target_context);
   x = tsi_gimplify_val (info, x, &wi->tsi);
-  arg = tree_cons (NULL, x, NULL);
-  x = build_addr (new_label, target_context);
-  arg = tree_cons (NULL, x, arg);
-  x = implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO];
-  x = build_function_call_expr (x, arg);
+  x = build_call_expr (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2,
+                      build_addr (new_label, target_context), x);
 
   SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
   *tsi_stmt_ptr (wi->tsi) = x;
@@ -1129,22 +1493,20 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
 static tree
 convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = data;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
   struct nesting_info *info = wi->info;
   tree t = *tp, label, new_label, x;
-  struct var_map_elt *elt, dummy;
   tree_stmt_iterator tmp_tsi;
+  void **slot;
 
   *walk_subtrees = 0;
   if (TREE_CODE (t) != LABEL_EXPR)
     return NULL_TREE;
   label = LABEL_EXPR_LABEL (t);
 
-  dummy.old = label;
-  elt = htab_find (info->var_map, &dummy);
-  if (!elt)
+  slot = pointer_map_contains (info->var_map, label);
+  if (!slot)
     return NULL_TREE;
-  new_label = elt->new;
 
   /* If there's any possibility that the previous statement falls through,
      then we must branch around the new non-local label.  */
@@ -1155,6 +1517,8 @@ convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
       x = build1 (GOTO_EXPR, void_type_node, label);
       tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
     }
+
+  new_label = (tree) *slot;
   x = build1 (LABEL_EXPR, void_type_node, new_label);
   tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
 
@@ -1168,9 +1532,9 @@ convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
 static tree
 convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = data;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
   struct nesting_info *info = wi->info, *i;
-  tree t = *tp, decl, target_context, x, arg;
+  tree t = *tp, decl, target_context, x;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -1206,12 +1570,11 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       x = get_frame_field (info, target_context, x, &wi->tsi);
       x = build_addr (x, target_context);
       x = tsi_gimplify_val (info, x, &wi->tsi);
-      arg = tree_cons (NULL, x, NULL);
 
       /* Do machine-specific ugliness.  Normally this will involve
         computing extra alignment, but it can really be anything.  */
-      x = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
-      x = build_function_call_expr (x, arg);
+      x = build_call_expr (implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE],
+                          1, x);
       x = init_tmp_var (info, x, &wi->tsi);
 
       /* Cast back to the proper function type.  */
@@ -1224,7 +1587,12 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
     case CALL_EXPR:
       /* Only walk call arguments, lest we generate trampolines for
         direct calls.  */
-      walk_tree (&TREE_OPERAND (t, 1), convert_tramp_reference, wi, NULL);
+      {
+       int nargs = call_expr_nargs (t);
+       int i;
+       for (i = 0; i < nargs; i++)
+         walk_tree (&CALL_EXPR_ARG (t, i), convert_tramp_reference, wi, NULL);
+      }
       break;
 
     default:
@@ -1243,9 +1611,11 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
 static tree
 convert_call_expr (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = data;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
   struct nesting_info *info = wi->info;
   tree t = *tp, decl, target_context;
+  char save_static_chain_added;
+  int i;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -1256,17 +1626,58 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
        break;
       target_context = decl_function_context (decl);
       if (target_context && !DECL_NO_STATIC_CHAIN (decl))
-       TREE_OPERAND (t, 2)
-         = get_static_chain (info, target_context, &wi->tsi);
+       {
+         CALL_EXPR_STATIC_CHAIN (t)
+           = get_static_chain (info, target_context, &wi->tsi);
+         info->static_chain_added
+           |= (1 << (info->context != target_context));
+       }
       break;
 
     case RETURN_EXPR:
-    case MODIFY_EXPR:
+    case GIMPLE_MODIFY_STMT:
     case WITH_SIZE_EXPR:
       /* Only return modify and with_size_expr may contain calls.  */
       *walk_subtrees = 1;
       break;
 
+    case OMP_PARALLEL:
+      save_static_chain_added = info->static_chain_added;
+      info->static_chain_added = 0;
+      walk_body (convert_call_expr, info, &OMP_PARALLEL_BODY (t));
+      for (i = 0; i < 2; i++)
+       {
+         tree c, decl;
+         if ((info->static_chain_added & (1 << i)) == 0)
+           continue;
+         decl = i ? get_chain_decl (info) : info->frame_decl;
+         /* Don't add CHAIN.* or FRAME.* twice.  */
+         for (c = OMP_PARALLEL_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
+           if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+                || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
+               && OMP_CLAUSE_DECL (c) == decl)
+             break;
+         if (c == NULL)
+           {
+             c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
+             OMP_CLAUSE_DECL (c) = decl;
+             OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
+             OMP_PARALLEL_CLAUSES (t) = c;
+           }
+       }
+      info->static_chain_added |= save_static_chain_added;
+      break;
+
+    case OMP_FOR:
+    case OMP_SECTIONS:
+    case OMP_SECTION:
+    case OMP_SINGLE:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+      walk_body (convert_call_expr, info, &OMP_BODY (t));
+      break;
+
     default:
       break;
     }
@@ -1311,13 +1722,17 @@ 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.  */
   if (root->frame_type)
     {
+      /* In some cases the frame type will trigger the -Wpadded warning.
+        This is not helpful; suppress it. */
+      int save_warn_padded = warn_padded;
+      warn_padded = 0;
       layout_type (root->frame_type);
+      warn_padded = save_warn_padded;
       layout_decl (root->frame_decl, 0);
     }
 
@@ -1340,9 +1755,9 @@ finalize_nesting_tree_1 (struct nesting_info *root)
          else
            x = p;
 
-         y = build (COMPONENT_REF, TREE_TYPE (field),
-                    root->frame_decl, field, NULL_TREE);
-         x = build (MODIFY_EXPR, TREE_TYPE (field), y, x);
+         y = build3 (COMPONENT_REF, TREE_TYPE (field),
+                     root->frame_decl, field, NULL_TREE);
+         x = build_gimple_modify_stmt (y, x);
          append_to_statement_list (x, &stmt_list);
        }
     }
@@ -1351,9 +1766,9 @@ finalize_nesting_tree_1 (struct nesting_info *root)
      from chain_decl.  */
   if (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));
+      tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field),
+                      root->frame_decl, root->chain_field, NULL_TREE);
+      x = build_gimple_modify_stmt (x, get_chain_decl (root));
       append_to_statement_list (x, &stmt_list);
     }
 
@@ -1363,29 +1778,25 @@ finalize_nesting_tree_1 (struct nesting_info *root)
       struct nesting_info *i;
       for (i = root->inner; i ; i = i->next)
        {
-         tree arg, x, field;
+         tree arg1, arg2, arg3, x, field;
 
          field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
          if (!field)
            continue;
 
          if (DECL_NO_STATIC_CHAIN (i->context))
-           x = null_pointer_node;
+           arg3 = null_pointer_node;
          else
-           x = build_addr (root->frame_decl, context);
-         arg = tree_cons (NULL, x, NULL);
+           arg3 = build_addr (root->frame_decl, context);
 
-         x = build_addr (i->context, context);
-         arg = tree_cons (NULL, x, arg);
+         arg2 = build_addr (i->context, context);
 
-         x = build (COMPONENT_REF, TREE_TYPE (field),
-                    root->frame_decl, field, NULL_TREE);
-         x = build_addr (x, context);
-         arg = tree_cons (NULL, x, arg);
+         x = build3 (COMPONENT_REF, TREE_TYPE (field),
+                     root->frame_decl, field, NULL_TREE);
+         arg1 = build_addr (x, context);
 
          x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
-         x = build_function_call_expr (x, arg);
-
+         x = build_call_expr (x, 3, arg1, arg2, arg3);
          append_to_statement_list (x, &stmt_list);
        }
     }
@@ -1417,12 +1828,35 @@ finalize_nesting_tree_1 (struct nesting_info *root)
   /* 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,
-                     DECL_SAVED_TREE (root->context));
+    declare_vars (root->new_local_var_chain, DECL_SAVED_TREE (root->context),
+                 false);
+  if (root->debug_var_chain)
+    declare_vars (root->debug_var_chain, DECL_SAVED_TREE (root->context),
+                 true);
 
   /* Dump the translated tree function.  */
   dump_function (TDI_nested, root->context);
-  node = cgraph_node (root->context);
+}
+
+static void
+finalize_nesting_tree (struct nesting_info *root)
+{
+  do
+    {
+      if (root->inner)
+       finalize_nesting_tree (root->inner);
+      finalize_nesting_tree_1 (root);
+      root = root->next;
+    }
+  while (root);
+}
+
+/* Unnest the nodes and pass them to cgraph.  */
+
+static void
+unnest_nesting_tree_1 (struct nesting_info *root)
+{
+  struct cgraph_node *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.  */
@@ -1434,13 +1868,13 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 }
 
 static void
-finalize_nesting_tree (struct nesting_info *root)
+unnest_nesting_tree (struct nesting_info *root)
 {
   do
     {
       if (root->inner)
-       finalize_nesting_tree (root->inner);
-      finalize_nesting_tree_1 (root);
+       unnest_nesting_tree (root->inner);
+      unnest_nesting_tree_1 (root);
       root = root->next;
     }
   while (root);
@@ -1456,7 +1890,8 @@ free_nesting_tree (struct nesting_info *root)
     {
       if (root->inner)
        free_nesting_tree (root->inner);
-      htab_delete (root->var_map);
+      pointer_map_destroy (root->var_map);
+      pointer_map_destroy (root->field_map);
       next = root->next;
       free (root);
       root = next;
@@ -1470,14 +1905,15 @@ free_nesting_tree (struct nesting_info *root)
 void
 lower_nested_functions (tree fndecl)
 {
-  struct nesting_info *root;
   struct cgraph_node *cgn;
+  struct nesting_info *root;
 
   /* If there are no nested functions, there's nothing to do.  */
   cgn = cgraph_node (fndecl);
   if (!cgn->nested)
     return;
 
+  bitmap_obstack_initialize (&nesting_info_bitmap_obstack);
   root = create_nesting_tree (cgn);
   walk_all_functions (convert_nonlocal_reference, root);
   walk_all_functions (convert_local_reference, root);
@@ -1485,7 +1921,9 @@ lower_nested_functions (tree fndecl)
   walk_all_functions (convert_nl_goto_receiver, root);
   convert_all_function_calls (root);
   finalize_nesting_tree (root);
+  unnest_nesting_tree (root);
   free_nesting_tree (root);
+  bitmap_obstack_release (&nesting_info_bitmap_obstack);
 }
 
 #include "gt-tree-nested.h"