OSDN Git Service

* tree-nested.c (finalize_nesting_tree_1): Declare the
[pf3gnuchains/gcc-fork.git] / gcc / tree-nested.c
index 4f6ec71..df55770 100644 (file)
@@ -1,11 +1,11 @@
-/* Nested function decomposition for trees.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+/* Nested function decomposition for GIMPLE.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 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
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful,
@@ -14,9 +14,8 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "function.h"
 #include "tree-dump.h"
 #include "tree-inline.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "tree-iterator.h"
 #include "tree-flow.h"
 #include "cgraph.h"
 #include "expr.h"
 #include "langhooks.h"
+#include "pointer-set.h"
 #include "ggc.h"
 
 
    been written as independent functions without change.  */
 
 
-struct var_map_elt
-{
-  tree old;
-  tree new;
-};
-
 struct nesting_info
 {
   struct nesting_info *outer;
   struct nesting_info *inner;
   struct nesting_info *next;
   
-  htab_t var_map;
+  struct pointer_map_t *field_map;
+  struct pointer_map_t *var_map;
+  bitmap suppress_expansion;
+
   tree context;
   tree new_local_var_chain;
+  tree debug_var_chain;
   tree frame_type;
   tree frame_decl;
   tree chain_field;
@@ -100,25 +98,13 @@ struct nesting_info
 
   bool any_parm_remapped;
   bool any_tramp_created;
+  char static_chain_added;
 };
 
 
-/* Hashing and equality functions for nesting_info->var_map.  */
-
-static hashval_t
-var_map_hash (const void *x)
-{
-  const struct var_map_elt *a = x;
-  return htab_hash_pointer (a->old);
-}
+/* Obstack used for the bitmaps in the struct above.  */
+static struct bitmap_obstack nesting_info_bitmap_obstack;
 
-static int
-var_map_eq (const void *x, const void *y)
-{
-  const struct var_map_elt *a = x;
-  const struct var_map_elt *b = y;
-  return a->old == b->old;
-}
 
 /* We're working in so many different function contexts simultaneously,
    that create_tmp_var is dangerous.  Prevent mishap.  */
@@ -143,6 +129,10 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix)
   DECL_CONTEXT (tmp_var) = info->context;
   TREE_CHAIN (tmp_var) = info->new_local_var_chain;
   DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
+  if (TREE_CODE (type) == COMPLEX_TYPE
+      || TREE_CODE (type) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (tmp_var) = 1;
+
   info->new_local_var_chain = tmp_var;
 
   return tmp_var;
@@ -166,7 +156,7 @@ build_addr (tree exp, tree context)
 
   /* Building the ADDR_EXPR will compute a set of properties for
      that ADDR_EXPR.  Those properties are unfortunately context
-     specific.  ie, they are dependent on CURRENT_FUNCTION_DECL.
+     specific, i.e., they are dependent on CURRENT_FUNCTION_DECL.
 
      Temporarily set CURRENT_FUNCTION_DECL to the desired context,
      build the ADDR_EXPR, then restore CURRENT_FUNCTION_DECL.  That
@@ -174,13 +164,13 @@ build_addr (tree exp, tree context)
   save_context = current_function_decl;
   current_function_decl = context;
   retval = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
-  current_function_decl = save_context;;
+  current_function_decl = save_context;
   return retval;
 }
 
 /* Insert FIELD into TYPE, sorted by alignment requirements.  */
 
-static void
+void
 insert_field_into_struct (tree type, tree field)
 {
   tree *p;
@@ -193,6 +183,10 @@ insert_field_into_struct (tree type, tree field)
 
   TREE_CHAIN (field) = *p;
   *p = field;
+
+  /* Set correct alignment for frame struct type.  */
+  if (TYPE_ALIGN (type) < DECL_ALIGN (field))
+    TYPE_ALIGN (type) = DECL_ALIGN (field);
 }
 
 /* Build or return the RECORD_TYPE that describes the frame state that is
@@ -220,6 +214,14 @@ get_frame_type (struct nesting_info *info)
 
       info->frame_type = type;
       info->frame_decl = create_tmp_var_for (info, type, "FRAME");
+
+      /* ??? Always make it addressable for now, since it is meant to
+        be pointed to by the static chain pointer.  This pessimizes
+        when it turns out that no static chains are needed because
+        the nested functions referencing non-local variables are not
+        reachable, but the true pessimization is to create the non-
+        local frame structure in the first place.  */
+      TREE_ADDRESSABLE (info->frame_decl) = 1;
     }
   return type;
 }
@@ -251,22 +253,18 @@ static tree
 lookup_field_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
-  tree field;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, insert);
-  if (!slot)
+  if (insert == NO_INSERT)
     {
-      gcc_assert (insert != INSERT);
-      return NULL;
+      slot = pointer_map_contains (info->field_map, decl);
+      return slot ? (tree) *slot : NULL_TREE;
     }
-  elt = *slot;
 
-  if (!elt && insert == INSERT)
+  slot = pointer_map_insert (info->field_map, decl);
+  if (!*slot)
     {
-      field = make_node (FIELD_DECL);
+      tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
 
       if (use_pointer_in_frame (decl))
@@ -287,19 +285,13 @@ lookup_field_for_decl (struct nesting_info *info, tree decl,
        }
 
       insert_field_into_struct (get_frame_type (info), field);
-  
-      elt = xmalloc (sizeof (*elt));
-      elt->old = decl;
-      elt->new = field;
-      *slot = elt;
+      *slot = field;
 
       if (TREE_CODE (decl) == PARM_DECL)
        info->any_parm_remapped = true;
     }
-  else
-    field = elt ? elt->new : NULL;
 
-  return field;
+  return (tree) *slot;
 }
 
 /* Build or return the variable that holds the static chain within
@@ -363,46 +355,69 @@ get_chain_field (struct nesting_info *info)
   return field;
 }
 
+/* Initialize a new temporary with the GIMPLE_CALL STMT.  */
+
+static tree
+init_tmp_var_with_call (struct nesting_info *info, gimple_stmt_iterator *gsi,
+                       gimple call)
+{
+  tree t;
+
+  t = create_tmp_var_for (info, gimple_call_return_type (call), NULL);
+  gimple_call_set_lhs (call, t);
+  if (! gsi_end_p (*gsi))
+    gimple_set_location (call, gimple_location (gsi_stmt (*gsi)));
+  gsi_insert_before (gsi, call, GSI_SAME_STMT);
+
+  return t;
+}
+
+  
 /* Copy EXP into a temporary.  Allocate the temporary in the context of
-   INFO and insert the initialization statement before TSI.  */
+   INFO and insert the initialization statement before GSI.  */
 
 static tree
