OSDN Git Service

* ggc.h (GGC_RESIZEVAR): New, reorder macros.
[pf3gnuchains/gcc-fork.git] / gcc / tree-nested.c
index ed4a1ae..2256050 100644 (file)
@@ -1,11 +1,11 @@
 /* Nested function decomposition for trees.
-   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    GCC is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful,
@@ -14,9 +14,8 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -34,6 +33,7 @@
 #include "cgraph.h"
 #include "expr.h"
 #include "langhooks.h"
+#include "pointer-set.h"
 #include "ggc.h"
 
 
    been written as independent functions without change.  */
 
 
-struct var_map_elt GTY(())
-{
-  tree old;
-  tree new;
-};
-
-struct nesting_info GTY ((chain_next ("%h.next")))
+struct nesting_info
 {
   struct nesting_info *outer;
   struct nesting_info *inner;
   struct nesting_info *next;
   
-  htab_t GTY ((param_is (struct var_map_elt))) field_map;
-  htab_t GTY ((param_is (struct var_map_elt))) var_map;
+  struct pointer_map_t *field_map;
+  struct pointer_map_t *var_map;
   bitmap suppress_expansion;
 
   tree context;
@@ -108,22 +102,9 @@ struct nesting_info GTY ((chain_next ("%h.next")))
 };
 
 
-/* Hashing and equality functions for nesting_info->var_map.  */
-
-static hashval_t
-var_map_hash (const void *x)
-{
-  const struct var_map_elt *a = (const struct var_map_elt *) x;
-  return htab_hash_pointer (a->old);
-}
+/* Obstack used for the bitmaps in the struct above.  */
+static struct bitmap_obstack nesting_info_bitmap_obstack;
 
-static int
-var_map_eq (const void *x, const void *y)
-{
-  const struct var_map_elt *a = (const struct var_map_elt *) x;
-  const struct var_map_elt *b = (const struct var_map_elt *) y;
-  return a->old == b->old;
-}
 
 /* We're working in so many different function contexts simultaneously,
    that create_tmp_var is dangerous.  Prevent mishap.  */
@@ -148,8 +129,9 @@ 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)
-    DECL_COMPLEX_GIMPLE_REG_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;
 
@@ -174,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
@@ -182,7 +164,7 @@ 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;
 }
 
@@ -201,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
@@ -267,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->field_map, &dummy, insert);
-  if (!slot)
+  if (insert == NO_INSERT)
     {
-      gcc_assert (insert != INSERT);
-      return NULL;
+      slot = pointer_map_contains (info->field_map, decl);
+      return slot ? (tree) *slot : NULL_TREE;
     }
-  elt = (struct var_map_elt *) *slot;
 
-  if (!elt && insert == INSERT)
+  slot = pointer_map_insert (info->field_map, decl);
+  if (!*slot)
     {
-      field = make_node (FIELD_DECL);
+      tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
 
       if (use_pointer_in_frame (decl))
@@ -303,19 +285,13 @@ lookup_field_for_decl (struct nesting_info *info, tree decl,
        }
 
       insert_field_into_struct (get_frame_type (info), field);
-  
-      elt = GGC_NEW (struct var_map_elt);
-      elt->old = decl;
-      elt->new = field;
-      *slot = elt;
+      *slot = field;
 
       if (TREE_CODE (decl) == PARM_DECL)
        info->any_parm_remapped = true;
     }
-  else
-    field = elt ? elt->new : NULL;
 
