/* Nested function decomposition for trees.
- Copyright (C) 2004, 2005, 2006, 2007 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,
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"
/* 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
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
if (insert == NO_INSERT)
{
slot = pointer_map_contains (info->field_map, decl);
- return slot ? *slot : NULL;
+ return slot ? (tree) *slot : NULL_TREE;
}
slot = pointer_map_insert (info->field_map, decl);
info->any_parm_remapped = true;
}
- return *slot;
+ return (tree) *slot;
}
/* Build or return the variable that holds the static chain within
static tree
get_trampoline_type (void)
{
- tree record, t;
unsigned align, size;
+ tree t;
if (trampoline_type)
return trampoline_type;
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
if (insert == NO_INSERT)
{
slot = pointer_map_contains (info->var_map, decl);
- return slot ? *slot : NULL;
+ return slot ? (tree) *slot : NULL_TREE;
}
slot = pointer_map_insert (info->var_map, decl);
info->any_tramp_created = true;
}
- return *slot;
+ return (tree) *slot;
}
/* Build or return the field within the non-local frame state that holds
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
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))
slot = pointer_map_insert (info->var_map, decl);
if (*slot)
- return *slot;
+ return (tree) *slot;
target_context = decl_function_context (decl);
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;
{
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);
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;
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;
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;
{
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));
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_COPYIN:
+ case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_UNTIED:
break;
default:
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;
}
slot = pointer_map_insert (info->var_map, decl);
if (*slot)
- return *slot;
+ return (tree) *slot;
/* Make sure frame_decl gets created. */
(void) get_frame_type (info);
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;
/* 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;
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;
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;
{
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))
{
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_COPYIN:
+ case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_UNTIED:
break;
default:
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;
}
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;
+ struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
tree t = *tp, label, new_label, target_context, x, field;
void **slot;
*slot = new_label;
}
else
- new_label = *slot;
+ new_label = (tree) *slot;
/* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field). */
field = get_nl_goto_field (i);
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;
tree_stmt_iterator tmp_tsi;
void **slot;
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;
+ struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
tree t = *tp, decl, target_context, x;
*walk_subtrees = 0;
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)
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;
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;
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: