OSDN Git Service

2009-04-10 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-nested.c
index d5309ec..8f9fec5 100644 (file)
@@ -1,11 +1,11 @@
-/* Nested function decomposition for trees.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+/* Nested function decomposition for GIMPLE.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    GCC is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful,
@@ -14,9 +14,8 @@
    GNU General Public License for more details.
 
    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, 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "function.h"
 #include "tree-dump.h"
 #include "tree-inline.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "tree-iterator.h"
 #include "tree-flow.h"
 #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 GTY(())
-{
-  tree old;
-  tree new;
-};
-
-struct nesting_info GTY ((chain_next ("%h.next")))
+struct nesting_info
 {
   struct nesting_info *outer;
   struct nesting_info *inner;
   struct nesting_info *next;
   
-  htab_t GTY ((param_is (struct var_map_elt))) 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 +98,13 @@ struct nesting_info GTY ((chain_next ("%h.next")))
 
   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 = (const struct var_map_elt *) 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 = (const struct var_map_elt *) x;
-  const struct var_map_elt *b = (const struct var_map_elt *) 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 +129,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;
@@ -166,7 +156,7 @@ build_addr (tree exp, tree context)
 
   /* Building the ADDR_EXPR will compute a set of properties for
      that ADDR_EXPR.  Those properties are unfortunately context
-     specific.  ie, they are dependent on CURRENT_FUNCTION_DECL.
+     specific, i.e., they are dependent on CURRENT_FUNCTION_DECL.
 
      Temporarily set CURRENT_FUNCTION_DECL to the desired context,
      build the ADDR_EXPR, then restore CURRENT_FUNCTION_DECL.  That
@@ -174,13 +164,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;
@@ -193,6 +183,10 @@ insert_field_into_struct (tree type, tree field)
 
   TREE_CHAIN (field) = *p;
   *p = field;
+
+  /* Set correct alignment for frame struct type.  */
+  if (TYPE_ALIGN (type) < DECL_ALIGN (field))
+    TYPE_ALIGN (type) = DECL_ALIGN (field);
 }
 
 /* Build or return the RECORD_TYPE that describes the frame state that is
@@ -259,22 +253,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 ? (tree) *slot : NULL_TREE;
     }
-  elt = (struct var_map_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))
@@ -295,19 +285,13 @@ lookup_field_for_decl (struct nesting_info *info, tree decl,
        }
 
       insert_field_into_struct (get_frame_type (info), field);
-  
-      elt = GGC_NEW (struct var_map_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 (tree) *slot;
 }
 
 /* Build or return the variable that holds the static chain within
@@ -371,46 +355,69 @@ get_chain_field (struct nesting_info *info)
   return field;
 }
 
+/* Initialize a new temporary with the GIMPLE_CALL STMT.  */
+
+static tree
+init_tmp_var_with_call (struct nesting_info *info, gimple_stmt_iterator *gsi,
+                       gimple call)
+{
+  tree t;
+
+  t = create_tmp_var_for (info, gimple_call_return_type (call), NULL);
+  gimple_call_set_lhs (call, t);
+  if (! gsi_end_p (*gsi))
+    gimple_set_location (call, gimple_location (gsi_stmt (*gsi)));
+  gsi_insert_before (gsi, call, GSI_SAME_STMT);
+
+  return t;
+}
+
+  
 /* Copy EXP into a temporary.  Allocate the temporary in the context of
-   INFO and insert the initialization statement before TSI.  */
+   INFO and insert the initialization statement before GSI.  */
 
 static tree
-init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+init_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi)
 {
-  tree t, stmt;
+  tree t;
+  gimple stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), t, exp);
-  SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
-  tsi_link_before (tsi, stmt, TSI_SAME_STMT);
+  stmt = gimple_build_assign (t, exp);
+  if (! gsi_end_p (*gsi))
+    gimple_set_location (stmt, gimple_location (gsi_stmt (*gsi)));
+  gsi_insert_before_without_update (gsi, stmt, GSI_SAME_STMT);
 
   return t;
 }
 
+
 /* Similarly, but only do so to force EXP to satisfy is_gimple_val.  */
 
 static tree
-tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+gsi_gimplify_val (struct nesting_info *info, tree exp,
+                 gimple_stmt_iterator *gsi)
 {
   if (is_gimple_val (exp))
     return exp;
   else
-    return init_tmp_var (info, exp, tsi);
+    return init_tmp_var (info, exp, gsi);
 }
 
 /* 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)
+save_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi)
 {
-  tree t, stmt;
+  tree t;
+  gimple stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), exp, t);
-  SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
-  tsi_link_after (tsi, stmt, TSI_SAME_STMT);
+  stmt = gimple_build_assign (exp, t);
+  if (! gsi_end_p (*gsi))
+    gimple_set_location (stmt, gimple_location (gsi_stmt (*gsi)));
+  gsi_insert_after_without_update (gsi, stmt, GSI_SAME_STMT);
 
   return t;
 }
@@ -422,8 +429,8 @@ static GTY(()) tree trampoline_type;
 static tree
 get_trampoline_type (void)
 {
-  tree record, t;
   unsigned align, size;
+  tree t;
 
   if (trampoline_type)
     return trampoline_type;
@@ -445,12 +452,13 @@ get_trampoline_type (void)
   DECL_ALIGN (t) = align;
   DECL_USER_ALIGN (t) = 1;
 
-  record = make_node (RECORD_TYPE);
-  TYPE_NAME (record) = get_identifier ("__builtin_trampoline");
-  TYPE_FIELDS (record) = t;
-  layout_type (record);
+  trampoline_type = make_node (RECORD_TYPE);
+  TYPE_NAME (trampoline_type) = get_identifier ("__builtin_trampoline");
+  TYPE_FIELDS (trampoline_type) = t;
+  layout_type (trampoline_type);
+  DECL_CONTEXT (t) = trampoline_type;
 
-  return record;
+  return trampoline_type;
 }
 
 /* Given DECL, a nested function, find or create a field in the non-local
@@ -460,39 +468,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 ? (tree) *slot : NULL_TREE;
     }
-  elt = (struct var_map_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 = GGC_NEW (struct var_map_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 (tree) *slot;
 } 
 
 /* Build or return the field within the non-local frame state that holds
@@ -537,127 +535,102 @@ 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
-{
-  walk_tree_fn callback;
-  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.  */
+/* Invoke CALLBACK on all statements of GIMPLE sequence SEQ.  */
 
 static void
-walk_stmts (struct walk_stmt_info *wi, tree *tp)
+walk_body (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+          struct nesting_info *info, gimple_seq seq)
 {
-  tree t = *tp;
-  if (!t)
-    return;
-
-  switch (TREE_CODE (t))
-    {
-    case STATEMENT_LIST:
-      {
-       tree_stmt_iterator i;
-       for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
-         {
-           wi->tsi = i;
-           walk_stmts (wi, tsi_stmt_ptr (i));
-         }
-      }
-      break;
-
-    case COND_EXPR:
-      walk_tree (&COND_EXPR_COND (t), wi->callback, wi, NULL);
-      walk_stmts (wi, &COND_EXPR_THEN (t));
-      walk_stmts (wi, &COND_EXPR_ELSE (t));
-      break;
-    case CATCH_EXPR:
-      walk_stmts (wi, &CATCH_BODY (t));
-      break;
-    case EH_FILTER_EXPR:
-      walk_stmts (wi, &EH_FILTER_FAILURE (t));
-      break;
-    case TRY_CATCH_EXPR:
-    case TRY_FINALLY_EXPR:
-      walk_stmts (wi, &TREE_OPERAND (t, 0));
-      walk_stmts (wi, &TREE_OPERAND (t, 1));
-      break;
-    case BIND_EXPR:
-      walk_stmts (wi, &BIND_EXPR_BODY (t));
-      break;
-
-    case RETURN_EXPR:
-      walk_stmts (wi, &TREE_OPERAND (t, 0));
-      break;
+  struct walk_stmt_info wi;
 
-    case MODIFY_EXPR:
-      /* 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);
+  memset (&wi, 0, sizeof (wi));
+  wi.info = info;
+  wi.val_only = true;
+  walk_gimple_seq (seq, callback_stmt, callback_op, &wi);
+}
 
-      /* 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;
+/* Invoke CALLBACK_STMT/CALLBACK_OP on all statements of INFO->CONTEXT.  */
 
-    default:
-      wi->val_only = true;
-      walk_tree (tp, wi->callback, wi, NULL);
-      break;
-    }
+static inline void
+walk_function (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+              struct nesting_info *info)
+{
+  walk_body (callback_stmt, callback_op, info, gimple_body (info->context));
 }
 
-/* Invoke CALLBACK on all statements of INFO->CONTEXT.  */
+/* Invoke CALLBACK on a GIMPLE_OMP_FOR's init, cond, incr and pre-body.  */
 
 static void
-walk_function (walk_tree_fn callback, struct nesting_info *info)
+walk_gimple_omp_for (gimple for_stmt,
+                    walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+                    struct nesting_info *info)
 {
   struct walk_stmt_info wi;
+  gimple_seq seq;
+  tree t;
+  size_t i;
+
+  walk_body (callback_stmt, callback_op, info, gimple_omp_for_pre_body (for_stmt));
 
+  seq = gimple_seq_alloc ();
   memset (&wi, 0, sizeof (wi));
-  wi.callback = callback;
   wi.info = info;
-  wi.val_only = true;
+  wi.gsi = gsi_last (seq);
+
+  for (i = 0; i < gimple_omp_for_collapse (for_stmt); i++)
+    {
+      wi.val_only = false;
+      walk_tree (gimple_omp_for_index_ptr (for_stmt, i), callback_op,
+                &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (gimple_omp_for_initial_ptr (for_stmt, i), callback_op,
+                &wi, NULL);
+
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (gimple_omp_for_final_ptr (for_stmt, i), callback_op,
+                &wi, NULL);
+
+      t = gimple_omp_for_incr (for_stmt, i);
+      gcc_assert (BINARY_CLASS_P (t));
+      wi.val_only = false;
+      walk_tree (&TREE_OPERAND (t, 0), callback_op, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&TREE_OPERAND (t, 1), callback_op, &wi, NULL);
+    }
 
-  walk_stmts (&wi, &DECL_SAVED_TREE (info->context));
+  if (gimple_seq_empty_p (seq))
+    gimple_seq_free (seq);
+  else
+    {
+      gimple_seq pre_body = gimple_omp_for_pre_body (for_stmt);
+      annotate_all_with_location (seq, gimple_location (for_stmt));
+      gimple_seq_add_seq (&pre_body, seq);
+      gimple_omp_for_set_pre_body (for_stmt, pre_body);
+    }
 }
 
 /* Similarly for ROOT and all functions nested underneath, depth first.  */
     
 static void
-walk_all_functions (walk_tree_fn callback, struct nesting_info *root)
+walk_all_functions (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+                   struct nesting_info *root)
 {
   do
     {
       if (root->inner)
-       walk_all_functions (callback, root->inner);
-      walk_function (callback, root);
+       walk_all_functions (callback_stmt, callback_op, root->inner);
+      walk_function (callback_stmt, callback_op, root);
       root = root->next;
     }
   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
@@ -690,7 +663,7 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
   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)
+       if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
          return true;
 
       if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl))
