OSDN Git Service

cp/:
[pf3gnuchains/gcc-fork.git] / gcc / tree-nested.c
index e5befa4..80041ec 100644 (file)
@@ -1,11 +1,11 @@
-/* Nested function decomposition for trees.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+/* Nested function decomposition for GIMPLE.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 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
 
    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,
    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
    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, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
 #include "function.h"
 #include "tree-dump.h"
 #include "tree-inline.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 "tree-iterator.h"
 #include "tree-flow.h"
 #include "cgraph.h"
 #include "expr.h"
 #include "langhooks.h"
+#include "pointer-set.h"
 #include "ggc.h"
 
 
 #include "ggc.h"
 
 
    been written as independent functions without change.  */
 
 
    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;
   
 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 context;
   tree new_local_var_chain;
+  tree debug_var_chain;
   tree frame_type;
   tree frame_decl;
   tree chain_field;
   tree frame_type;
   tree frame_decl;
   tree chain_field;
@@ -100,25 +98,13 @@ struct nesting_info
 
   bool any_parm_remapped;
   bool any_tramp_created;
 
   bool any_parm_remapped;
   bool any_tramp_created;
+  char static_chain_added;
 };
 
 
 };
 
 
-/* Hashing and equality functions for nesting_info->var_map.  */
+/* Obstack used for the bitmaps in the struct above.  */
+static struct bitmap_obstack nesting_info_bitmap_obstack;
 
 
-static hashval_t
-var_map_hash (const void *x)
-{
-  const struct var_map_elt *a = x;
-  return htab_hash_pointer (a->old);
-}
-
-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.  */
 
 /* We're working in so many different function contexts simultaneously,
    that create_tmp_var is dangerous.  Prevent mishap.  */
@@ -143,17 +129,24 @@ 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;
   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;
 }
 
   info->new_local_var_chain = tmp_var;
 
   return tmp_var;
 }
 
-/* Take the address of EXP.  Mark it for addressability as necessary.  */
+/* Take the address of EXP to be used within function CONTEXT.
+   Mark it for addressability as necessary.  */
 
 tree
 
 tree
-build_addr (tree exp)
+build_addr (tree exp, tree context)
 {
   tree base = exp;
 {
   tree base = exp;
+  tree save_context;
+  tree retval;
 
   while (handled_component_p (base))
     base = TREE_OPERAND (base, 0);
 
   while (handled_component_p (base))
     base = TREE_OPERAND (base, 0);
@@ -161,12 +154,23 @@ build_addr (tree exp)
   if (DECL_P (base))
     TREE_ADDRESSABLE (base) = 1;
 
   if (DECL_P (base))
     TREE_ADDRESSABLE (base) = 1;
 
-  return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
+  /* Building the ADDR_EXPR will compute a set of properties for
+     that ADDR_EXPR.  Those properties are unfortunately context
+     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
+     way the properties are for the ADDR_EXPR are computed properly.  */
+  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;
+  return retval;
 }
 
 /* Insert FIELD into TYPE, sorted by alignment requirements.  */
 
 }
 
 /* Insert FIELD into TYPE, sorted by alignment requirements.  */
 