-init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+init_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi)
 {
-  tree t, stmt;
+  tree t;
+  gimple stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = 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;
 }
 
+
 /* Similarly, but only do so to force EXP to satisfy is_gimple_val.  */
 
 static tree
-tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+gsi_gimplify_val (struct nesting_info *info, tree exp,
+                 gimple_stmt_iterator *gsi)
 {
   if (is_gimple_val (exp))
     return exp;
   else
-    return init_tmp_var (info, exp, tsi);
+    return init_tmp_var (info, exp, gsi);
 }
 
 /* Similarly, but copy from the temporary and insert the statement
    after the iterator.  */
 
 static tree
-save_tmp_var (struct nesting_info *info, tree exp,
-             tree_stmt_iterator *tsi)
+save_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi)
 {
-  tree t, stmt;
+  tree t;
+  gimple stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build (MODIFY_EXPR, TREE_TYPE (t), exp, t);
-  SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
-  tsi_link_after (tsi, stmt, TSI_SAME_STMT);
+  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;
 }
@@ -414,8 +429,8 @@ static GTY(()) tree trampoline_type;
 static tree
 get_trampoline_type (void)
 {
-  tree record, t;
   unsigned align, size;
+  tree t;
 
   if (trampoline_type)
     return trampoline_type;
@@ -437,12 +452,13 @@ get_trampoline_type (void)
   DECL_ALIGN (t) = align;
   DECL_USER_ALIGN (t) = 1;
 
-  record = make_node (RECORD_TYPE);
-  TYPE_NAME (record) = get_identifier ("__builtin_trampoline");
-  TYPE_FIELDS (record) = t;
-  layout_type (record);
+  trampoline_type = make_node (RECORD_TYPE);
+  TYPE_NAME (trampoline_type) = get_identifier ("__builtin_trampoline");
+  TYPE_FIELDS (trampoline_type) = t;
+  layout_type (trampoline_type);
+  DECL_CONTEXT (t) = trampoline_type;
 
-  return record;
+  return trampoline_type;
 }
 
 /* Given DECL, a nested function, find or create a field in the non-local
@@ -452,39 +468,29 @@ static tree
 lookup_tramp_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
-  tree field;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, insert);
-  if (!slot)
+  if (insert == NO_INSERT)
     {
-      gcc_assert (insert != INSERT);
-      return NULL;
+      slot = pointer_map_contains (info->var_map, decl);
+      return slot ? (tree) *slot : NULL_TREE;
     }
-  elt = *slot;
 
-  if (!elt && insert == INSERT)
+  slot = pointer_map_insert (info->var_map, decl);
+  if (!*slot)
     {
-      field = make_node (FIELD_DECL);
+      tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
       TREE_TYPE (field) = get_trampoline_type ();
       TREE_ADDRESSABLE (field) = 1;
 
       insert_field_into_struct (get_frame_type (info), field);
-
-      elt = xmalloc (sizeof (*elt));
-      elt->old = decl;
-      elt->new = field;
-      *slot = elt;
+      *slot = field;
 
       info->any_tramp_created = true;
     }
-  else
-    field = elt ? elt->new : NULL;
 
-  return field;
+  return (tree) *slot;
 } 
 
 /* Build or return the field within the non-local frame state that holds
@@ -529,127 +535,102 @@ get_nl_goto_field (struct nesting_info *info)
 
   return field;
 }
-\f
-/* Convenience routines to walk all statements of a gimple function.
-
-   For each statement, we invoke CALLBACK via walk_tree.  The passed
-   data is a walk_stmt_info structure.  Of note here is a TSI that
-   points to the current statement being walked.  The VAL_ONLY flag
-   that indicates whether the *TP being examined may be replaced 
-   with something that matches is_gimple_val (if true) or something
-   slightly more complicated (if false).  "Something" technically 
-   means the common subset of is_gimple_lvalue and is_gimple_rhs, 
-   but we never try to form anything more complicated than that, so
-   we don't bother checking.  */
-
-struct walk_stmt_info
-{
-  walk_tree_fn callback;
-  tree_stmt_iterator tsi;
-  struct nesting_info *info;
-  bool val_only;
-  bool is_lhs;
-  bool changed;
-};
 
-/* A subroutine of walk_function.  Iterate over all sub-statements of *TP.  */
+/* Invoke CALLBACK on all statements of GIMPLE sequence SEQ.  */
 
 static void
-walk_stmts (struct walk_stmt_info *wi, tree *tp)
+walk_body (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+          struct nesting_info *info, gimple_seq seq)
 {
-  tree t = *tp;
-  if (!t)
-    return;
-
-  switch (TREE_CODE (t))
-    {
-    case STATEMENT_LIST:
-      {
-       tree_stmt_iterator i;
-       for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
-         {
-           wi->tsi = i;
-           walk_stmts (wi, tsi_stmt_ptr (i));
-         }
-      }
-      break;
-
-    case COND_EXPR:
-      walk_tree (&COND_EXPR_COND (t), wi->callback, wi, NULL);
-      walk_stmts (wi, &COND_EXPR_THEN (t));
-      walk_stmts (wi, &COND_EXPR_ELSE (t));
-      break;
-    case CATCH_EXPR:
-      walk_stmts (wi, &CATCH_BODY (t));
-      break;
-    case EH_FILTER_EXPR:
-      walk_stmts (wi, &EH_FILTER_FAILURE (t));
-      break;
-    case TRY_CATCH_EXPR:
-    case TRY_FINALLY_EXPR:
-      walk_stmts (wi, &TREE_OPERAND (t, 0));
-      walk_stmts (wi, &TREE_OPERAND (t, 1));
-      break;
-    case BIND_EXPR:
-      walk_stmts (wi, &BIND_EXPR_BODY (t));
-      break;
-
-    case RETURN_EXPR:
-      walk_stmts (wi, &TREE_OPERAND (t, 0));
-      break;
+  struct walk_stmt_info wi;
 
-    case MODIFY_EXPR:
-      /* A formal temporary lhs may use a COMPONENT_REF rhs.  */
-      wi->val_only = !is_gimple_formal_tmp_var (TREE_OPERAND (t, 0));
-      walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL);
+  memset (&wi, 0, sizeof (wi));
+  wi.info = info;
+  wi.val_only = true;
+  walk_gimple_seq (seq, callback_stmt, callback_op, &wi);
+}
 