@@ -706,8 +679,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 = GGC_CNEW (struct nesting_info);
-  info->var_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_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)
@@ -731,7 +706,7 @@ create_nesting_tree (struct cgraph_node *cgn)
 
 static tree
 get_static_chain (struct nesting_info *info, tree target_context,
-                 tree_stmt_iterator *tsi)
+                 gimple_stmt_iterator *gsi)
 {
   struct nesting_info *i;
   tree x;
@@ -750,20 +725,21 @@ get_static_chain (struct nesting_info *info, tree target_context,
 
          x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
          x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
-         x = init_tmp_var (info, x, tsi);
+         x = init_tmp_var (info, x, gsi);
        }
     }
 
   return x;
 }
 
+
 /* Return an expression referencing FIELD from TARGET_CONTEXT's non-local
    frame as seen from INFO->CONTEXT.  Insert any necessary computations
-   before TSI.  */
+   before GSI.  */
 
 static tree
 get_frame_field (struct nesting_info *info, tree target_context,
-                tree field, tree_stmt_iterator *tsi)
+                tree field, gimple_stmt_iterator *gsi)
 {
   struct nesting_info *i;
   tree x;
@@ -784,7 +760,7 @@ get_frame_field (struct nesting_info *info, tree target_context,
 
          x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
          x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
-         x = init_tmp_var (info, x, tsi);
+         x = init_tmp_var (info, x, gsi);
        }
 
       x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
@@ -794,7 +770,76 @@ get_frame_field (struct nesting_info *info, tree target_context,
   return x;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to VAR
+
+/* A subroutine of convert_nonlocal_reference_op.  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 (tree) *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;
+}
+
+
+/* Callback for walk_gimple_stmt, rewrite all references to VAR
    and PARM_DECLs that belong to outer functions.
 
    The rewrite will involve some number of structure accesses back up
@@ -803,10 +848,10 @@ get_frame_field (struct nesting_info *info, tree target_context,
    indirections apply to decls for which use_pointer_in_frame is true.  */
 
 static tree
-convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
+convert_nonlocal_reference_op (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp;
 
   *walk_subtrees = 0;
@@ -821,43 +866,37 @@ 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->gsi);
+             if (use_pointer_in_frame (t))
+               {
+                 x = init_tmp_var (info, x, &wi->gsi);
+                 x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+               }
            }
 
          if (wi->val_only)
            {
              if (wi->is_lhs)
-               x = save_tmp_var (info, x, &wi->tsi);
+               x = save_tmp_var (info, x, &wi->gsi);
              else
-               x = init_tmp_var (info, x, &wi->tsi);
+               x = init_tmp_var (info, x, &wi->gsi);
            }
 
          *tp = x;
        }
       break;
 
-    case GOTO_EXPR:
-      /* Don't walk non-local gotos for now.  */
-      if (TREE_CODE (GOTO_DESTINATION (t)) != LABEL_DECL)
-       {
-         *walk_subtrees = 1;
-         wi->val_only = true;
-         wi->is_lhs = false;
-       }
-      break;
-
     case LABEL_DECL:
       /* We're taking the address of a label from a parent function, but
         this is not itself a non-local goto.  Mark the label such that it
@@ -874,15 +913,15 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
        wi->val_only = false;
        wi->is_lhs = false;
        wi->changed = false;
-       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
+       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference_op, wi, 0);
        wi->val_only = true;
 
        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.  */