-static void
+void
 insert_field_into_struct (tree type, tree field)
 {
   tree *p;
 insert_field_into_struct (tree type, tree field)
 {
   tree *p;
@@ -179,6 +183,10 @@ insert_field_into_struct (tree type, tree field)
 
   TREE_CHAIN (field) = *p;
   *p = 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
 }
 
 /* Build or return the RECORD_TYPE that describes the frame state that is
@@ -206,6 +214,14 @@ get_frame_type (struct nesting_info *info)
 
       info->frame_type = type;
       info->frame_decl = create_tmp_var_for (info, type, "FRAME");
 
       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;
 }
     }
   return type;
 }
@@ -237,22 +253,18 @@ static tree
 lookup_field_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
 lookup_field_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
   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 = *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))
       DECL_NAME (field) = DECL_NAME (decl);
 
       if (use_pointer_in_frame (decl))
@@ -273,19 +285,13 @@ lookup_field_for_decl (struct nesting_info *info, tree decl,
        }
 
       insert_field_into_struct (get_frame_type (info), field);
        }
 
       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;
     }
 
       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
 }
 
 /* Build or return the variable that holds the static chain within
@@ -308,7 +314,8 @@ get_chain_decl (struct nesting_info *info)
         Note also that it's represented as a parameter.  This is more
         close to the truth, since the initial value does come from 
         the caller.  */
         Note also that it's represented as a parameter.  This is more
         close to the truth, since the initial value does come from 
         the caller.  */
-      decl = build_decl (PARM_DECL, create_tmp_var_name ("CHAIN"), type);
+      decl = build_decl (DECL_SOURCE_LOCATION (info->context),
+                        PARM_DECL, create_tmp_var_name ("CHAIN"), type);
       DECL_ARTIFICIAL (decl) = 1;
       DECL_IGNORED_P (decl) = 1;
       TREE_USED (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
       DECL_IGNORED_P (decl) = 1;
       TREE_USED (decl) = 1;
@@ -349,31 +356,71 @@ get_chain_field (struct nesting_info *info)
   return field;
 }
 
   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
 /* 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
 
 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);
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build (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;
 }
 
 
   return t;
 }
 
+
 /* Similarly, but only do so to force EXP to satisfy is_gimple_val.  */
 
 static tree
 /* 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
 {
   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, gimple_stmt_iterator *gsi)
+{
+  tree t;
+  gimple stmt;
+
+  t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
+  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;
 }
 
 /* Build or return the type used to represent a nested function trampoline.  */
 }
 
 /* Build or return the type used to represent a nested function trampoline.  */
@@ -381,10 +428,10 @@ tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
 static GTY(()) tree trampoline_type;
 
 static tree
 static GTY(()) tree trampoline_type;
 
 static tree
-get_trampoline_type (void)
+get_trampoline_type (struct nesting_info *info)
 {
 {
-  tree record, t;
   unsigned align, size;
   unsigned align, size;
+  tree t;
 
   if (trampoline_type)
     return trampoline_type;
 
   if (trampoline_type)
     return trampoline_type;
@@ -402,16 +449,18 @@ get_trampoline_type (void)
 
   t = build_index_type (build_int_cst (NULL_TREE, size - 1));
   t = build_array_type (char_type_node, t);
 
   t = build_index_type (build_int_cst (NULL_TREE, size - 1));
   t = build_array_type (char_type_node, t);
-  t = build_decl (FIELD_DECL, get_identifier ("__data"), t);
+  t = build_decl (DECL_SOURCE_LOCATION (info->context),
+                 FIELD_DECL, get_identifier ("__data"), t);
   DECL_ALIGN (t) = align;
   DECL_USER_ALIGN (t) = 1;
 
   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
 }
 
 /* Given DECL, a nested function, find or create a field in the non-local
@@ -421,39 +470,29 @@ static tree
 lookup_tramp_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
 lookup_tramp_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
   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 = *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);
       DECL_NAME (field) = DECL_NAME (decl);
-      TREE_TYPE (field) = get_trampoline_type ();
+      TREE_TYPE (field) = get_trampoline_type (info);
       TREE_ADDRESSABLE (field) = 1;
 
       insert_field_into_struct (get_frame_type (info), field);
       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;
     }
 
       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
 } 
 
 /* Build or return the field within the non-local frame state that holds
@@ -498,121 +537,103 @@ get_nl_goto_field (struct nesting_info *info)
 
   return field;
 }
 
   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 changed;
-};
 
 
-/* A subroutine of walk_function.  Iterate over all sub-statements of *TP.  */
+/* Invoke CALLBACK on all statements of GIMPLE sequence SEQ.  */
 
 static void
 
 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;
+  struct walk_stmt_info wi;
 
 
-    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;
+  memset (&wi, 0, sizeof (wi));
+  wi.info = info;
+  wi.val_only = true;
+  walk_gimple_seq (seq, callback_stmt, callback_op, &wi);
+}
 
 
-    case RETURN_EXPR:
-      walk_stmts (wi, &TREE_OPERAND (t, 0));
-      break;
 
 
-    case MODIFY_EXPR:
-      /* The immediate arguments of a MODIFY_EXPR may use COMPONENT_REF.  */
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
-      wi->val_only = false;
-      walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL);
-      wi->val_only = true;
-      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
 
 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;
 {
   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));
   memset (&wi, 0, sizeof (wi));