-      /* If the rhs is appropriate for a memory, we may use a
-        COMPONENT_REF on the lhs.  */
-      wi->val_only = !is_gimple_mem_rhs (TREE_OPERAND (t, 1));
-      wi->is_lhs = true;
-      walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
 
-      wi->val_only = true;
-      wi->is_lhs = false;
-      break;
+/* Invoke CALLBACK_STMT/CALLBACK_OP on all statements of INFO->CONTEXT.  */
 
-    default:
-      wi->val_only = true;
-      walk_tree (tp, wi->callback, wi, NULL);
-      break;
-    }
+static inline void
+walk_function (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+              struct nesting_info *info)
+{
+  walk_body (callback_stmt, callback_op, info, gimple_body (info->context));
 }
 
-/* Invoke CALLBACK on all statements of INFO->CONTEXT.  */
+/* Invoke CALLBACK on a GIMPLE_OMP_FOR's init, cond, incr and pre-body.  */
 
 static void
-walk_function (walk_tree_fn callback, struct nesting_info *info)
+walk_gimple_omp_for (gimple for_stmt,
+                    walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+                    struct nesting_info *info)
 {
   struct walk_stmt_info wi;
+  gimple_seq seq;
+  tree t;
+  size_t i;
 
+  walk_body (callback_stmt, callback_op, info, gimple_omp_for_pre_body (for_stmt));
+
+  seq = gimple_seq_alloc ();
   memset (&wi, 0, sizeof (wi));
-  wi.callback = callback;
   wi.info = info;
-  wi.val_only = true;
+  wi.gsi = gsi_last (seq);
+
+  for (i = 0; i < gimple_omp_for_collapse (for_stmt); i++)
+    {
+      wi.val_only = false;
+      walk_tree (gimple_omp_for_index_ptr (for_stmt, i), callback_op,
+                &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (gimple_omp_for_initial_ptr (for_stmt, i), callback_op,
+                &wi, NULL);
+
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (gimple_omp_for_final_ptr (for_stmt, i), callback_op,
+                &wi, NULL);
+
+      t = gimple_omp_for_incr (for_stmt, i);
+      gcc_assert (BINARY_CLASS_P (t));
+      wi.val_only = false;
+      walk_tree (&TREE_OPERAND (t, 0), callback_op, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&TREE_OPERAND (t, 1), callback_op, &wi, NULL);
+    }
 
-  walk_stmts (&wi, &DECL_SAVED_TREE (info->context));
+  if (gimple_seq_empty_p (seq))
+    gimple_seq_free (seq);
+  else
+    {
+      gimple_seq pre_body = gimple_omp_for_pre_body (for_stmt);
+      annotate_all_with_location (seq, gimple_location (for_stmt));
+      gimple_seq_add_seq (&pre_body, seq);
+      gimple_omp_for_set_pre_body (for_stmt, pre_body);
+    }
 }
 
 /* Similarly for ROOT and all functions nested underneath, depth first.  */
     
 static void
-walk_all_functions (walk_tree_fn callback, struct nesting_info *root)
+walk_all_functions (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
+                   struct nesting_info *root)
 {
   do
     {
       if (root->inner)
-       walk_all_functions (callback, root->inner);
-      walk_function (callback, root);
+       walk_all_functions (callback_stmt, callback_op, root->inner);
+      walk_function (callback_stmt, callback_op, root);
       root = root->next;
     }
   while (root);
 }
-\f
+
+
 /* We have to check for a fairly pathological case.  The operands of function
    nested function are to be interpreted in the context of the enclosing
    function.  So if any are variably-sized, they will get remapped when the
@@ -682,7 +663,7 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
   for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
     {
       for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg))
-       if (variably_modified_type_p (TREE_TYPE (arg), 0), orig_fndecl)
+       if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
          return true;
 
       if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl))
@@ -698,8 +679,10 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
 static struct nesting_info *
 create_nesting_tree (struct cgraph_node *cgn)
 {
-  struct nesting_info *info = 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)
@@ -723,7 +706,7 @@ create_nesting_tree (struct cgraph_node *cgn)
 
 static tree
 get_static_chain (struct nesting_info *info, tree target_context,
-                 tree_stmt_iterator *tsi)
+                 gimple_stmt_iterator *gsi)
 {
   struct nesting_info *i;
   tree x;
@@ -741,21 +724,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);
-         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 an expression referencing FIELD from TARGET_CONTEXT's non-local
    frame as seen from INFO->CONTEXT.  Insert any necessary computations
-   before TSI.  */
+   before GSI.  */
 
 static tree
 get_frame_field (struct nesting_info *info, tree target_context,
-                tree field, tree_stmt_iterator *tsi)
+                tree field, gimple_stmt_iterator *gsi)
 {
   struct nesting_info *i;
   tree x;
@@ -775,18 +759,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);
-         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 = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
   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 (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+  DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+  TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+  TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+  TREE_READONLY (new_decl) = TREE_READONLY (decl);
+  TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+  DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+  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
@@ -795,10 +859,10 @@ get_frame_field (struct nesting_info *info, tree target_context,
    indirections apply to decls for which use_pointer_in_frame is true.  */
 
 static tree
-convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
+convert_nonlocal_reference_op (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = 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;
@@ -813,43 +877,37 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
     case PARM_DECL:
       if (decl_function_context (t) != info->context)
        {
-         tree target_context = decl_function_context (t);
-         struct nesting_info *i;
          tree x;
          wi->changed = true;
 
-         for (i = info->outer; i->context != target_context; i = i->outer)
-           continue;
-         x = lookup_field_for_decl (i, t, INSERT);
-         x = get_frame_field (info, target_context, x, &wi->tsi);
-         if (use_pointer_in_frame (t))
+         x = get_nonlocal_debug_decl (info, t);
+         if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
            {
-             x = init_tmp_var (info, x, &wi->tsi);
-             x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+             tree target_context = decl_function_context (t);
+             struct nesting_info *i;
+             for (i = info->outer; i->context != target_context; i = i->outer)
+               continue;
+             x = lookup_field_for_decl (i, t, INSERT);
+             x = get_frame_field (info, target_context, x, &wi->gsi);
+             if (use_pointer_in_frame (t))
+               {
+                 x = init_tmp_var (info, x, &wi->gsi);
+                 x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+               }
            }
 
          if (wi->val_only)
            {
              if (wi->is_lhs)
-               x = save_tmp_var (info, x, &wi->tsi);
+               x = save_tmp_var (info, x, &wi->gsi);
              else
-               x = init_tmp_var (info, x, &wi->tsi);
+               x = init_tmp_var (info, x, &wi->gsi);
            }
 
          *tp = x;
        }
       break;
 
-    case GOTO_EXPR:
-      /* Don't walk non-local gotos for now.  */
-      if (TREE_CODE (GOTO_DESTINATION (t)) != LABEL_DECL)
-       {
-         *walk_subtrees = 1;
-         wi->val_only = true;
-         wi->is_lhs = false;
-       }
-      break;
-
     case LABEL_DECL:
       /* We're taking the address of a label from a parent function, but
         this is not itself a non-local goto.  Mark the label such that it
@@ -866,25 +924,26 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
        wi->val_only = false;
        wi->is_lhs = false;
        wi->changed = false;
-       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
+       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference_op, wi, 0);
        wi->val_only = true;
 
        if (wi->changed)
          {
            tree save_context;
 
-           /* If we changed anything, then TREE_INVARIANT is be wrong,
-              since we're no longer directly referencing a decl.  */
+           /* If we changed anything, we might no longer be directly
+              referencing a decl.  */
            save_context = current_function_decl;
            current_function_decl = info->context;
-           recompute_tree_invarant_for_addr_expr (t);
+           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)
-             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+             *tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
+                                     t, &wi->gsi);
          }
       }
       break;