-  return field;
+  return (tree) *slot;
 }
 
 /* Build or return the variable that holds the static chain within
@@ -388,7 +364,7 @@ init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
   tree t, stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (t), t, exp);
+  stmt = build_gimple_modify_stmt (t, exp);
   SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
   tsi_link_before (tsi, stmt, TSI_SAME_STMT);
 
@@ -416,7 +392,7 @@ save_tmp_var (struct nesting_info *info, tree exp,
   tree t, stmt;
 
   t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
-  stmt = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (t), exp, t);
+  stmt = build_gimple_modify_stmt (exp, t);
   SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
   tsi_link_after (tsi, stmt, TSI_SAME_STMT);
 
@@ -430,8 +406,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;
@@ -453,12 +429,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
@@ -468,39 +445,29 @@ static tree
 lookup_tramp_for_decl (struct nesting_info *info, tree decl,
                       enum insert_option insert)
 {
-  struct var_map_elt *elt, dummy;
   void **slot;
-  tree field;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, insert);
-  if (!slot)
+  if (insert == NO_INSERT)
     {
-      gcc_assert (insert != INSERT);
-      return NULL;
+      slot = pointer_map_contains (info->var_map, decl);
+      return slot ? (tree) *slot : NULL_TREE;
     }
-  elt = (struct var_map_elt *) *slot;
 
-  if (!elt && insert == INSERT)
+  slot = pointer_map_insert (info->var_map, decl);
+  if (!*slot)
     {
-      field = make_node (FIELD_DECL);
+      tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
       TREE_TYPE (field) = get_trampoline_type ();
       TREE_ADDRESSABLE (field) = 1;
 
       insert_field_into_struct (get_frame_type (info), field);
-
-      elt = GGC_NEW (struct var_map_elt);
-      elt->old = decl;
-      elt->new = field;
-      *slot = elt;
+      *slot = field;
 
       info->any_tramp_created = true;
     }
-  else
-    field = elt ? elt->new : NULL;
 
-  return field;
+  return (tree) *slot;
 } 
 
 /* Build or return the field within the non-local frame state that holds
@@ -546,6 +513,47 @@ get_nl_goto_field (struct nesting_info *info)
   return field;
 }
 \f
+/* Helper function for walk_stmts.  Walk output operands of an ASM_EXPR.  */
+
+static void
+walk_asm_expr (struct walk_stmt_info *wi, tree stmt)
+{
+  int noutputs = list_length (ASM_OUTPUTS (stmt));
+  const char **oconstraints
+    = (const char **) alloca ((noutputs) * sizeof (const char *));
+  int i;
+  tree link;
+  const char *constraint;
+  bool allows_mem, allows_reg, is_inout;
+
+  wi->is_lhs = true;
+  for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
+    {
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+      oconstraints[i] = constraint;
+      parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
+                              &allows_reg, &is_inout);
+
+      wi->val_only = (allows_reg || !allows_mem);
+      walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+    }
+
+  for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
+    {
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+      parse_input_constraint (&constraint, 0, 0, noutputs, 0,
+                             oconstraints, &allows_mem, &allows_reg);
+
+      wi->val_only = (allows_reg || !allows_mem);
+      /* Although input "m" is not really a LHS, we need a lvalue.  */
+      wi->is_lhs = !wi->val_only;
+      walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+    }
+
+  wi->is_lhs = false;
+  wi->val_only = true;
+}
+
 /* Iterate over all sub-statements of *TP calling walk_tree with
    WI->CALLBACK for every sub-expression in each statement found.  */
 
@@ -628,6 +636,10 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp)
       wi->is_lhs = false;
       break;
 
+    case ASM_EXPR:
+      walk_asm_expr (wi, *tp);
+      break;
+
     default:
       wi->val_only = true;
       walk_tree (tp, wi->callback, wi, NULL);
@@ -658,6 +670,63 @@ walk_function (walk_tree_fn callback, struct nesting_info *info)
   walk_body (callback, info, &DECL_SAVED_TREE (info->context));
 }
 