-  wi.callback = callback;
   wi.info = info;
   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
 }
 
 /* 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)
 {
   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);
 }
       root = root->next;
     }
   while (root);
 }
-\f
-/* We have to check for a fairly pathalogical case.  The operands of function
+
+
+/* We have to check for a fairly pathological case.  The operands of function
    nested function are to be interpreted in the context of the enclosing
    function.  So if any are variably-sized, they will get remapped when the
    enclosing function is inlined.  But that remapping would also have to be
    nested function are to be interpreted in the context of the enclosing
    function.  So if any are variably-sized, they will get remapped when the
    enclosing function is inlined.  But that remapping would also have to be
@@ -644,7 +665,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))
   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))
          return true;
 
       if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl))
@@ -660,8 +681,10 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
 static struct nesting_info *
 create_nesting_tree (struct cgraph_node *cgn)
 {
 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)
   info->context = cgn->decl;
 
   for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
@@ -685,14 +708,14 @@ create_nesting_tree (struct cgraph_node *cgn)
 
 static tree
 get_static_chain (struct nesting_info *info, tree target_context,
 
 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;
 
   if (info->context == target_context)
     {
 {
   struct nesting_info *i;
   tree x;
 
   if (info->context == target_context)
     {
-      x = build_addr (info->frame_decl);
+      x = build_addr (info->frame_decl, target_context);
     }
   else
     {
     }
   else
     {
@@ -703,21 +726,22 @@ 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);
          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 = init_tmp_var (info, x, tsi);
+         x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+         x = init_tmp_var (info, x, gsi);
        }
     }
 
   return x;
 }
 
        }
     }
 
   return x;
 }
 
+
 /* Return an expression referencing FIELD from TARGET_CONTEXT's non-local
    frame as seen from INFO->CONTEXT.  Insert any necessary computations
 /* 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,
 
 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;
 {
   struct nesting_info *i;
   tree x;
@@ -737,18 +761,98 @@ 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);
          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 = init_tmp_var (info, x, tsi);
+         x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+         x = init_tmp_var (info, x, gsi);
        }
 
       x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
     }
 
        }
 
       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;
 }
 
   return x;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to VAR
+static void note_nonlocal_vla_type (struct nesting_info *info, tree type);
+
+/* 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 (DECL_SOURCE_LOCATION (decl),
+                        VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  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;
+  if ((TREE_CODE (decl) == PARM_DECL
+       || TREE_CODE (decl) == RESULT_DECL
+       || TREE_CODE (decl) == VAR_DECL)
+      && DECL_BY_REFERENCE (decl))
+    DECL_BY_REFERENCE (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;
+
+  if (!optimize
+      && info->context != target_context
+      && variably_modified_type_p (TREE_TYPE (decl), NULL))
+    note_nonlocal_vla_type (info, TREE_TYPE (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
    and PARM_DECLs that belong to outer functions.
 
    The rewrite will involve some number of structure accesses back up
@@ -757,10 +861,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
    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 = data;
-  struct nesting_info *info = wi->info;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp;
 
   *walk_subtrees = 0;
   tree t = *tp;
 
   *walk_subtrees = 0;
@@ -775,36 +879,37 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
     case PARM_DECL:
       if (decl_function_context (t) != info->context)
        {
     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;
 
          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->val_only)
-           x = init_tmp_var (info, x, &wi->tsi);
+           {
+             if (wi->is_lhs)
+               x = save_tmp_var (info, x, &wi->gsi);
+             else
+               x = init_tmp_var (info, x, &wi->gsi);
+           }
 
          *tp = x;
        }
       break;
 
 
          *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;
-       }
-      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
     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
@@ -818,22 +923,29 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       {
        bool save_val_only = wi->val_only;
 
       {
        bool save_val_only = wi->val_only;
 
-       wi->changed = false;
        wi->val_only = false;
        wi->val_only = false;
-       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
+       wi->is_lhs = false;
+       wi->changed = false;
+       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference_op, wi, 0);
        wi->val_only = true;
 
        if (wi->changed)
          {
        wi->val_only = true;
 
        if (wi->changed)
          {
-           /* 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);
+           tree save_context;
+
+           /* 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);
+           current_function_decl = save_context;
 
            /* If the callback converted the address argument in a context
               where we only accept variables (and min_invariant, presumably),
               then compute the address into a temporary.  */
            if (save_val_only)
 
            /* If the callback converted the address argument in a context
               where we only accept variables (and min_invariant, presumably),
               then compute the address into a temporary.  */
            if (save_val_only)