@@ -903,28 +962,35 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
        {
          if (TREE_CODE (t) == COMPONENT_REF)
-           walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+           walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op, wi,
                       NULL);
          else if (TREE_CODE (t) == ARRAY_REF
                   || TREE_CODE (t) == ARRAY_RANGE_REF)
            {
-             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
-                        NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
-                        NULL);
-             walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi,
-                        NULL);
+             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference_op,
+                        wi, NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op,
+                        wi, NULL);
+             walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference_op,
+                        wi, NULL);
            }
          else if (TREE_CODE (t) == BIT_FIELD_REF)
            {
-             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
-                        NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
-                        NULL);
+             walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference_op,
+                        wi, NULL);
+             walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference_op,
+                        wi, NULL);
            }
        }
       wi->val_only = false;
-      walk_tree (tp, convert_nonlocal_reference, wi, NULL);
+      walk_tree (tp, convert_nonlocal_reference_op, wi, NULL);
+      break;
+
+    case VIEW_CONVERT_EXPR:
+      /* Just request to look at the subtrees, leaving val_only and lhs
+        untouched.  This might actually be for !val_only + lhs, in which
+        case we don't want to force a replacement by a temporary.  */
+      *walk_subtrees = 1;
       break;
 
     default:
@@ -940,17 +1006,347 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to VAR
+static tree convert_nonlocal_reference_stmt (gimple_stmt_iterator *, bool *,
+                                            struct walk_stmt_info *);
+
+/* Helper for convert_nonlocal_references, rewrite all references to VAR
+   and PARM_DECLs that belong to outer functions.  */
+
+static bool
+convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  bool need_chain = false, need_stmts = false;
+  tree clause, decl;
+  int dummy;
+  bitmap new_suppress;
+
+  new_suppress = BITMAP_GGC_ALLOC ();
+  bitmap_copy (new_suppress, info->suppress_expansion);
+
+  for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+    {
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_PRIVATE:
+       case OMP_CLAUSE_FIRSTPRIVATE:
+       case OMP_CLAUSE_COPYPRIVATE:
+       case OMP_CLAUSE_SHARED:
+       do_decl_clause:
+         decl = OMP_CLAUSE_DECL (clause);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+           break;
+         if (decl_function_context (decl) != info->context)
+           {
+             bitmap_set_bit (new_suppress, DECL_UID (decl));
+             OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
+             need_chain = true;
+           }
+         break;
+
+       case OMP_CLAUSE_SCHEDULE:
+         if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
+           break;
+         /* FALLTHRU */
+       case OMP_CLAUSE_IF:
+       case OMP_CLAUSE_NUM_THREADS:
+         wi->val_only = true;
+         wi->is_lhs = false;
+         convert_nonlocal_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
+                                        &dummy, wi);
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  info->suppress_expansion = new_suppress;
+
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           {
+             tree old_context
+               = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = info->context;
+             walk_body (convert_nonlocal_reference_stmt,
+                        convert_nonlocal_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+             walk_body (convert_nonlocal_reference_stmt,
+                        convert_nonlocal_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_nonlocal_reference_stmt,
+                    convert_nonlocal_reference_op, info,
+                    OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+         break;
+
+       default:
+         break;
+       }
+
+  return need_chain;
+}
+
+/* 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;
+
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      save_suppress = info->suppress_expansion;
+      if (convert_nonlocal_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+                                       wi))
+       {
+         tree c, decl;
+         decl = get_chain_decl (info);
+         c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
+         OMP_CLAUSE_DECL (c) = decl;
+         OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+         gimple_omp_taskreg_set_clauses (stmt, c);
+       }
+
+      save_local_var_chain = info->new_local_var_chain;
+      info->new_local_var_chain = NULL;
+
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+
+      if (info->new_local_var_chain)
+       declare_vars (info->new_local_var_chain,
+                     gimple_seq_first_stmt (gimple_omp_body (stmt)),
+                     false);
+      info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_FOR:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+      walk_gimple_omp_for (stmt, convert_nonlocal_reference_stmt,
+                          convert_nonlocal_reference_op, info);
+      walk_body (convert_nonlocal_reference_stmt,
+                convert_nonlocal_reference_op, info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTIONS:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+      walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+                info, gimple_omp_body (stmt));
+      break;
+
+    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;
+}
+
+
+/* A subroutine of convert_local_reference.  Create a local variable
+   in the parent function with DECL_VALUE_EXPR set to reference the
+   field in FRAME.  This is used both for debug info and in OpenMP
+   lowering.  */
+
+static tree
+get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
+{
+  tree x, new_decl;
+  void **slot;
+
+  slot = pointer_map_insert (info->var_map, decl);
+  if (*slot)
+    return (tree) *slot;
+
+  /* Make sure frame_decl gets created.  */
+  (void) get_frame_type (info);
+  x = info->frame_decl;
+  x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+
+  new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+  DECL_CONTEXT (new_decl) = info->context;
+  DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
+  DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
+  DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
+  TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
+  TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
+  TREE_READONLY (new_decl) = TREE_READONLY (decl);
+  TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
+  DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+  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.  */
 
+static bool convert_local_omp_clauses (tree *, struct walk_stmt_info *);
+
 static tree
-convert_local_reference (tree *tp, int *walk_subtrees, void *data)
+convert_local_reference_op (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = 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;
+  bool save_val_only;
 
+  *walk_subtrees = 0;
   switch (TREE_CODE (t))
     {
     case VAR_DECL:
@@ -974,14 +1370,16 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
            break;
          wi->changed = true;
 
-         x = get_frame_field (info, info->context, field, &wi->tsi);
+         x = get_local_debug_decl (info, t, field);
+         if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+           x = get_frame_field (info, info->context, field, &wi->gsi);
 
          if (wi->val_only)
            {
              if (wi->is_lhs)
-               x = save_tmp_var (info, x, &wi->tsi);
+               x = save_tmp_var (info, x, &wi->gsi);
              else
-               x = init_tmp_var (info, x, &wi->tsi);
+               x = init_tmp_var (info, x, &wi->gsi);
            }
 
          *tp = x;
@@ -989,34 +1387,32 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case ADDR_EXPR:
-      {
-       bool save_val_only = wi->val_only;
-
-       wi->val_only = false;
-       wi->is_lhs = false;
-       wi->changed = false;
-       walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
-       wi->val_only = save_val_only;
+      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;
 
-       /* If we converted anything ... */
-       if (wi->changed)
-         {
-           tree save_context;
+      /* If we converted anything ... */
+      if (wi->changed)
+       {
+         tree save_context;
 
-           /* 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;
            
-           save_context = current_function_decl;
-           current_function_decl = info->context;
-           recompute_tree_invarant_for_addr_expr (t);
-           current_function_decl = save_context;
-
-           /* If we are in a context where we only accept values, then
-              compute the address into a temporary.  */
-           if (save_val_only)
-             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
-         }
-      }
+         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:
@@ -1028,33 +1424,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.  */
+      save_val_only = wi->val_only;
       wi->val_only = true;
       wi->is_lhs = false;
       for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
        {
          if (TREE_CODE (t) == COMPONENT_REF)
-           walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+           walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
                       NULL);
          else if (TREE_CODE (t) == ARRAY_REF
                   || TREE_CODE (t) == ARRAY_RANGE_REF)
            {
-             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi,
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 3), convert_local_reference_op, wi,
                         NULL);
            }
          else if (TREE_CODE (t) == BIT_FIELD_REF)
            {
-             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 1), convert_local_reference_op, wi,
                         NULL);
-             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+             walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
                         NULL);
            }
        }
       wi->val_only = false;