+/* Invoke CALLBACK on OMP_FOR init, cond, incr and pre-body.  */
+
+static void
+walk_omp_for (walk_tree_fn callback, struct nesting_info *info, tree for_stmt)
+{
+  struct walk_stmt_info wi;
+  tree t, list = NULL, empty;
+  int i;
+
+  walk_body (callback, info, &OMP_FOR_PRE_BODY (for_stmt));
+
+  empty = build_empty_stmt ();
+  append_to_statement_list_force (empty, &list);
+  memset (&wi, 0, sizeof (wi));
+  wi.callback = callback;
+  wi.info = info;
+  wi.tsi = tsi_last (list);
+
+  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
+    {
+      t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
+      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+      wi.val_only = false;
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 1), callback, &wi, NULL);
+
+      t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
+      gcc_assert (COMPARISON_CLASS_P (t));
+      SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+      wi.val_only = false;
+      walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+
+      t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+      wi.val_only = false;
+      walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
+      t = GIMPLE_STMT_OPERAND (t, 1);
+      gcc_assert (BINARY_CLASS_P (t));
+      wi.val_only = false;
+      walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
+      wi.val_only = true;
+      wi.is_lhs = false;
+      walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+    }
+
+  /* Remove empty statement added above from the end of statement list.  */
+  tsi_delink (&wi.tsi);
+  append_to_statement_list (list, &OMP_FOR_PRE_BODY (for_stmt));
+}
+
 /* Similarly for ROOT and all functions nested underneath, depth first.  */
     
 static void
@@ -705,7 +774,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))
@@ -721,10 +790,10 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
 static struct nesting_info *
 create_nesting_tree (struct cgraph_node *cgn)
 {
-  struct nesting_info *info = GGC_CNEW (struct nesting_info);
-  info->field_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
-  info->var_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
-  info->suppress_expansion = BITMAP_GGC_ALLOC ();
+  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)
@@ -819,18 +888,15 @@ get_frame_field (struct nesting_info *info, tree target_context,
 static tree
 get_nonlocal_debug_decl (struct nesting_info *info, tree decl)
 {
-  struct var_map_elt *elt, dummy;
   tree target_context;
   struct nesting_info *i;
   tree x, field, new_decl;
   void **slot;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, INSERT);
-  elt = *slot;
+  slot = pointer_map_insert (info->var_map, decl);
 
-  if (elt)
-    return elt->new;
+  if (*slot)
+    return (tree) *slot;
 
   target_context = decl_function_context (decl);
 
@@ -874,11 +940,7 @@ get_nonlocal_debug_decl (struct nesting_info *info, tree decl)
   SET_DECL_VALUE_EXPR (new_decl, x);
   DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
 
-  elt = ggc_alloc (sizeof (*elt));
-  elt->old = decl;
-  elt->new = new_decl;
-  *slot = elt;
-
+  *slot = new_decl;
   TREE_CHAIN (new_decl) = info->debug_var_chain;
   info->debug_var_chain = new_decl;
 
@@ -899,7 +961,7 @@ static tree
 convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp;
   tree save_local_var_chain;
   bitmap save_suppress;
@@ -980,8 +1042,8 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
          {
            tree save_context;
 
-           /* If we changed anything, then TREE_INVARIANT is be wrong,
-              since we're no longer directly referencing a decl.  */
+           /* If we changed anything, we might no longer be directly
+              referencing a decl.  */
            save_context = current_function_decl;
            current_function_decl = info->context;
            recompute_tree_invariant_for_addr_expr (t);
@@ -991,7 +1053,8 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
               where we only accept variables (and min_invariant, presumably),
               then compute the address into a temporary.  */
            if (save_val_only)
-             *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+             *tp = tsi_gimplify_val ((struct nesting_info *) wi->info,
+                                     t, &wi->tsi);
          }
       }
       break;