+           /* If we changed anything, we might no longer be directly
+              referencing a decl.  */
            save_context = current_function_decl;
            current_function_decl = info->context;
            recompute_tree_invariant_for_addr_expr (t);
@@ -892,7 +931,8 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
               where we only accept variables (and min_invariant, presumably),
               then compute the address into a temporary.  */
            if (save_val_only)
-             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+             *tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
+                                     t, &wi->gsi);
          }
       }
       break;
@@ -911,28 +951,35 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       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,
+           walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op, 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);
+             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference_op,
+                        wi, NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op,
+                        wi, NULL);
+             walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference_op,
+                        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);
+             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference_op,
+                        wi, NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op,
+                        wi, NULL);
            }
        }
       wi->val_only = false;
-      walk_tree (tp, convert_nonlocal_reference, wi, NULL);
+      walk_tree (tp, convert_nonlocal_reference_op, wi, NULL);
+      break;
+
+    case VIEW_CONVERT_EXPR:
+      /* Just request to look at the subtrees, leaving val_only and lhs
+        untouched.  This might actually be for !val_only + lhs, in which
+        case we don't want to force a replacement by a temporary.  */
+      *walk_subtrees = 1;
       break;
 
     default:
@@ -948,15 +995,277 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to VAR
+static tree convert_nonlocal_reference_stmt (gimple_stmt_iterator *, bool *,
+                                            struct walk_stmt_info *);
+
+/* Helper for convert_nonlocal_references, rewrite all references to VAR
+   and PARM_DECLs that belong to outer functions.  */
+
+static bool
+convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  bool need_chain = false, need_stmts = 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_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_PRIVATE:
+       case OMP_CLAUSE_FIRSTPRIVATE:
+       case OMP_CLAUSE_COPYPRIVATE:
+       case OMP_CLAUSE_SHARED:
+       do_decl_clause:
+         decl = OMP_CLAUSE_DECL (clause);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+           break;
+         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_op (&OMP_CLAUSE_OPERAND (clause, 0),
+                                        &dummy, wi);
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  info->suppress_expansion = new_suppress;
+
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           {
+             tree old_context
+               = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = info->context;
+             walk_body (convert_nonlocal_reference_stmt,
+                        convert_nonlocal_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+             walk_body (convert_nonlocal_reference_stmt,
+                        convert_nonlocal_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_nonlocal_reference_stmt,
+                    convert_nonlocal_reference_op, info,
+                    OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+         break;
+
+       default:
+         break;
+       }
+
+  return need_chain;
+}
+
+
+/* Callback for walk_gimple_stmt.  Rewrite all references to VAR and
+   PARM_DECLs that belong to outer functions.  This handles statements
+   that are not handled via the standard recursion done in
+   walk_gimple_stmt.  STMT is the statement to examine, DATA is as in
+   convert_nonlocal_reference_op.  Set *HANDLED_OPS_P to true if all the
+   operands of STMT have been handled by this function.  */
+
+static tree
+convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                                struct walk_stmt_info *wi)
+{
+  struct nesting_info *info = (struct nesting_info *) wi->info;
+  tree save_local_var_chain;
+  bitmap save_suppress;
+  gimple stmt = gsi_stmt (*gsi);
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_GOTO:
+      /* Don't walk non-local gotos for now.  */
+      if (TREE_CODE (gimple_goto_dest (stmt)) != LABEL_DECL)
+       {
+         wi->val_only = true;
+         wi->is_lhs = false;
+         *handled_ops_p = true;
+         return NULL_TREE;
+       }
+      break;
+
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      save_suppress = info->suppress_expansion;
+      if (convert_nonlocal_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+                                       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) = gimple_omp_taskreg_clauses (stmt);
+         gimple_omp_taskreg_set_clauses (stmt, c);
+       }
+
+      save_local_var_chain = info->new_local_var_chain;
+      info->new_local_var_chain = NULL;
+
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+
+      if (info->new_local_var_chain)
+       declare_vars (info->new_local_var_chain,
+                     gimple_seq_first_stmt (gimple_omp_body (stmt)),
+                     false);
+      info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_FOR:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+      walk_gimple_omp_for (stmt, convert_nonlocal_reference_stmt,
+                          convert_nonlocal_reference_op, info);
+      walk_body (convert_nonlocal_reference_stmt,
+                convert_nonlocal_reference_op, info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTIONS:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+      break;
+
+    default:
+      /* For every other statement that we are not interested in
+        handling here, let the walker traverse the operands.  */
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
+  /* We have handled all of STMT operands, no need to traverse the operands.  */
+  *handled_ops_p = true;
+  return NULL_TREE;
+}
+
+
+/* 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 (tree) *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_gimple_stmt, 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)
+convert_local_reference_op (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp, field, x;
   bool save_val_only;
 
@@ -984,14 +1293,16 @@ 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->gsi);
 
          if (wi->val_only)
            {
              if (wi->is_lhs)
-               x = save_tmp_var (info, x, &wi->tsi);
+               x = save_tmp_var (info, x, &wi->gsi);
              else
-               x = init_tmp_var (info, x, &wi->tsi);
+               x = init_tmp_var (info, x, &wi->gsi);
            }
 
          *tp = x;
@@ -1003,7 +1314,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       wi->val_only = false;
       wi->is_lhs = false;
       wi->changed = false;
-      walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
+      walk_tree (&TREE_OPERAND (t, 0), convert_local_reference_op, wi, NULL);
       wi->val_only = save_val_only;
 
       /* If we converted anything ... */