-      walk_tree (tp, convert_local_reference, wi, NULL);
+      walk_tree (tp, convert_local_reference_op, wi, NULL);
+      wi->val_only = save_val_only;
+      break;
+
+    case VIEW_CONVERT_EXPR:
+      /* Just request to look at the subtrees, leaving val_only and lhs
+        untouched.  This might actually be for !val_only + lhs, in which
+        case we don't want to force a replacement by a temporary.  */
+      *walk_subtrees = 1;
       break;
 
     default:
@@ -1070,28 +1475,245 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that 
-   reference labels from outer functions.  The rewrite will be a 
+static tree convert_local_reference_stmt (gimple_stmt_iterator *, bool *,
+                                         struct walk_stmt_info *);
+
+/* Helper for convert_local_reference.  Convert all the references in
+   the chain of clauses at *PCLAUSES.  WI is as in convert_local_reference.  */
+
+static bool
+convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
+{
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  bool need_frame = false, need_stmts = false;
+  tree clause, decl;
+  int dummy;
+  bitmap new_suppress;
+
+  new_suppress = BITMAP_GGC_ALLOC ();
+  bitmap_copy (new_suppress, info->suppress_expansion);
+
+  for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+    {
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
+       case OMP_CLAUSE_PRIVATE:
+       case OMP_CLAUSE_FIRSTPRIVATE:
+       case OMP_CLAUSE_COPYPRIVATE:
+       case OMP_CLAUSE_SHARED:
+       do_decl_clause:
+         decl = OMP_CLAUSE_DECL (clause);
+         if (TREE_CODE (decl) == VAR_DECL
+             && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+           break;
+         if (decl_function_context (decl) == info->context
+             && !use_pointer_in_frame (decl))
+           {
+             tree field = lookup_field_for_decl (info, decl, NO_INSERT);
+             if (field)
+               {
+                 bitmap_set_bit (new_suppress, DECL_UID (decl));
+                 OMP_CLAUSE_DECL (clause)
+                   = get_local_debug_decl (info, decl, field);
+                 need_frame = true;
+               }
+           }
+         break;
+
+       case OMP_CLAUSE_SCHEDULE:
+         if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
+           break;
+         /* FALLTHRU */
+       case OMP_CLAUSE_IF:
+       case OMP_CLAUSE_NUM_THREADS:
+         wi->val_only = true;
+         wi->is_lhs = false;
+         convert_local_reference_op (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
+                                     wi);
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+       case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  info->suppress_expansion = new_suppress;
+
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+       {
+       case OMP_CLAUSE_REDUCTION:
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+           {
+             tree old_context
+               = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = info->context;
+             walk_body (convert_local_reference_stmt,
+                        convert_local_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+             walk_body (convert_local_reference_stmt,
+                        convert_local_reference_op, info,
+                        OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_local_reference_stmt,
+                    convert_local_reference_op, info,
+                    OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+         break;
+
+       default:
+         break;
+       }
+
+  return need_frame;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all references to VAR
+   and PARM_DECLs that were referenced by inner nested functions.
+   The rewrite will be a structure reference to the local frame variable.  */
+
+static tree
+convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                             struct walk_stmt_info *wi)
+{
+  struct nesting_info *info = (struct nesting_info *) wi->info;
+  tree save_local_var_chain;
+  bitmap save_suppress;
+  gimple stmt = gsi_stmt (*gsi);
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      save_suppress = info->suppress_expansion;
+      if (convert_local_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
+                                    wi))
+       {
+         tree c;
+         (void) get_frame_type (info);
+         c = build_omp_clause (OMP_CLAUSE_SHARED);
+         OMP_CLAUSE_DECL (c) = info->frame_decl;
+         OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+         gimple_omp_taskreg_set_clauses (stmt, c);
+       }
+
+      save_local_var_chain = info->new_local_var_chain;
+      info->new_local_var_chain = NULL;
+
+      walk_body (convert_local_reference_stmt, convert_local_reference_op, info,
+                gimple_omp_body (stmt));
+
+      if (info->new_local_var_chain)
+       declare_vars (info->new_local_var_chain,
+                     gimple_seq_first_stmt (gimple_omp_body (stmt)), false);
+      info->new_local_var_chain = save_local_var_chain;
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_FOR:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
+      walk_gimple_omp_for (stmt, convert_local_reference_stmt,
+                          convert_local_reference_op, info);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTIONS:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_sections_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SINGLE:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (gimple_omp_single_clauses_ptr (stmt), wi);
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      info->suppress_expansion = save_suppress;
+      break;
+
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+      walk_body (convert_local_reference_stmt, convert_local_reference_op,
+                info, gimple_omp_body (stmt));
+      break;
+
+    default:
+      /* For every other statement that we are not interested in
+        handling here, let the walker traverse the operands.  */
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
+  /* Indicate that we have handled all the operands ourselves.  */
+  *handled_ops_p = true;
+  return NULL_TREE;
+}
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all GIMPLE_GOTOs
+   that reference labels from outer functions.  The rewrite will be a
    call to __builtin_nonlocal_goto.  */
 
 static tree
-convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
+convert_nl_goto_reference (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                          struct walk_stmt_info *wi)
 {
-  struct walk_stmt_info *wi = 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;
+  gimple call;
+  gimple stmt = gsi_stmt (*gsi);
 
-  *walk_subtrees = 0;
-  if (TREE_CODE (t) != GOTO_EXPR)
-    return NULL_TREE;
-  label = GOTO_DESTINATION (t);
+  if (gimple_code (stmt) != GIMPLE_GOTO)
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
+  label = gimple_goto_dest (stmt);
   if (TREE_CODE (label) != LABEL_DECL)
-    return NULL_TREE;
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
+
   target_context = decl_function_context (label);
   if (target_context == info->context)
-    return NULL_TREE;
+    {
+      *handled_ops_p = false;
+      return NULL_TREE;
+    }
 
   for (i = info->outer; target_context != i->context; i = i->outer)
     continue;
@@ -1101,86 +1723,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
-     when we expand rtl.  */
-  new_label = create_artificial_label ();
-  DECL_NONLOCAL (new_label) = 1;
-
-  /* Enter this association into var_map so that we can insert the new
-     label into the IL during a second pass.  */
-  elt = xmalloc (sizeof (*elt));
-  elt->old = label;
-  elt->new = new_label;
-  slot = htab_find_slot (i->var_map, elt, INSERT);
-  *slot = elt;
+     when we expand rtl.  Enter this association into var_map so that we
+     can insert the new label into the IL during a second pass.  */
+  slot = pointer_map_insert (i->var_map, label);
+  if (*slot == NULL)
+    {
+      new_label = create_artificial_label ();
+      DECL_NONLOCAL (new_label) = 1;
+      *slot = new_label;
+    }
+  else
+    new_label = (tree) *slot;
   
   /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field).  */
   field = get_nl_goto_field (i);
-  x = get_frame_field (info, target_context, field, &wi->tsi);
+  x = get_frame_field (info, target_context, field, &wi->gsi);
   x = build_addr (x, target_context);
-  x = tsi_gimplify_val (info, x, &wi->tsi);
-  arg = tree_cons (NULL, x, NULL);
-  x = build_addr (new_label, target_context);
-  arg = tree_cons (NULL, x, arg);
-  x = implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO];
-  x = build_function_call_expr (x, arg);
-
-  SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
-  *tsi_stmt_ptr (wi->tsi) = x;
+  x = gsi_gimplify_val (info, x, &wi->gsi);
+  call = gimple_build_call (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2,
+                           build_addr (new_label, target_context), x);
+  gsi_replace (&wi->gsi, call, false);
 
+  /* We have handled all of STMT's operands, no need to keep going.  */
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all LABEL_EXPRs that 
+
+/* Called via walk_function+walk_tree, rewrite all GIMPLE_LABELs whose labels
    are referenced via nonlocal goto from a nested function.  The rewrite
    will involve installing a newly generated DECL_NONLOCAL label, and
-   (potentially) a branch around the rtl gunk that is assumed to be 
+   (potentially) a branch around the rtl gunk that is assumed to be
    attached to such a label.  */
 
 static tree
-convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
+convert_nl_goto_receiver (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                         struct walk_stmt_info *wi)
 {
-  struct walk_stmt_info *wi = 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.  */
-  tmp_tsi = wi->tsi;
-  tsi_prev (&tmp_tsi);
-  if (tsi_end_p (tmp_tsi) || block_may_fallthru (tsi_stmt (tmp_tsi)))
+  tmp_gsi = wi->gsi;
+  gsi_prev (&tmp_gsi);
+  if (gsi_end_p (tmp_gsi) || gimple_stmt_may_fallthru (gsi_stmt (tmp_gsi)))
     {
-      x = build1 (GOTO_EXPR, void_type_node, label);
-      tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
+      gimple stmt = gimple_build_goto (label);
+      gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
     }
-  x = build1 (LABEL_EXPR, void_type_node, new_label);
-  tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
 
+  new_label = (tree) *slot;
+  stmt = gimple_build_label (new_label);
+  gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all references to addresses
+
+/* Called via walk_function+walk_stmt, rewrite all references to addresses
    of nested functions that require the use of trampolines.  The rewrite
    will involve a reference a trampoline generated for the occasion.  */
 
 static tree
-convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
+convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = 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))
@@ -1206,6 +1836,10 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       if (DECL_NO_STATIC_CHAIN (decl))
        break;
 
+      /* If we don't want a trampoline, then don't build one.  */
+      if (TREE_NO_TRAMPOLINE (t))
+       break;
+
       /* Lookup the immediate parent of the callee, as that's where
         we need to insert the trampoline.  */
       for (i = info; i->context != target_context; i = i->outer)
@@ -1213,30 +1847,23 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       x = lookup_tramp_for_decl (i, decl, INSERT);
 
       /* Compute the address of the field holding the trampoline.  */
-      x = get_frame_field (info, target_context, x, &wi->tsi);
+      x = get_frame_field (info, target_context, x, &wi->gsi);
       x = build_addr (x, target_context);
-      x = tsi_gimplify_val (info, x, &wi->tsi);
-      arg = tree_cons (NULL, x, NULL);
+      x = gsi_gimplify_val (info, x, &wi->gsi);
 
       /* Do machine-specific ugliness.  Normally this will involve
         computing extra alignment, but it can really be anything.  */
-      x = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
-      x = build_function_call_expr (x, arg);
-      x = init_tmp_var (info, x, &wi->tsi);
+      builtin = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
+      call = gimple_build_call (builtin, 1, x);
+      x = init_tmp_var_with_call (info, &wi->gsi, call);
 
       /* Cast back to the proper function type.  */
       x = build1 (NOP_EXPR, TREE_TYPE (t), x);
-      x = init_tmp_var (info, x, &wi->tsi);
+      x = init_tmp_var (info, x, &wi->gsi);
 
       *tp = x;
       break;
 
-    case CALL_EXPR:
-      /* Only walk call arguments, lest we generate trampolines for
-        direct calls.  */
-      walk_tree (&TREE_OPERAND (t, 1), convert_tramp_reference, wi, NULL);
-      break;
-
     default:
       if (!IS_TYPE_OR_DECL_P (t))
        *walk_subtrees = 1;
@@ -1246,44 +1873,127 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Called via walk_function+walk_tree, rewrite all CALL_EXPRs that 
-   reference nested functions to make sure that the static chain is
-   set up properly for the call.  */
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all references
+   to addresses of nested functions that require the use of
+   trampolines.  The rewrite will involve a reference a trampoline
+   generated for the occasion.  */
 
 static tree
-convert_call_expr (tree *tp, int *walk_subtrees, void *data)
+convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                             struct walk_stmt_info *wi)
 {
-  struct walk_stmt_info *wi = data;
-  struct nesting_info *info = wi->info;
-  tree t = *tp, decl, target_context;
+  gimple stmt = gsi_stmt (*gsi);
 
-  *walk_subtrees = 0;
-  switch (TREE_CODE (t))
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_CALL:
+      {
+       /* Only walk call arguments, lest we generate trampolines for
+          direct calls.  */
+       unsigned long i, nargs = gimple_call_num_args (stmt);
+       for (i = 0; i < nargs; i++)
+         walk_tree (gimple_call_arg_ptr (stmt, i), convert_tramp_reference_op,
+                    wi, NULL);
+
+       *handled_ops_p = true;
+       return NULL_TREE;
+      }
+
+    default:
+      break;
+    }
+
+  *handled_ops_p = false;
+  return NULL_TREE;
+}
+
+
+
+/* Called via walk_function+walk_gimple_stmt, rewrite all GIMPLE_CALLs
+   that reference nested functions to make sure that the static chain
+   is set up properly for the call.  */
+
+static tree
+convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+                     struct walk_stmt_info *wi)
+{
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
+  tree decl, target_context;
+  char save_static_chain_added;
+  int i;
+  gimple stmt = gsi_stmt (*gsi);
+
+  switch (gimple_code (stmt))
     {
-    case CALL_EXPR:
-      decl = get_callee_fndecl (t);
+    case GIMPLE_CALL:
+      decl = gimple_call_fndecl (stmt);
       if (!decl)
        break;
       target_context = decl_function_context (decl);
       if (target_context && !DECL_NO_STATIC_CHAIN (decl))
-       TREE_OPERAND (t, 2)
-         = get_static_chain (info, target_context, &wi->tsi);
+       {
+         gimple_call_set_chain (stmt, get_static_chain (info, target_context,
+                                                        &wi->gsi));
+         info->static_chain_added |= (1 << (info->context != target_context));
+       }
       break;
 
-    case RETURN_EXPR:
-    case MODIFY_EXPR:
-    case WITH_SIZE_EXPR:
-      /* Only return modify and with_size_expr may contain calls.  */
-      *walk_subtrees = 1;
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      save_static_chain_added = info->static_chain_added;
+      info->static_chain_added = 0;
+      walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt));
+      for (i = 0; i < 2; i++)
+       {
+         tree c, decl;
+         if ((info->static_chain_added & (1 << i)) == 0)
+           continue;
+         decl = i ? get_chain_decl (info) : info->frame_decl;
+         /* Don't add CHAIN.* or FRAME.* twice.  */
+         for (c = gimple_omp_taskreg_clauses (stmt);
+              c;
+              c = OMP_CLAUSE_CHAIN (c))
+           if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+                || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
+               && OMP_CLAUSE_DECL (c) == decl)
+             break;
+         if (c == NULL)
+           {
+             c = build_omp_clause (i ? OMP_CLAUSE_FIRSTPRIVATE
+                                     : OMP_CLAUSE_SHARED);
+             OMP_CLAUSE_DECL (c) = decl;
+             OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+             gimple_omp_taskreg_set_clauses (stmt, c);
+           }
+       }
+      info->static_chain_added |= save_static_chain_added;
       break;
 