@@ -1034,30 +1097,45 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       walk_tree (tp, convert_nonlocal_reference, 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;
+
     case OMP_PARALLEL:
+    case OMP_TASK:
       save_suppress = info->suppress_expansion;
-      if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
+      if (convert_nonlocal_omp_clauses (&OMP_TASKREG_CLAUSES (t), wi))
        {
          tree c, decl;
          decl = get_chain_decl (info);
          c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
          OMP_CLAUSE_DECL (c) = decl;
-         OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
-         OMP_PARALLEL_CLAUSES (t) = c;
+         OMP_CLAUSE_CHAIN (c) = OMP_TASKREG_CLAUSES (t);
+         OMP_TASKREG_CLAUSES (t) = c;
        }
 
       save_local_var_chain = info->new_local_var_chain;
       info->new_local_var_chain = NULL;
 
-      walk_body (convert_nonlocal_reference, info, &OMP_PARALLEL_BODY (t));
+      walk_body (convert_nonlocal_reference, info, &OMP_TASKREG_BODY (t));
 
       if (info->new_local_var_chain)
-       declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
+       declare_vars (info->new_local_var_chain, OMP_TASKREG_BODY (t), false);
       info->new_local_var_chain = save_local_var_chain;
       info->suppress_expansion = save_suppress;
       break;
 
     case OMP_FOR:
+      save_suppress = info->suppress_expansion;
+      convert_nonlocal_omp_clauses (&OMP_FOR_CLAUSES (t), wi);
+      walk_omp_for (convert_nonlocal_reference, info, t);
+      walk_body (convert_nonlocal_reference, info, &OMP_FOR_BODY (t));
+      info->suppress_expansion = save_suppress;
+      break;
+
     case OMP_SECTIONS:
     case OMP_SINGLE:
       save_suppress = info->suppress_expansion;
@@ -1088,8 +1166,8 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
 static bool
 convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
-  struct nesting_info *info = wi->info;
-  bool need_chain = false;
+  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;
@@ -1101,13 +1179,25 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
     {
       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_STMT (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
        case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_FIRSTPRIVATE:
-       case OMP_CLAUSE_LASTPRIVATE:
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_COPYPRIVATE:
        case OMP_CLAUSE_SHARED:
+       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));
@@ -1132,6 +1222,8 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
        case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
          break;
 
        default:
@@ -1141,6 +1233,35 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 
   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, info,
+                        &OMP_CLAUSE_REDUCTION_INIT (clause));
+             walk_body (convert_nonlocal_reference, info,
+                        &OMP_CLAUSE_REDUCTION_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_nonlocal_reference, info,
+                    &OMP_CLAUSE_LASTPRIVATE_STMT (clause));
+         break;
+
+       default:
+         break;
+       }
+
   return need_chain;
 }
 
@@ -1152,16 +1273,12 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 static tree
 get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
 {
-  struct var_map_elt *elt, dummy;
   tree x, new_decl;
   void **slot;
 
-  dummy.old = decl;
-  slot = htab_find_slot (info->var_map, &dummy, INSERT);
-  elt = *slot;
-
-  if (elt)
-    return elt->new;
+  slot = pointer_map_insert (info->var_map, decl);
+  if (*slot)
+    return (tree) *slot;
 
   /* Make sure frame_decl gets created.  */
   (void) get_frame_type (info);
@@ -1181,11 +1298,7 @@ get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
 
   SET_DECL_VALUE_EXPR (new_decl, x);
   DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
-
-  elt = ggc_alloc (sizeof (*elt));
-  elt->old = decl;
-  elt->new = new_decl;
-  *slot = elt;
+  *slot = new_decl;
 
   TREE_CHAIN (new_decl) = info->debug_var_chain;
   info->debug_var_chain = new_decl;
@@ -1206,7 +1319,7 @@ static tree
 convert_local_reference (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp, field, x;
   bool save_val_only;
   tree save_local_var_chain;
@@ -1276,7 +1389,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
          /* If we are in a context where we only accept values, then
             compute the address into a temporary.  */
          if (save_val_only)
-           *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+           *tp = tsi_gimplify_val ((struct nesting_info *)wi->info, t, &wi->tsi);
        }
       break;
 
@@ -1320,30 +1433,45 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       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;
+
     case OMP_PARALLEL:
+    case OMP_TASK:
       save_suppress = info->suppress_expansion;
-      if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
+      if (convert_local_omp_clauses (&OMP_TASKREG_CLAUSES (t), wi))
        {
          tree c;
          (void) get_frame_type (info);
          c = build_omp_clause (OMP_CLAUSE_SHARED);
          OMP_CLAUSE_DECL (c) = info->frame_decl;
-         OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
-         OMP_PARALLEL_CLAUSES (t) = c;
+         OMP_CLAUSE_CHAIN (c) = OMP_TASKREG_CLAUSES (t);
+         OMP_TASKREG_CLAUSES (t) = c;
        }
 
       save_local_var_chain = info->new_local_var_chain;
       info->new_local_var_chain = NULL;
 
-      walk_body (convert_local_reference, info, &OMP_PARALLEL_BODY (t));
+      walk_body (convert_local_reference, info, &OMP_TASKREG_BODY (t));
 
       if (info->new_local_var_chain)
-       declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
+       declare_vars (info->new_local_var_chain, OMP_TASKREG_BODY (t), false);
       info->new_local_var_chain = save_local_var_chain;
       info->suppress_expansion = save_suppress;
       break;
 
     case OMP_FOR:
+      save_suppress = info->suppress_expansion;
+      convert_local_omp_clauses (&OMP_FOR_CLAUSES (t), wi);
+      walk_omp_for (convert_local_reference, info, t);
+      walk_body (convert_local_reference, info, &OMP_FOR_BODY (t));
+      info->suppress_expansion = save_suppress;
+      break;
+
     case OMP_SECTIONS:
     case OMP_SINGLE:
       save_suppress = info->suppress_expansion;
@@ -1374,8 +1502,8 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
 static bool
 convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
-  struct nesting_info *info = wi->info;
-  bool need_frame = false;
+  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;
@@ -1387,13 +1515,25 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
     {
       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_STMT (clause))
+           need_stmts = true;
+         goto do_decl_clause;
+
        case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_FIRSTPRIVATE:
-       case OMP_CLAUSE_LASTPRIVATE:
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_COPYPRIVATE:
        case OMP_CLAUSE_SHARED:
+       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))
            {
@@ -1423,6 +1563,8 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
        case OMP_CLAUSE_COPYIN:
+       case OMP_CLAUSE_COLLAPSE:
+       case OMP_CLAUSE_UNTIED:
          break;
 
        default:
@@ -1432,6 +1574,35 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 
   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, info,
+                        &OMP_CLAUSE_REDUCTION_INIT (clause));
+             walk_body (convert_local_reference, info,
+                        &OMP_CLAUSE_REDUCTION_MERGE (clause));
+             DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+               = old_context;
+           }
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         walk_body (convert_local_reference, info,
+                    &OMP_CLAUSE_LASTPRIVATE_STMT (clause));
+         break;
+
+       default:
+         break;
+       }
+
   return need_frame;
 }
 