-             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+             *tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
+                                     t, &wi->gsi);
          }
       }
       break;
          }
       }
       break;
@@ -848,31 +960,39 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
         anything that describes the references.  Otherwise, we lose track
         of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value.  */
       wi->val_only = true;
         anything that describes the references.  Otherwise, we lose track
         of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value.  */
       wi->val_only = true;
+      wi->is_lhs = false;
       for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
        {
          if (TREE_CODE (t) == COMPONENT_REF)
       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)
            {
                       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)
            {
            }
          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;
            }
        }
       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:
       break;
 
     default:
@@ -880,24 +1000,356 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
        {
          *walk_subtrees = 1;
           wi->val_only = true;
        {
          *walk_subtrees = 1;
           wi->val_only = true;
+         wi->is_lhs = false;
+       }
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+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;
+}
+
+/* Create nonlocal debug decls for nonlocal VLA array bounds.  */
+
+static void
+note_nonlocal_vla_type (struct nesting_info *info, tree type)
+{
+  while (POINTER_TYPE_P (type) && !TYPE_NAME (type))
+    type = TREE_TYPE (type);
+
+  if (TYPE_NAME (type)
+      && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+    type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
+
+  while (POINTER_TYPE_P (type)
+        || TREE_CODE (type) == VECTOR_TYPE
+        || TREE_CODE (type) == FUNCTION_TYPE
+        || TREE_CODE (type) == METHOD_TYPE)
+    type = TREE_TYPE (type);
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree domain, t;
+
+      note_nonlocal_vla_type (info, TREE_TYPE (type));
+      domain = TYPE_DOMAIN (type);
+      if (domain)
+       {
+         t = TYPE_MIN_VALUE (domain);
+         if (t && (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL)
+             && decl_function_context (t) != info->context)
+           get_nonlocal_debug_decl (info, t);
+         t = TYPE_MAX_VALUE (domain);
+         if (t && (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL)
+             && decl_function_context (t) != info->context)
+           get_nonlocal_debug_decl (info, t);
+       }
+    }
+}
+
+/* Create nonlocal debug decls for nonlocal VLA array bounds for VLAs
+   in BLOCK.  */
+
+static void
+note_nonlocal_block_vlas (struct nesting_info *info, tree block)
+{
+  tree var;
+
+  for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var))
+    if (TREE_CODE (var) == VAR_DECL
+       && variably_modified_type_p (TREE_TYPE (var), NULL)
+       && DECL_HAS_VALUE_EXPR_P (var)
+       && decl_function_context (var) != info->context)
+      note_nonlocal_vla_type (info, TREE_TYPE (var));
+}
+
+/* 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;
        }
       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 (gimple_location (stmt),
+                               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;
+
+    case GIMPLE_BIND:
+      if (!optimize && gimple_bind_block (stmt))
+       note_nonlocal_block_vlas (info, gimple_bind_block (stmt));
+
+      *handled_ops_p = false;
+      return NULL_TREE;
+
+    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;
 }
 
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to VAR
+
+/* 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 (DECL_SOURCE_LOCATION (decl),
+                        VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  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;
+  if ((TREE_CODE (decl) == PARM_DECL
+       || TREE_CODE (decl) == RESULT_DECL
+       || TREE_CODE (decl) == VAR_DECL)
+      && DECL_BY_REFERENCE (decl))
+    DECL_BY_REFERENCE (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.  */
 
    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
 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 = data;
-  struct nesting_info *info = wi->info;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp, field, x;
   tree t = *tp, field, x;