-    default:
+    case GIMPLE_OMP_FOR:
+      walk_body (convert_gimple_call, NULL, info,
+                gimple_omp_for_pre_body (stmt));
+      /* FALLTHRU */
+    case GIMPLE_OMP_SECTIONS:
+    case GIMPLE_OMP_SECTION:
+    case GIMPLE_OMP_SINGLE:
+    case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_ORDERED:
+    case GIMPLE_OMP_CRITICAL:
+      walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt));
       break;
+
+    default:
+      /* Keep looking for other operands.  */
+      *handled_ops_p = false;
+      return NULL_TREE;
     }
 
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
+
 /* Walk the nesting tree starting with ROOT, depth first.  Convert all
    trampolines and call expressions.  On the way back up, determine if
    a nested function actually uses its static chain; if not, remember that.  */
@@ -1296,8 +2006,9 @@ convert_all_function_calls (struct nesting_info *root)
       if (root->inner)
        convert_all_function_calls (root->inner);
 
-      walk_function (convert_tramp_reference, root);
-      walk_function (convert_call_expr, root);
+      walk_function (convert_tramp_reference_stmt, convert_tramp_reference_op,
+                    root);
+      walk_function (convert_gimple_call, NULL, root);
 
       /* If the function does not use a static chain, then remember that.  */
       if (root->outer && !root->chain_decl && !root->chain_field)