@@ -1443,9 +1614,8 @@ static tree
 convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info, *i;
-  tree t = *tp, label, new_label, target_context, x, arg, field;
-  struct var_map_elt *elt, dummy;
+  struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
+  tree t = *tp, label, new_label, target_context, x, field;
   void **slot;
 
   *walk_subtrees = 0;
@@ -1468,32 +1638,23 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
      (hairy target-specific) non-local goto receiver code to be generated
      when we expand rtl.  Enter this association into var_map so that we
      can insert the new label into the IL during a second pass.  */
-  dummy.old = label;
-  slot = htab_find_slot (i->var_map, &dummy, INSERT);
-  elt = (struct var_map_elt *) *slot;
-  if (elt == NULL)
+  slot = pointer_map_insert (i->var_map, label);
+  if (*slot == NULL)
     {
       new_label = create_artificial_label ();
       DECL_NONLOCAL (new_label) = 1;
-
-      elt = GGC_NEW (struct var_map_elt); 
-      elt->old = label;
-      elt->new = new_label;
-      *slot = elt;
+      *slot = new_label;
     }
   else
-    new_label = elt->new;
+    new_label = (tree) *slot;
   
   /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field).  */
   field = get_nl_goto_field (i);
   x = get_frame_field (info, target_context, field, &wi->tsi);
   x = build_addr (x, target_context);
   x = tsi_gimplify_val (info, x, &wi->tsi);
-  arg = tree_cons (NULL, x, NULL);
-  x = build_addr (new_label, target_context);
-  arg = tree_cons (NULL, x, arg);
-  x = implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO];
-  x = build_function_call_expr (x, arg);
+  x = build_call_expr (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2,
+                      build_addr (new_label, target_context), x);
 
   SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
   *tsi_stmt_ptr (wi->tsi) = x;
@@ -1511,21 +1672,19 @@ static tree
 convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp, label, new_label, x;