+  bool save_val_only;
 
 
+  *walk_subtrees = 0;
   switch (TREE_CODE (t))
     {
     case VAR_DECL:
   switch (TREE_CODE (t))
     {
     case VAR_DECL:
@@ -921,36 +1373,49 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
            break;
          wi->changed = true;
 
            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->val_only)
-           x = init_tmp_var (info, x, &wi->tsi);
+           {
+             if (wi->is_lhs)
+               x = save_tmp_var (info, x, &wi->gsi);
+             else
+               x = init_tmp_var (info, x, &wi->gsi);
+           }
+
          *tp = x;
        }
       break;
 
     case ADDR_EXPR:
          *tp = x;
        }
       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_op, wi, NULL);
+      wi->val_only = save_val_only;
 
 
-       wi->changed = false;
-       wi->val_only = 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 = gsi_gimplify_val ((struct nesting_info *) wi->info,
+                                   t, &wi->gsi);
+       }
       break;
 
     case REALPART_EXPR:
       break;
 
     case REALPART_EXPR:
@@ -962,32 +1427,42 @@ 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.  */
       /* 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->val_only = true;
+      wi->is_lhs = false;
       for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
        {
          if (TREE_CODE (t) == COMPONENT_REF)
       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)
            {
                       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);
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
                         NULL);
                         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)
            {
                         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);
                         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;
                         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:
       break;
 
     default:
@@ -995,35 +1470,254 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
        {
          *walk_subtrees = 1;
          wi->val_only = true;
        {
          *walk_subtrees = 1;
          wi->val_only = true;
+         wi->is_lhs = false;
+       }
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+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 (gimple_location (stmt),
+                               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;
       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;
 }
 
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that 
-   reference labels from outer functions.  The rewrite will be a 
+
+/* 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
    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 = data;
-  struct nesting_info *info = wi->info, *i;
-  tree t = *tp, label, new_label, target_context, x, arg, field;
-  struct var_map_elt *elt;
+  struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
+  tree label, new_label, target_context, x, field;
   void **slot;
   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)
   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)
   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;
 
   for (i = info->outer; target_context != i->context; i = i->outer)
     continue;
@@ -1033,86 +1727,94 @@ 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
      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 (UNKNOWN_LOCATION);
+      DECL_NONLOCAL (new_label) = 1;
+      *slot = new_label;
+    }
+  else
+    new_label = (tree) *slot;
   
   /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field).  */
   field = get_nl_goto_field (i);
   
   /* 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);
-  x = tsi_gimplify_val (info, x, &wi->tsi);
-  arg = tree_cons (NULL, x, NULL);
-  x = build_addr (new_label);
-  arg = tree_cons (NULL, x, arg);
-  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 = get_frame_field (info, target_context, field, &wi->gsi);
+  x = build_addr (x, target_context);
+  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;
 }
 
   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
    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
    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 = 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;
+    }
 
 
-  dummy.old = label;
-  elt = htab_find (info->var_map, &dummy);
-  if (!elt)
-    return NULL_TREE;
-  new_label = elt->new;
+  label = gimple_label_label (stmt);
+
+  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.  */
 
   /* 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;
 }
 
   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
    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 = data;
-  struct nesting_info *info = wi->info, *i;
-  tree t = *tp, decl, target_context, x, arg;
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  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))
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -1138,6 +1840,10 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       if (DECL_NO_STATIC_CHAIN (decl))
        break;
 
       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)
       /* 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)
@@ -1145,30 +1851,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 = 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 = build_addr (x);
-      x = tsi_gimplify_val (info, x, &wi->tsi);
-      arg = tree_cons (NULL, x, NULL);
+      x = get_frame_field (info, target_context, x, &wi->gsi);
+      x = build_addr (x, target_context);
+      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.  */
 
       /* 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);
 
       /* 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;
 
 
       *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;
     default:
       if (!IS_TYPE_OR_DECL_P (t))
        *walk_subtrees = 1;
@@ -1178,44 +1877,128 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
   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
 
 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 = 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 CALL_EXPR:
-      decl = get_callee_fndecl (t);
+    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 GIMPLE_CALL:
+      decl = gimple_call_fndecl (stmt);
       if (!decl)
        break;
       target_context = decl_function_context (decl);
       if (target_context && !DECL_NO_STATIC_CHAIN (decl))
       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;
 
       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 (gimple_location (stmt),
+                                   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;
 
       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;
       break;
+
+    default:
+      /* Keep looking for other operands.  */
+      *handled_ops_p = false;
+      return NULL_TREE;
     }
 
     }
 
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
   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.  */
 /* 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.  */