@@ -1022,7 +1333,8 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
          /* 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);
+           *tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
+                                   t, &wi->gsi);
        }
       break;
 
@@ -1041,31 +1353,38 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       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,
+           walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, 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,
+             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi,
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 3), convert_local_reference_op, wi,
                         NULL);
            }
          else if (TREE_CODE (t) == BIT_FIELD_REF)
            {
-             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi,
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
                         NULL);
            }
        }
       wi->val_only = false;
-      walk_tree (tp, convert_local_reference, wi, NULL);
+      walk_tree (tp, convert_local_reference_op, wi, NULL);
       wi->val_only = save_val_only;
       break;
 
+    case VIEW_CONVERT_EXPR:
+      /* Just request to look at the subtrees, leaving val_only and lhs
+        untouched.  This might actually be for !val_only + lhs, in which
+        case we don't want to force a replacement by a temporary.  */
+      *walk_subtrees = 1;
+      break;
+
     default:
       if (!IS_TYPE_OR_DECL_P (t))
        {
@@ -1079,28 +1398,245 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that 
-   reference labels from outer functions.  The rewrite will be a 
+static tree convert_local_reference_stmt (gimple_stmt_iterator *, bool *,
+                                         struct walk_stmt_info *);
+
+/* Helper for convert_local_reference.  Convert all the references in
+   the chain of clauses at *PCLAUSES.  WI is as in convert_local_reference.  */
+
+static bool
+convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  bool need_frame = false, need_stmts = 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_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_PRIVATE:
+       case OMP_CLAUSE_FIRSTPRIVATE:
+       case OMP_CLAUSE_COPYPRIVATE:
+       case OMP_CLAUSE_SHARED:
+       do_decl_clause:
+         decl = OMP_CLAUSE_DECL (clause);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+           break;
+         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_op (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
+                                     wi);
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  info->suppress_expansion = new_suppress;
+
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           {
+             tree old_context
+               = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = info->context;
+             walk_body (convert_local_reference_stmt,
+                        convert_local_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+             walk_body (convert_local_reference_stmt,
+                        convert_local_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_local_reference_stmt,
+                    convert_local_reference_op, info,
+                    OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+         break;
+
+       default:
+         break;
+       }
+
+  return need_frame;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, 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 tree
+convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                             struct walk_stmt_info *wi)
+{
+  struct nesting_info *info = (struct nesting_info *) wi->info;
+  tree save_local_var_chain;
+  bitmap save_suppress;
+  gimple stmt = gsi_stmt (*gsi);
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      save_suppress = info->suppress_expansion;
+      if (convert_local_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+                                    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) = gimple_omp_taskreg_clauses (stmt);
+         gimple_omp_taskreg_set_clauses (stmt, c);
+       }
+
+      save_local_var_chain = info->new_local_var_chain;
+      info->new_local_var_chain = NULL;
+
+      walk_body (convert_local_reference_stmt, convert_local_reference_op, info,
+                gimple_omp_body (stmt));
+
+      if (info->new_local_var_chain)
+       declare_vars (info->new_local_var_chain,
+                     gimple_seq_first_stmt (gimple_omp_body (stmt)), false);
+      info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_FOR:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+      walk_gimple_omp_for (stmt, convert_local_reference_stmt,
+                          convert_local_reference_op, info);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTIONS:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      break;
+
+    default:
+      /* For every other statement that we are not interested in
+        handling here, let the walker traverse the operands.  */
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
+  /* Indicate that we have handled all the operands ourselves.  */
+  *handled_ops_p = true;
+  return NULL_TREE;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all GIMPLE_GOTOs
+   that reference labels from outer functions.  The rewrite will be a
    call to __builtin_nonlocal_goto.  */
 
 static tree
-convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
+convert_nl_goto_reference (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                          struct walk_stmt_info *wi)
 {
-  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, dummy;
+  struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
+  tree label, new_label, target_context, x, field;
   void **slot;
+  gimple call;
+  gimple stmt = gsi_stmt (*gsi);
 
-  *walk_subtrees = 0;
-  if (TREE_CODE (t) != GOTO_EXPR)
-    return NULL_TREE;
-  label = GOTO_DESTINATION (t);
+  if (gimple_code (stmt) != GIMPLE_GOTO)
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
+  label = gimple_goto_dest (stmt);
   if (TREE_CODE (label) != LABEL_DECL)
-    return NULL_TREE;
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
   target_context = decl_function_context (label);
   if (target_context == info->context)
-    return NULL_TREE;
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
 
   for (i = info->outer; target_context != i->context; i = i->outer)
     continue;
@@ -1112,90 +1648,92 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
      (hairy target-specific) non-local goto receiver code to be generated
      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.  */
-  dummy.old = label;
-  slot = htab_find_slot (i->var_map, &dummy, INSERT);
-  elt = (struct var_map_elt *) *slot;
-  if (elt == NULL)
+  slot = pointer_map_insert (i->var_map, label);
+  if (*slot == NULL)
     {
       new_label = create_artificial_label ();
       DECL_NONLOCAL (new_label) = 1;
-
-      elt = GGC_NEW (struct var_map_elt); 
-      elt->old = label;
-      elt->new = new_label;
-      *slot = elt;
+      *slot = new_label;
     }
   else
-    new_label = elt->new;
+    new_label = (tree) *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 = get_frame_field (info, target_context, field, &wi->gsi);
   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);
-
-  SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
-  *tsi_stmt_ptr (wi->tsi) = x;
+  x = gsi_gimplify_val (info, x, &wi->gsi);
+  call = gimple_build_call (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2,
+                           build_addr (new_label, target_context), x);
+  gsi_replace (&wi->gsi, call, false);
 
+  /* We have handled all of STMT's operands, no need to keep going.  */
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all LABEL_EXPRs that 
+
+/* Called via walk_function+walk_tree, rewrite all GIMPLE_LABELs whose labels
    are referenced via nonlocal goto from a nested function.  The rewrite
    will involve installing a newly generated DECL_NONLOCAL label, and
-   (potentially) a branch around the rtl gunk that is assumed to be 
+   (potentially) a branch around the rtl gunk that is assumed to be
    attached to such a label.  */
 
 static tree
-convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
+convert_nl_goto_receiver (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                         struct walk_stmt_info *wi)
 {
-  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;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  tree label, new_label;
+  gimple_stmt_iterator tmp_gsi;
+  void **slot;
+  gimple stmt = gsi_stmt (*gsi);
 
-  *walk_subtrees = 0;
-  if (TREE_CODE (t) != LABEL_EXPR)
-    return NULL_TREE;
-  label = LABEL_EXPR_LABEL (t);
+  if (gimple_code (stmt) != GIMPLE_LABEL)
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
+  label = gimple_label_label (stmt);
 
-  dummy.old = label;
-  elt = (struct var_map_elt *) htab_find (info->var_map, &dummy);
-  if (!elt)
-    return NULL_TREE;
-  new_label = elt->new;
+  slot = pointer_map_contains (info->var_map, label);
+  if (!slot)
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
 
   /* If there's any possibility that the previous statement falls through,
      then we must branch around the new non-local label.  */
-  tmp_tsi = wi->tsi;
-  tsi_prev (&tmp_tsi);
-  if (tsi_end_p (tmp_tsi) || block_may_fallthru (tsi_stmt (tmp_tsi)))
+  tmp_gsi = wi->gsi;
+  gsi_prev (&tmp_gsi);
+  if (gsi_end_p (tmp_gsi) || gimple_stmt_may_fallthru (gsi_stmt (tmp_gsi)))
     {
-      x = build1 (GOTO_EXPR, void_type_node, label);
-      tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
+      gimple stmt = gimple_build_goto (label);
+      gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
     }
-  x = build1 (LABEL_EXPR, void_type_node, new_label);
-  tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
 
+  new_label = (tree) *slot;
+  stmt = gimple_build_label (new_label);
+  gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to addresses
+
+/* Called via walk_function+walk_stmt, rewrite all references to addresses
    of nested functions that require the use of trampolines.  The rewrite
    will involve a reference a trampoline generated for the occasion.  */
 
 static tree
-convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
+convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *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;
+  struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
+  tree t = *tp, decl, target_context, x, builtin;
+  gimple call;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -1221,6 +1759,10 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       if (DECL_NO_STATIC_CHAIN (decl))
        break;
 
+      /* If we don't want a trampoline, then don't build one.  */
+      if (TREE_NO_TRAMPOLINE (t))
+       break;
+
       /* Lookup the immediate parent of the callee, as that's where
         we need to insert the trampoline.  */
       for (i = info; i->context != target_context; i = i->outer)
@@ -1228,30 +1770,23 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       x = lookup_tramp_for_decl (i, decl, INSERT);
 
       /* Compute the address of the field holding the trampoline.  */
-      x = get_frame_field (info, target_context, x, &wi->tsi);
+      x = get_frame_field (info, target_context, x, &wi->gsi);
       x = build_addr (x, target_context);
-      x = tsi_gimplify_val (info, x, &wi->tsi);
-      arg = tree_cons (NULL, x, NULL);
+      x = gsi_gimplify_val (info, x, &wi->gsi);
 
       /* 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 = init_tmp_var (info, x, &wi->tsi);
+      builtin = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
+      call = gimple_build_call (builtin, 1, x);
+      x = init_tmp_var_with_call (info, &wi->gsi, call);
 
       /* Cast back to the proper function type.  */
       x = build1 (NOP_EXPR, TREE_TYPE (t), x);
-      x = init_tmp_var (info, x, &wi->tsi);
+      x = init_tmp_var (info, x, &wi->gsi);
 
       *tp = x;
       break;
 
-    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);
-      break;
-
     default:
       if (!IS_TYPE_OR_DECL_P (t))
        *walk_subtrees = 1;
@@ -1261,44 +1796,127 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all CALL_EXPRs that 
-   reference nested functions to make sure that the static chain is
-   set up properly for the call.  */
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all references
+   to addresses of nested functions that require the use of
+   trampolines.  The rewrite will involve a reference a trampoline
+   generated for the occasion.  */
 
 static tree
-convert_call_expr (tree *tp, int *walk_subtrees, void *data)
+convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                             struct walk_stmt_info *wi)
 {
-  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
-  tree t = *tp, decl, target_context;
+  gimple stmt = gsi_stmt (*gsi);
 
-  *walk_subtrees = 0;
-  switch (TREE_CODE (t))
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_CALL:
+      {
+       /* Only walk call arguments, lest we generate trampolines for
+          direct calls.  */
+       unsigned long i, nargs = gimple_call_num_args (stmt);
+       for (i = 0; i < nargs; i++)
+         walk_tree (gimple_call_arg_ptr (stmt, i), convert_tramp_reference_op,
+                    wi, NULL);
+
+       *handled_ops_p = true;
+       return NULL_TREE;
+      }
+
+    default:
+      break;
+    }
+
+  *handled_ops_p = false;
+  return NULL_TREE;
+}
+
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all GIMPLE_CALLs
+   that reference nested functions to make sure that the static chain
+   is set up properly for the call.  */
+
+static tree
+convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                     struct walk_stmt_info *wi)
+{
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  tree decl, target_context;
+  char save_static_chain_added;
+  int i;
+  gimple stmt = gsi_stmt (*gsi);
+
+  switch (gimple_code (stmt))
     {
-    case CALL_EXPR:
-      decl = get_callee_fndecl (t);
+    case GIMPLE_CALL:
+      decl = gimple_call_fndecl (stmt);
       if (!decl)
        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);
+       {
+         gimple_call_set_chain (stmt, get_static_chain (info, target_context,
+                                                        &wi->gsi));
+         info->static_chain_added |= (1 << (info->context != target_context));
+       }
       break;
 
-    case RETURN_EXPR:
-    case MODIFY_EXPR:
-    case WITH_SIZE_EXPR:
-      /* Only return modify and with_size_expr may contain calls.  */
-      *walk_subtrees = 1;
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      save_static_chain_added = info->static_chain_added;
+      info->static_chain_added = 0;
+      walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt));
+      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 = gimple_omp_taskreg_clauses (stmt);
+              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 (i ? OMP_CLAUSE_FIRSTPRIVATE
+                                     : OMP_CLAUSE_SHARED);
+             OMP_CLAUSE_DECL (c) = decl;
+             OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+             gimple_omp_taskreg_set_clauses (stmt, c);
+           }
+       }
+      info->static_chain_added |= save_static_chain_added;
       break;
 