-  struct var_map_elt *elt, dummy;
   tree_stmt_iterator tmp_tsi;
+  void **slot;
 
   *walk_subtrees = 0;
   if (TREE_CODE (t) != LABEL_EXPR)
     return NULL_TREE;
   label = LABEL_EXPR_LABEL (t);
 
-  dummy.old = label;
-  elt = (struct var_map_elt *) htab_find (info->var_map, &dummy);
-  if (!elt)
+  slot = pointer_map_contains (info->var_map, label);
+  if (!slot)
     return NULL_TREE;
-  new_label = elt->new;
 
   /* If there's any possibility that the previous statement falls through,
      then we must branch around the new non-local label.  */
@@ -1536,6 +1695,8 @@ convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
       x = build1 (GOTO_EXPR, void_type_node, label);
       tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
     }
+
+  new_label = (tree) *slot;
   x = build1 (LABEL_EXPR, void_type_node, new_label);
   tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
 
@@ -1550,8 +1711,8 @@ static tree
 convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info, *i;
-  tree t = *tp, decl, target_context, x, arg;
+  struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
+  tree t = *tp, decl, target_context, x;
 
   *walk_subtrees = 0;
   switch (TREE_CODE (t))
@@ -1577,6 +1738,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)
@@ -1587,12 +1752,11 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
       x = get_frame_field (info, target_context, x, &wi->tsi);
       x = build_addr (x, target_context);
       x = tsi_gimplify_val (info, x, &wi->tsi);
-      arg = tree_cons (NULL, x, NULL);
 
       /* Do machine-specific ugliness.  Normally this will involve
         computing extra alignment, but it can really be anything.  */
-      x = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
-      x = build_function_call_expr (x, arg);
+      x = build_call_expr (implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE],
+                          1, x);
       x = init_tmp_var (info, x, &wi->tsi);
 
       /* Cast back to the proper function type.  */
@@ -1605,7 +1769,12 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
     case CALL_EXPR:
       /* Only walk call arguments, lest we generate trampolines for
         direct calls.  */
-      walk_tree (&TREE_OPERAND (t, 1), convert_tramp_reference, wi, NULL);
+      {
+       int nargs = call_expr_nargs (t);
+       int i;
+       for (i = 0; i < nargs; i++)
+         walk_tree (&CALL_EXPR_ARG (t, i), convert_tramp_reference, wi, NULL);
+      }
       break;
 
     default:
@@ -1625,7 +1794,7 @@ static tree
 convert_call_expr (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nesting_info *info = wi->info;
+  struct nesting_info *const info = (struct nesting_info *) wi->info;
   tree t = *tp, decl, target_context;
   char save_static_chain_added;
   int i;
@@ -1640,7 +1809,7 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
       target_context = decl_function_context (decl);
       if (target_context && !DECL_NO_STATIC_CHAIN (decl))
        {
-         TREE_OPERAND (t, 2)
+         CALL_EXPR_STATIC_CHAIN (t)
            = get_static_chain (info, target_context, &wi->tsi);
          info->static_chain_added
            |= (1 << (info->context != target_context));
@@ -1655,9 +1824,10 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case OMP_PARALLEL:
+    case OMP_TASK:
       save_static_chain_added = info->static_chain_added;
       info->static_chain_added = 0;
-      walk_body (convert_call_expr, info, &OMP_PARALLEL_BODY (t));
+      walk_body (convert_call_expr, info, &OMP_TASKREG_BODY (t));
       for (i = 0; i < 2; i++)
        {
          tree c, decl;
@@ -1665,23 +1835,26 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data)
            continue;
          decl = i ? get_chain_decl (info) : info->frame_decl;
          /* Don't add CHAIN.* or FRAME.* twice.  */
-         for (c = OMP_PARALLEL_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
+         for (c = OMP_TASKREG_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
            if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
                 || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
                && OMP_CLAUSE_DECL (c) == decl)
              break;
          if (c == NULL)
            {
-             c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
+             c = build_omp_clause (i ? OMP_CLAUSE_FIRSTPRIVATE
+                                     : OMP_CLAUSE_SHARED);
              OMP_CLAUSE_DECL (c) = decl;
-             OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
-             OMP_PARALLEL_CLAUSES (t) = c;
+             OMP_CLAUSE_CHAIN (c) = OMP_TASKREG_CLAUSES (t);
+             OMP_TASKREG_CLAUSES (t) = c;
            }
        }
       info->static_chain_added |= save_static_chain_added;
       break;
 
     case OMP_FOR:
+      walk_body (convert_call_expr, info, &OMP_FOR_PRE_BODY (t));
+      /* FALLTHRU */
     case OMP_SECTIONS:
     case OMP_SECTION:
     case OMP_SINGLE:
@@ -1770,7 +1943,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 
          y = build3 (COMPONENT_REF, TREE_TYPE (field),
                      root->frame_decl, field, NULL_TREE);
-         x = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (field), y, x);
+         x = build_gimple_modify_stmt (y, x);
          append_to_statement_list (x, &stmt_list);
        }
     }