@@ -1310,6 +2021,142 @@ convert_all_function_calls (struct nesting_info *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
@@ -1318,10 +2165,12 @@ convert_all_function_calls (struct nesting_info *root)
 static void
 finalize_nesting_tree_1 (struct nesting_info *root)
 {
-  tree stmt_list = NULL;
+  gimple_seq stmt_list;
+  gimple stmt;
   tree context = root->context;
   struct function *sf;
-  struct cgraph_node *node;
+
+  stmt_list = NULL;
 
   /* If we created a non-local frame type or decl, we need to lay them
      out at this time.  */
@@ -1330,10 +2179,26 @@ finalize_nesting_tree_1 (struct nesting_info *root)
       /* 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);
       warn_padded = save_warn_padded;
       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 
@@ -1355,10 +2220,19 @@ finalize_nesting_tree_1 (struct nesting_info *root)
          else
            x = p;
 
-         y = build (COMPONENT_REF, TREE_TYPE (field),
-                    root->frame_decl, field, NULL_TREE);
-         x = build (MODIFY_EXPR, TREE_TYPE (field), y, x);
-         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);
+           }
        }
     }
 
@@ -1366,10 +2240,10 @@ finalize_nesting_tree_1 (struct nesting_info *root)
      from chain_decl.  */
   if (root->chain_field)
     {
-      tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
-                     root->frame_decl, root->chain_field, NULL_TREE);
-      x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
-      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.  */
@@ -1378,41 +2252,37 @@ finalize_nesting_tree_1 (struct nesting_info *root)
       struct nesting_info *i;
       for (i = root->inner; i ; i = i->next)
        {
-         tree arg, x, field;
+         tree arg1, arg2, arg3, x, field;
 
          field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
          if (!field)
            continue;
 
          if (DECL_NO_STATIC_CHAIN (i->context))
-           x = null_pointer_node;
+           arg3 = null_pointer_node;
          else
-           x = build_addr (root->frame_decl, context);
-         arg = tree_cons (NULL, x, NULL);
+           arg3 = build_addr (root->frame_decl, context);
 
-         x = build_addr (i->context, context);
-         arg = tree_cons (NULL, x, arg);
+         arg2 = build_addr (i->context, context);
 
-         x = build (COMPONENT_REF, TREE_TYPE (field),
-                    root->frame_decl, field, NULL_TREE);
-         x = build_addr (x, context);
-         arg = tree_cons (NULL, x, arg);
+         x = build3 (COMPONENT_REF, TREE_TYPE (field),
+                     root->frame_decl, field, NULL_TREE);
+         arg1 = build_addr (x, context);
 
          x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
-         x = build_function_call_expr (x, arg);
-
-         append_to_statement_list (x, &stmt_list);
+         stmt = gimple_build_call (x, 3, arg1, arg2, arg3);
+         gimple_seq_add_stmt (&stmt_list, stmt);
        }
     }
 
   /* If we created initialization statements, insert them.  */
   if (stmt_list)
     {
-      annotate_all_with_locus (&stmt_list,
-                              DECL_SOURCE_LOCATION (context));
-      append_to_statement_list (BIND_EXPR_BODY (DECL_SAVED_TREE (context)),
-                               &stmt_list);
-      BIND_EXPR_BODY (DECL_SAVED_TREE (context)) = stmt_list;
+      gimple bind;
+      annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context));
+      bind = gimple_seq_first_stmt (gimple_body (context));
+      gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind));
+      gimple_bind_set_body (bind, stmt_list);
     }
 
   /* If a chain_decl was created, then it needs to be registered with
@@ -1432,12 +2302,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)
-    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);
-  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.  */
@@ -1449,13 +2407,13 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 }
 
 static void