@@ -1228,8 +2011,9 @@ convert_all_function_calls (struct nesting_info *root)
       if (root->inner)
        convert_all_function_calls (root->inner);
 
       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)
 
       /* If the function does not use a static chain, then remember that.  */
       if (root->outer && !root->chain_decl && !root->chain_field)
@@ -1242,6 +2026,142 @@ convert_all_function_calls (struct nesting_info *root)
   while (root);
 }
 
   while (root);
 }
 
+struct nesting_copy_body_data
+{
+  copy_body_data cb;
+  struct nesting_info *root;
+};
+
+/* A helper subroutine for debug_var_chain type remapping.  */
+
+static tree
+nesting_copy_decl (tree decl, copy_body_data *id)
+{
+  struct nesting_copy_body_data *nid = (struct nesting_copy_body_data *) id;
+  void **slot = pointer_map_contains (nid->root->var_map, decl);
+
+  if (slot)
+    return (tree) *slot;
+
+  if (TREE_CODE (decl) == TYPE_DECL && DECL_ORIGINAL_TYPE (decl))
+    {
+      tree new_decl = copy_decl_no_change (decl, id);
+      DECL_ORIGINAL_TYPE (new_decl)
+       = remap_type (DECL_ORIGINAL_TYPE (decl), id);
+      return new_decl;
+    }
+
+  if (TREE_CODE (decl) == VAR_DECL
+      || TREE_CODE (decl) == PARM_DECL
+      || TREE_CODE (decl) == RESULT_DECL)
+    return decl;
+
+  return copy_decl_no_change (decl, id);
+}
+
+/* A helper function for remap_vla_decls.  See if *TP contains
+   some remapped variables.  */
+
+static tree
+contains_remapped_vars (tree *tp, int *walk_subtrees, void *data)
+{
+  struct nesting_info *root = (struct nesting_info *) data;
+  tree t = *tp;
+  void **slot;
+
+  if (DECL_P (t))
+    {
+      *walk_subtrees = 0;
+      slot = pointer_map_contains (root->var_map, t);
+
+      if (slot)
+       return (tree) *slot;
+    }
+  return NULL;
+}
+
+/* Remap VLA decls in BLOCK and subblocks if remapped variables are
+   involved.  */
+
+static void
+remap_vla_decls (tree block, struct nesting_info *root)
+{
+  tree var, subblock, val, type;
+  struct nesting_copy_body_data id;
+
+  for (subblock = BLOCK_SUBBLOCKS (block);
+       subblock;
+       subblock = BLOCK_CHAIN (subblock))
+    remap_vla_decls (subblock, root);
+
+  for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var))
+    {
+      if (TREE_CODE (var) == VAR_DECL
+         && variably_modified_type_p (TREE_TYPE (var), NULL)
+         && DECL_HAS_VALUE_EXPR_P (var))
+       {
+         type = TREE_TYPE (var);
+         val = DECL_VALUE_EXPR (var);
+         if (walk_tree (&type, contains_remapped_vars, root, NULL) != NULL
+             ||  walk_tree (&val, contains_remapped_vars, root, NULL) != NULL)
+           break;
+       }
+    }
+  if (var == NULL_TREE)
+    return;
+
+  memset (&id, 0, sizeof (id));
+  id.cb.copy_decl = nesting_copy_decl;
+  id.cb.decl_map = pointer_map_create ();
+  id.root = root;
+
+  for (; var; var = TREE_CHAIN (var))
+    if (TREE_CODE (var) == VAR_DECL
+       && variably_modified_type_p (TREE_TYPE (var), NULL)
+       && DECL_HAS_VALUE_EXPR_P (var))
+      {
+       struct nesting_info *i;
+       tree newt, t, context;
+
+       t = type = TREE_TYPE (var);
+       val = DECL_VALUE_EXPR (var);
+       if (walk_tree (&type, contains_remapped_vars, root, NULL) == NULL
+           && walk_tree (&val, contains_remapped_vars, root, NULL) == NULL)
+         continue;
+
+       context = decl_function_context (var);
+       for (i = root; i; i = i->outer)
+         if (i->context == context)
+           break;
+
+       if (i == NULL)
+         continue;
+
+       id.cb.src_fn = i->context;
+       id.cb.dst_fn = i->context;
+       id.cb.src_cfun = DECL_STRUCT_FUNCTION (root->context);
+
+       TREE_TYPE (var) = newt = remap_type (type, &id.cb);
+       while (POINTER_TYPE_P (newt) && !TYPE_NAME (newt))
+         {
+           newt = TREE_TYPE (newt);
+           t = TREE_TYPE (t);
+         }
+       if (TYPE_NAME (newt)
+           && TREE_CODE (TYPE_NAME (newt)) == TYPE_DECL
+           && DECL_ORIGINAL_TYPE (TYPE_NAME (newt))
+           && newt != t
+           && TYPE_NAME (newt) == TYPE_NAME (t))
+         TYPE_NAME (newt) = remap_decl (TYPE_NAME (newt), &id.cb);
+
+       walk_tree (&val, copy_tree_body_r, &id.cb, NULL);
+       if (val != DECL_VALUE_EXPR (var))
+         SET_DECL_VALUE_EXPR (var, val);
+      }
+
+  pointer_map_destroy (id.cb.decl_map);
+}
+
 /* Do "everything else" to clean up or complete state collected by the
    various walking passes -- lay out the types and decls, generate code
    to initialize the frame decl, store critical expressions in the
 /* Do "everything else" to clean up or complete state collected by the
    various walking passes -- lay out the types and decls, generate code
    to initialize the frame decl, store critical expressions in the
@@ -1250,17 +2170,40 @@ convert_all_function_calls (struct nesting_info *root)
 static void
 finalize_nesting_tree_1 (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;
   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.  */
   if (root->frame_type)
     {
 
   /* 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;
+      tree *adjust;
+
+      warn_padded = 0;
       layout_type (root->frame_type);
       layout_type (root->frame_type);
+      warn_padded = save_warn_padded;
       layout_decl (root->frame_decl, 0);
       layout_decl (root->frame_decl, 0);
+
+      /* Remove root->frame_decl from root->new_local_var_chain, so
+        that we can declare it also in the lexical blocks, which
+        helps ensure virtual regs that end up appearing in its RTL
+        expression get substituted in instantiate_virtual_regs().  */
+      for (adjust = &root->new_local_var_chain;
+          *adjust != root->frame_decl;
+          adjust = &TREE_CHAIN (*adjust))
+       gcc_assert (TREE_CHAIN (*adjust));
+      *adjust = TREE_CHAIN (*adjust);
+
+      TREE_CHAIN (root->frame_decl) = NULL_TREE;
+      declare_vars (root->frame_decl,
+                   gimple_seq_first_stmt (gimple_body (context)), true);
     }
 
   /* If any parameters were referenced non-locally, then we need to 
     }
 
   /* If any parameters were referenced non-locally, then we need to 
@@ -1278,14 +2221,23 @@ finalize_nesting_tree_1 (struct nesting_info *root)
            continue;
 
          if (use_pointer_in_frame (p))
            continue;
 
          if (use_pointer_in_frame (p))
-           x = build_addr (p);
+           x = build_addr (p, context);
          else
            x = p;
 
          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);
-         append_to_statement_list (x, &stmt_list);
+         y = build3 (COMPONENT_REF, TREE_TYPE (field),
+                     root->frame_decl, field, NULL_TREE);
+         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);
+           }
        }
     }
 
        }
     }
 
@@ -1293,10 +2245,10 @@ finalize_nesting_tree_1 (struct nesting_info *root)
      from chain_decl.  */
   if (root->chain_field)
     {
      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));