@@ -1781,7 +1954,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
     {
       tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field),
                       root->frame_decl, root->chain_field, NULL_TREE);
-      x = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (x), x, get_chain_decl (root));
+      x = build_gimple_modify_stmt (x, get_chain_decl (root));
       append_to_statement_list (x, &stmt_list);
     }
 
@@ -1791,29 +1964,25 @@ finalize_nesting_tree_1 (struct nesting_info *root)
       struct nesting_info *i;
       for (i = root->inner; i ; i = i->next)
        {
-         tree arg, x, field;
+         tree arg1, arg2, arg3, x, field;
 
          field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
          if (!field)
            continue;
 
          if (DECL_NO_STATIC_CHAIN (i->context))
-           x = null_pointer_node;
+           arg3 = null_pointer_node;
          else
-           x = build_addr (root->frame_decl, context);
-         arg = tree_cons (NULL, x, NULL);
+           arg3 = build_addr (root->frame_decl, context);
 
-         x = build_addr (i->context, context);
-         arg = tree_cons (NULL, x, arg);
+         arg2 = build_addr (i->context, context);
 
          x = build3 (COMPONENT_REF, TREE_TYPE (field),
                      root->frame_decl, field, NULL_TREE);
-         x = build_addr (x, context);
-         arg = tree_cons (NULL, x, arg);
+         arg1 = build_addr (x, context);
 
          x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
-         x = build_function_call_expr (x, arg);
-
+         x = build_call_expr (x, 3, arg1, arg2, arg3);
          append_to_statement_list (x, &stmt_list);
        }
     }
@@ -1907,16 +2076,15 @@ free_nesting_tree (struct nesting_info *root)
     {
       if (root->inner)
        free_nesting_tree (root->inner);
-      htab_delete (root->var_map);
+      pointer_map_destroy (root->var_map);
+      pointer_map_destroy (root->field_map);
       next = root->next;
-      ggc_free (root);
+      free (root);
       root = next;
     }
   while (root);
 }
 
-static GTY(()) struct nesting_info *root;
-
 /* Main entry point for this pass.  Process FNDECL and all of its nested
    subroutines and turn them into something less tightly bound.  */
 
@@ -1924,12 +2092,14 @@ void
 lower_nested_functions (tree fndecl)
 {
   struct cgraph_node *cgn;
+  struct nesting_info *root;
 
   /* If there are no nested functions, there's nothing to do.  */
   cgn = cgraph_node (fndecl);
   if (!cgn->nested)
     return;
 
+  bitmap_obstack_initialize (&nesting_info_bitmap_obstack);
   root = create_nesting_tree (cgn);
   walk_all_functions (convert_nonlocal_reference, root);
   walk_all_functions (convert_local_reference, root);
@@ -1939,7 +2109,7 @@ lower_nested_functions (tree fndecl)
   finalize_nesting_tree (root);
   unnest_nesting_tree (root);
   free_nesting_tree (root);
-  root = NULL;
+  bitmap_obstack_release (&nesting_info_bitmap_obstack);
 }
 
 #include "gt-tree-nested.h"