-finalize_nesting_tree (struct nesting_info *root)
+unnest_nesting_tree (struct nesting_info *root)
 {
   do
     {
       if (root->inner)
-       finalize_nesting_tree (root->inner);
-      finalize_nesting_tree_1 (root);
+       unnest_nesting_tree (root->inner);
+      unnest_nesting_tree_1 (root);
       root = root->next;
     }
   while (root);
@@ -1471,7 +2429,8 @@ free_nesting_tree (struct nesting_info *root)
     {
       if (root->inner)
        free_nesting_tree (root->inner);
-      htab_delete (root->var_map);
+      pointer_map_destroy (root->var_map);
+      pointer_map_destroy (root->field_map);
       next = root->next;
       free (root);
       root = next;
@@ -1485,22 +2444,29 @@ free_nesting_tree (struct nesting_info *root)
 void
 lower_nested_functions (tree fndecl)
 {
-  struct nesting_info *root;
   struct cgraph_node *cgn;
+  struct nesting_info *root;
 
   /* If there are no nested functions, there's nothing to do.  */
   cgn = cgraph_node (fndecl);
   if (!cgn->nested)
     return;
 
+  bitmap_obstack_initialize (&nesting_info_bitmap_obstack);
   root = create_nesting_tree (cgn);
-  walk_all_functions (convert_nonlocal_reference, root);
-  walk_all_functions (convert_local_reference, root);
-  walk_all_functions (convert_nl_goto_reference, root);
-  walk_all_functions (convert_nl_goto_receiver, root);
+  walk_all_functions (convert_nonlocal_reference_stmt,
+                      convert_nonlocal_reference_op,
+                     root);
+  walk_all_functions (convert_local_reference_stmt,
+                      convert_local_reference_op,
+                     root);
+  walk_all_functions (convert_nl_goto_reference, NULL, root);
+  walk_all_functions (convert_nl_goto_receiver, NULL, root);
   convert_all_function_calls (root);
   finalize_nesting_tree (root);
+  unnest_nesting_tree (root);
   free_nesting_tree (root);
+  bitmap_obstack_release (&nesting_info_bitmap_obstack);
 }
 
 #include "gt-tree-nested.h"