-    default:
+    case GIMPLE_OMP_FOR:
+      walk_body (convert_gimple_call, NULL, info,
+                gimple_omp_for_pre_body (stmt));
+      /* FALLTHRU */
+    case GIMPLE_OMP_SECTIONS:
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+    case GIMPLE_OMP_CRITICAL:
+      walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt));
       break;
+
+    default:
+      /* Keep looking for other operands.  */
+      *handled_ops_p = false;
+      return NULL_TREE;
     }
 
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
+
 /* Walk the nesting tree starting with ROOT, depth first.  Convert all
    trampolines and call expressions.  On the way back up, determine if
    a nested function actually uses its static chain; if not, remember that.  */
@@ -1311,8 +1929,9 @@ convert_all_function_calls (struct nesting_info *root)
       if (root->inner)
        convert_all_function_calls (root->inner);
 
-      walk_function (convert_tramp_reference, root);
-      walk_function (convert_call_expr, root);
+      walk_function (convert_tramp_reference_stmt, convert_tramp_reference_op,
+                    root);
+      walk_function (convert_gimple_call, NULL, root);
 
       /* If the function does not use a static chain, then remember that.  */
       if (root->outer && !root->chain_decl && !root->chain_field)
@@ -1333,10 +1952,12 @@ convert_all_function_calls (struct nesting_info *root)
 static void
 finalize_nesting_tree_1 (struct nesting_info *root)
 {
-  tree stmt_list = NULL;
+  gimple_seq stmt_list;
+  gimple stmt;
   tree context = root->context;
   struct function *sf;
-  struct cgraph_node *node;
+
+  stmt_list = NULL;
 
   /* If we created a non-local frame type or decl, we need to lay them
      out at this time.  */
@@ -1372,8 +1993,17 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 
          y = build3 (COMPONENT_REF, TREE_TYPE (field),
                      root->frame_decl, field, NULL_TREE);
-         x = build2 (MODIFY_EXPR, TREE_TYPE (field), y, x);
-         append_to_statement_list (x, &stmt_list);
+         stmt = gimple_build_assign (y, x);
+         gimple_seq_add_stmt (&stmt_list, stmt);
+         /* If the assignment is from a non-register the stmt is
+            not valid gimple.  Make it so by using a temporary instead.  */
+         if (!is_gimple_reg (x)
+             && is_gimple_reg_type (TREE_TYPE (x)))
+           {
+             gimple_stmt_iterator gsi = gsi_last (stmt_list);
+             x = init_tmp_var (root, x, &gsi);
+             gimple_assign_set_rhs1 (stmt, x);
+           }
        }
     }
 