-      append_to_statement_list (x, &stmt_list);
+      tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field),
+                      root->frame_decl, root->chain_field, NULL_TREE);
+      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.  */
     }
 
   /* If trampolines were created, then we need to initialize them.  */
@@ -1305,41 +2257,37 @@ finalize_nesting_tree_1 (struct nesting_info *root)
       struct nesting_info *i;
       for (i = root->inner; i ; i = i->next)
        {
       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))
 
          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
          else
-           x = build_addr (root->frame_decl);
-         arg = tree_cons (NULL, x, NULL);
+           arg3 = build_addr (root->frame_decl, context);
 
 
-         x = build_addr (i->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);
-         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 = 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)
     {
        }
     }
 
   /* 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
     }
 
   /* If a chain_decl was created, then it needs to be registered with
@@ -1359,12 +2307,100 @@ 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)
   /* 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)
+    {
+      tree debug_var;
+      gimple scope;
+
+      remap_vla_decls (DECL_INITIAL (root->context), root);
+
+      for (debug_var = root->debug_var_chain; debug_var;
+          debug_var = TREE_CHAIN (debug_var))
+       if (variably_modified_type_p (TREE_TYPE (debug_var), NULL))
+         break;
+
+      /* If there are any debug decls with variable length types,
+        remap those types using other debug_var_chain variables.  */
+      if (debug_var)
+       {
+         struct nesting_copy_body_data id;
+
+         memset (&id, 0, sizeof (id));
+         id.cb.copy_decl = nesting_copy_decl;
+         id.cb.decl_map = pointer_map_create ();
+         id.root = root;
+
+         for (; debug_var; debug_var = TREE_CHAIN (debug_var))
+           if (variably_modified_type_p (TREE_TYPE (debug_var), NULL))
+             {
+               tree type = TREE_TYPE (debug_var);
+               tree newt, t = type;
+               struct nesting_info *i;
+
+               for (i = root; i; i = i->outer)
+                 if (variably_modified_type_p (type, i->context))
+                   break;
+
+               if (i == NULL)
+                 continue;
+
+               id.cb.src_fn = i->context;
+               id.cb.dst_fn = i->context;
+               id.cb.src_cfun = DECL_STRUCT_FUNCTION (root->context);
+
+               TREE_TYPE (debug_var) = newt = remap_type (type, &id.cb);
+               while (POINTER_TYPE_P (newt) && !TYPE_NAME (newt))
+                 {
+                   newt = TREE_TYPE (newt);
+                   t = TREE_TYPE (t);
+                 }
+               if (TYPE_NAME (newt)
+                   && TREE_CODE (TYPE_NAME (newt)) == TYPE_DECL
+                   && DECL_ORIGINAL_TYPE (TYPE_NAME (newt))
+                   && newt != t
+                   && TYPE_NAME (newt) == TYPE_NAME (t))
+                 TYPE_NAME (newt) = remap_decl (TYPE_NAME (newt), &id.cb);
+             }
+
+         pointer_map_destroy (id.cb.decl_map);
+       }
+
+      scope = gimple_seq_first_stmt (gimple_body (root->context));
+      if (gimple_bind_block (scope))
+       declare_vars (root->debug_var_chain, scope, true);
+      else
+       BLOCK_VARS (DECL_INITIAL (root->context))
+         = chainon (BLOCK_VARS (DECL_INITIAL (root->context)),
+                    root->debug_var_chain);
+    }
 
   /* Dump the translated tree function.  */
   dump_function (TDI_nested, root->context);
 
   /* 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.  */
 
   /* For nested functions update the cgraph to reflect unnesting.
      We also delay finalizing of these functions up to this point.  */
@@ -1376,13 +2412,13 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 }
 
 static void
 }
 
 static void
-finalize_nesting_tree (struct nesting_info *root)
+unnest_nesting_tree (struct nesting_info *root)
 {
   do
     {
       if (root->inner)
 {
   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);
       root = root->next;
     }
   while (root);
@@ -1398,7 +2434,8 @@ free_nesting_tree (struct nesting_info *root)
     {
       if (root->inner)
        free_nesting_tree (root->inner);
     {
       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;
       next = root->next;
       free (root);
       root = next;
@@ -1412,22 +2449,29 @@ free_nesting_tree (struct nesting_info *root)
 void
 lower_nested_functions (tree fndecl)
 {
 void
 lower_nested_functions (tree fndecl)
 {
-  struct nesting_info *root;
   struct cgraph_node *cgn;
   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;
 
 
   /* 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);
   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);
   convert_all_function_calls (root);
   finalize_nesting_tree (root);
+  unnest_nesting_tree (root);
   free_nesting_tree (root);
   free_nesting_tree (root);
+  bitmap_obstack_release (&nesting_info_bitmap_obstack);
 }
 
 #include "gt-tree-nested.h"
 }
 
 #include "gt-tree-nested.h"