@@ -1383,8 +2013,8 @@ finalize_nesting_tree_1 (struct nesting_info *root)
     {
       tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field),
                       root->frame_decl, root->chain_field, NULL_TREE);
-      x = build2 (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
-      append_to_statement_list (x, &stmt_list);
+      stmt = gimple_build_assign (x, get_chain_decl (root));
+      gimple_seq_add_stmt (&stmt_list, stmt);
     }
 
   /* If trampolines were created, then we need to initialize them.  */
@@ -1393,41 +2023,37 @@ 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 = build3 (COMPONENT_REF, TREE_TYPE (field),
                      root->frame_decl, field, NULL_TREE);
-         x = build_addr (x, context);
-         arg = tree_cons (NULL, x, arg);
+         arg1 = build_addr (x, context);
 
          x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
-         x = build_function_call_expr (x, arg);
-
-         append_to_statement_list (x, &stmt_list);
+         stmt = gimple_build_call (x, 3, arg1, arg2, arg3);
+         gimple_seq_add_stmt (&stmt_list, stmt);
        }
     }
 
   /* If we created initialization statements, insert them.  */
   if (stmt_list)
     {
-      annotate_all_with_locus (&stmt_list,
-                              DECL_SOURCE_LOCATION (context));
-      append_to_statement_list (BIND_EXPR_BODY (DECL_SAVED_TREE (context)),
-                               &stmt_list);
-      BIND_EXPR_BODY (DECL_SAVED_TREE (context)) = stmt_list;
+      gimple bind;
+      annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context));
+      bind = gimple_seq_first_stmt (gimple_body (context));
+      gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind));
+      gimple_bind_set_body (bind, stmt_list);
     }
 
   /* If a chain_decl was created, then it needs to be registered with
@@ -1447,12 +2073,37 @@ 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,
+                 gimple_seq_first_stmt (gimple_body (root->context)),
+                 false);
+  if (root->debug_var_chain)
+    declare_vars (root->debug_var_chain,
+                 gimple_seq_first_stmt (gimple_body (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.  */
@@ -1464,13 +2115,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);
@@ -1486,16 +2137,15 @@ 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;
-      ggc_free (root);
+      free (root);
       root = next;
     }
   while (root);
 }
 
-static GTY(()) struct nesting_info *root;
-
 /* Main entry point for this pass.  Process FNDECL and all of its nested
    subroutines and turn them into something less tightly bound.  */
 
@@ -1503,21 +2153,28 @@ void
 lower_nested_functions (tree fndecl)
 {
   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);
-  walk_all_functions (convert_nl_goto_reference, root);
-  walk_all_functions (convert_nl_goto_receiver, root);
+  walk_all_functions (convert_nonlocal_reference_stmt,
+                      convert_nonlocal_reference_op,
+                     root);
+  walk_all_functions (convert_local_reference_stmt,
+                      convert_local_reference_op,
+                     root);
+  walk_all_functions (convert_nl_goto_reference, NULL, root);
+  walk_all_functions (convert_nl_goto_receiver, NULL, root);
   convert_all_function_calls (root);
   finalize_nesting_tree (root);
+  unnest_nesting_tree (root);
   free_nesting_tree (root);
-  root = NULL;
+  bitmap_obstack_release (&nesting_info_bitmap_obstack);
 }
 
 #include "gt-tree-nested.h"