/* Nested function decomposition for GIMPLE.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
#include "tree.h"
+#include "gimple.h"
#include "rtl.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "stor-layout.h"
#include "tm_p.h"
-#include "function.h"
#include "tree-dump.h"
#include "tree-inline.h"
-#include "gimple.h"
+#include "internal-fn.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
#include "tree-iterator.h"
-#include "tree-flow.h"
#include "cgraph.h"
-#include "expr.h"
+#include "tree-cfg.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h" /* FIXME: For STACK_SAVEAREA_MODE and SAVE_NONLOCAL. */
#include "langhooks.h"
-#include "pointer-set.h"
-#include "ggc.h"
+#include "gimple-low.h"
+#include "gomp-constants.h"
/* The object of this pass is to lower the representation of a set of nested
struct nesting_info *inner;
struct nesting_info *next;
- struct pointer_map_t *field_map;
- struct pointer_map_t *var_map;
+ hash_map<tree, tree> *field_map;
+ hash_map<tree, tree> *var_map;
+ hash_set<tree *> *mem_refs;
bitmap suppress_expansion;
tree context;
tmp_var = create_tmp_var_raw (type, prefix);
DECL_CONTEXT (tmp_var) = info->context;
- TREE_CHAIN (tmp_var) = info->new_local_var_chain;
+ DECL_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)
way the properties are for the ADDR_EXPR are computed properly. */
save_context = current_function_decl;
current_function_decl = context;
- retval = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
+ retval = build_fold_addr_expr (exp);
current_function_decl = save_context;
return retval;
}
DECL_CONTEXT (field) = type;
- for (p = &TYPE_FIELDS (type); *p ; p = &TREE_CHAIN (*p))
+ for (p = &TYPE_FIELDS (type); *p ; p = &DECL_CHAIN (*p))
if (DECL_ALIGN (field) >= DECL_ALIGN (*p))
break;
- TREE_CHAIN (field) = *p;
+ DECL_CHAIN (field) = *p;
*p = field;
/* Set correct alignment for frame struct type. */
info->frame_type = type;
info->frame_decl = create_tmp_var_for (info, type, "FRAME");
+ DECL_NONLOCAL_FRAME (info->frame_decl) = 1;
/* ??? Always make it addressable for now, since it is meant to
be pointed to by the static chain pointer. This pessimizes
lookup_field_for_decl (struct nesting_info *info, tree decl,
enum insert_option insert)
{
- void **slot;
-
if (insert == NO_INSERT)
{
- slot = pointer_map_contains (info->field_map, decl);
- return slot ? (tree) *slot : NULL_TREE;
+ tree *slot = info->field_map->get (decl);
+ return slot ? *slot : NULL_TREE;
}
- slot = pointer_map_insert (info->field_map, decl);
+ tree *slot = &info->field_map->get_or_insert (decl);
if (!*slot)
{
tree field = make_node (FIELD_DECL);
info->any_parm_remapped = true;
}
- return (tree) *slot;
+ return *slot;
}
/* Build or return the variable that holds the static chain within
static tree
init_tmp_var_with_call (struct nesting_info *info, gimple_stmt_iterator *gsi,
- gimple call)
+ gcall *call)
{
tree t;
align = STACK_BOUNDARY;
}
- t = build_index_type (build_int_cst (NULL_TREE, size - 1));
+ t = build_index_type (size_int (size - 1));
t = build_array_type (char_type_node, t);
t = build_decl (DECL_SOURCE_LOCATION (info->context),
FIELD_DECL, get_identifier ("__data"), t);
lookup_tramp_for_decl (struct nesting_info *info, tree decl,
enum insert_option insert)
{
- void **slot;
-
if (insert == NO_INSERT)
{
- slot = pointer_map_contains (info->var_map, decl);
- return slot ? (tree) *slot : NULL_TREE;
+ tree *slot = info->var_map->get (decl);
+ return slot ? *slot : NULL_TREE;
}
- slot = pointer_map_insert (info->var_map, decl);
+ tree *slot = &info->var_map->get_or_insert (decl);
if (!*slot)
{
tree field = make_node (FIELD_DECL);
info->any_tramp_created = true;
}
- return (tree) *slot;
+ return *slot;
}
/* Build or return the field within the non-local frame state that holds
size = size + 1;
type = build_array_type
- (type, build_index_type (build_int_cst (NULL_TREE, size)));
+ (type, build_index_type (size_int (size)));
field = make_node (FIELD_DECL);
DECL_NAME (field) = get_identifier ("__nl_goto_buf");
return field;
}
-/* Invoke CALLBACK on all statements of GIMPLE sequence SEQ. */
+/* Invoke CALLBACK on all statements of GIMPLE sequence *PSEQ. */
static void
walk_body (walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
- struct nesting_info *info, gimple_seq seq)
+ struct nesting_info *info, gimple_seq *pseq)
{
struct walk_stmt_info wi;
memset (&wi, 0, sizeof (wi));
wi.info = info;
wi.val_only = true;
- walk_gimple_seq (seq, callback_stmt, callback_op, &wi);
+ walk_gimple_seq_mod (pseq, callback_stmt, callback_op, &wi);
}
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));
+ gimple_seq body = gimple_body (info->context);
+ walk_body (callback_stmt, callback_op, info, &body);
+ gimple_set_body (info->context, body);
}
/* Invoke CALLBACK on a GIMPLE_OMP_FOR's init, cond, incr and pre-body. */
static void
-walk_gimple_omp_for (gimple for_stmt,
+walk_gimple_omp_for (gomp_for *for_stmt,
walk_stmt_fn callback_stmt, walk_tree_fn callback_op,
struct nesting_info *info)
{
tree t;
size_t i;
- walk_body (callback_stmt, callback_op, info, gimple_omp_for_pre_body (for_stmt));
+ walk_body (callback_stmt, callback_op, info, gimple_omp_for_pre_body_ptr (for_stmt));
- seq = gimple_seq_alloc ();
+ seq = NULL;
memset (&wi, 0, sizeof (wi));
wi.info = info;
wi.gsi = gsi_last (seq);
walk_tree (&TREE_OPERAND (t, 1), callback_op, &wi, NULL);
}
- if (gimple_seq_empty_p (seq))
- gimple_seq_free (seq);
- else
+ seq = gsi_seq (wi.gsi);
+ if (!gimple_seq_empty_p (seq))
{
gimple_seq pre_body = gimple_omp_for_pre_body (for_stmt);
annotate_all_with_location (seq, gimple_location (for_stmt));
static bool
check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
{
- struct cgraph_node *cgn = cgraph_node (fndecl);
+ struct cgraph_node *cgn = cgraph_node::get (fndecl);
tree arg;
for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
{
- for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg))
+ for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = DECL_CHAIN (arg))
if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
return true;
- if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl))
+ if (check_for_nested_with_variably_modified (cgn->decl,
+ orig_fndecl))
return true;
}
create_nesting_tree (struct cgraph_node *cgn)
{
struct nesting_info *info = XCNEW (struct nesting_info);
- info->field_map = pointer_map_create ();
- info->var_map = pointer_map_create ();
+ info->field_map = new hash_map<tree, tree>;
+ info->var_map = new hash_map<tree, tree>;
+ info->mem_refs = new hash_set<tree *>;
info->suppress_expansion = BITMAP_ALLOC (&nesting_info_bitmap_obstack);
info->context = cgn->decl;
{
tree field = get_chain_field (i);
- x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+ x = build_simple_mem_ref (x);
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, gsi);
}
{
tree field = get_chain_field (i);
- x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+ x = build_simple_mem_ref (x);
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_simple_mem_ref (x);
}
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
/* 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. */
+ and in OMP 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);
+ tree *slot = &info->var_map->get_or_insert (decl);
if (*slot)
- return (tree) *slot;
+ return *slot;
target_context = decl_function_context (decl);
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 = build_simple_mem_ref (x);
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
}
- x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+ x = build_simple_mem_ref (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);
+ x = build_simple_mem_ref (x);
/* ??? We should be remapping types as well, surely. */
new_decl = build_decl (DECL_SOURCE_LOCATION (decl),
DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
*slot = new_decl;
- TREE_CHAIN (new_decl) = info->debug_var_chain;
+ DECL_CHAIN (new_decl) = info->debug_var_chain;
info->debug_var_chain = new_decl;
if (!optimize
if (use_pointer_in_frame (t))
{
x = init_tmp_var (info, x, &wi->gsi);
- x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
+ x = build_simple_mem_ref (x);
}
}
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_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_op, wi, NULL);
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;
+ /* If not optimizing, we will force the creation of the CHAIN object in
+ convert_all_function_calls, so we need to take it into account here. */
+ bool need_chain = info->outer && !optimize, need_stmts = false;
tree clause, decl;
int dummy;
bitmap new_suppress;
need_stmts = true;
goto do_decl_clause;
+ case OMP_CLAUSE_LINEAR:
+ if (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause))
+ need_stmts = true;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op (&OMP_CLAUSE_LINEAR_STEP (clause),
+ &dummy, wi);
+ goto do_decl_clause;
+
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYPRIVATE:
{
bitmap_set_bit (new_suppress, DECL_UID (decl));
OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
- need_chain = true;
+ if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_PRIVATE)
+ need_chain = true;
}
break;
if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
break;
/* FALLTHRU */
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_DEPEND:
+ case OMP_CLAUSE_DEVICE:
+ case OMP_CLAUSE_NUM_TEAMS:
+ case OMP_CLAUSE_THREAD_LIMIT:
+ case OMP_CLAUSE_SAFELEN:
+ case OMP_CLAUSE__CILK_FOR_COUNT_:
wi->val_only = true;
wi->is_lhs = false;
convert_nonlocal_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
- &dummy, wi);
+ &dummy, wi);
+ break;
+
+ case OMP_CLAUSE_DIST_SCHEDULE:
+ if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause) != NULL)
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
+ &dummy, wi);
+ }
+ break;
+
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ if (OMP_CLAUSE_SIZE (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op (&OMP_CLAUSE_SIZE (clause),
+ &dummy, wi);
+ }
+ if (DECL_P (OMP_CLAUSE_DECL (clause)))
+ goto do_decl_clause;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ walk_tree (&OMP_CLAUSE_DECL (clause), convert_nonlocal_reference_op,
+ wi, NULL);
+ break;
+
+ case OMP_CLAUSE_ALIGNED:
+ if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op
+ (&OMP_CLAUSE_ALIGNED_ALIGNMENT (clause), &dummy, wi);
+ }
+ /* Like do_decl_clause, but don't add any suppression. */
+ 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)
+ {
+ OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
+ if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_PRIVATE)
+ need_chain = true;
+ }
break;
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COLLAPSE:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
+ case OMP_CLAUSE_PROC_BIND:
break;
default:
= info->context;
walk_body (convert_nonlocal_reference_stmt,
convert_nonlocal_reference_op, info,
- OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+ &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
walk_body (convert_nonlocal_reference_stmt,
convert_nonlocal_reference_op, info,
- OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+ &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
= old_context;
}
case OMP_CLAUSE_LASTPRIVATE:
walk_body (convert_nonlocal_reference_stmt,
convert_nonlocal_reference_op, info,
- OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ break;
+
+ case OMP_CLAUSE_LINEAR:
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info,
+ &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause));
break;
default:
{
tree var;
- for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var))
+ for (var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
if (TREE_CODE (var) == VAR_DECL
&& variably_modified_type_p (TREE_TYPE (var), NULL)
&& DECL_HAS_VALUE_EXPR_P (var)
info->new_local_var_chain = NULL;
walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
- info, gimple_omp_body (stmt));
+ info, gimple_omp_body_ptr (stmt));
if (info->new_local_var_chain)
declare_vars (info->new_local_var_chain,
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,
+ walk_gimple_omp_for (as_a <gomp_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));
+ convert_nonlocal_reference_op, info, gimple_omp_body_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
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, gimple_omp_body_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
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, gimple_omp_body_ptr (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_TARGET:
+ if (!is_gimple_omp_offloaded (stmt))
+ {
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt),
+ wi);
+ info->suppress_expansion = save_suppress;
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info,
+ gimple_omp_body_ptr (stmt));
+ break;
+ }
+ save_suppress = info->suppress_expansion;
+ if (convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt),
+ wi))
+ {
+ tree c, decl;
+ decl = get_chain_decl (info);
+ c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP);
+ OMP_CLAUSE_DECL (c) = decl;
+ OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TO);
+ OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl);
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_target_clauses (stmt);
+ gimple_omp_target_set_clauses (as_a <gomp_target *> (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_ptr (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_TEAMS:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+ walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
+ info, gimple_omp_body_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
- info, gimple_omp_body (stmt));
+ info, gimple_omp_body_ptr (stmt));
break;
case GIMPLE_BIND:
- if (!optimize && gimple_bind_block (stmt))
- note_nonlocal_block_vlas (info, gimple_bind_block (stmt));
+ {
+ gbind *bind_stmt = as_a <gbind *> (stmt);
+ if (!optimize && gimple_bind_block (bind_stmt))
+ note_nonlocal_block_vlas (info, gimple_bind_block (bind_stmt));
+
+ for (tree var = gimple_bind_vars (bind_stmt); var; var = DECL_CHAIN (var))
+ if (TREE_CODE (var) == NAMELIST_DECL)
+ {
+ /* Adjust decls mentioned in NAMELIST_DECL. */
+ tree decls = NAMELIST_DECL_ASSOCIATED_DECL (var);
+ tree decl;
+ unsigned int i;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (decls), i, decl)
+ {
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ continue;
+ if (decl_function_context (decl) != info->context)
+ CONSTRUCTOR_ELT (decls, i)->value
+ = get_nonlocal_debug_decl (info, decl);
+ }
+ }
*handled_ops_p = false;
return NULL_TREE;
-
+ }
case GIMPLE_COND:
wi->val_only = true;
wi->is_lhs = false;
/* 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
+ field in FRAME. This is used both for debug info and in OMP
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);
+ tree *slot = &info->var_map->get_or_insert (decl);
if (*slot)
- return (tree) *slot;
+ return *slot;
/* Make sure frame_decl gets created. */
(void) get_frame_type (info);
DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
*slot = new_decl;
- TREE_CHAIN (new_decl) = info->debug_var_chain;
+ DECL_CHAIN (new_decl) = info->debug_var_chain;
info->debug_var_chain = new_decl;
/* Do not emit debug info twice. */
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_op, wi,
- NULL);
- walk_tree (&TREE_OPERAND (t, 2), convert_local_reference_op, wi,
- NULL);
- }
}
wi->val_only = false;
walk_tree (tp, convert_local_reference_op, wi, NULL);
wi->val_only = save_val_only;
break;
+ case MEM_REF:
+ save_val_only = wi->val_only;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ walk_tree (&TREE_OPERAND (t, 0), convert_local_reference_op,
+ wi, NULL);
+ /* We need to re-fold the MEM_REF as component references as
+ part of a ADDR_EXPR address are not allowed. But we cannot
+ fold here, as the chain record type is not yet finalized. */
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+ && !DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
+ info->mem_refs->add (tp);
+ 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
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;
+ /* If not optimizing, we will force the creation of the FRAME object in
+ convert_all_function_calls, so we need to take it into account here. */
+ bool need_frame = info->inner && !optimize, need_stmts = false;
tree clause, decl;
int dummy;
bitmap new_suppress;
need_stmts = true;
goto do_decl_clause;
+ case OMP_CLAUSE_LINEAR:
+ if (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause))
+ need_stmts = true;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op (&OMP_CLAUSE_LINEAR_STEP (clause), &dummy,
+ wi);
+ goto do_decl_clause;
+
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYPRIVATE:
if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
break;
/* FALLTHRU */
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
+ case OMP_CLAUSE_DEPEND:
+ case OMP_CLAUSE_DEVICE:
+ case OMP_CLAUSE_NUM_TEAMS:
+ case OMP_CLAUSE_THREAD_LIMIT:
+ case OMP_CLAUSE_SAFELEN:
+ case OMP_CLAUSE__CILK_FOR_COUNT_:
wi->val_only = true;
wi->is_lhs = false;
convert_local_reference_op (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
wi);
break;
+ case OMP_CLAUSE_DIST_SCHEDULE:
+ if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause) != NULL)
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
+ &dummy, wi);
+ }
+ break;
+
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ if (OMP_CLAUSE_SIZE (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op (&OMP_CLAUSE_SIZE (clause),
+ &dummy, wi);
+ }
+ if (DECL_P (OMP_CLAUSE_DECL (clause)))
+ goto do_decl_clause;
+ wi->val_only = true;
+ wi->is_lhs = false;
+ walk_tree (&OMP_CLAUSE_DECL (clause), convert_local_reference_op,
+ wi, NULL);
+ break;
+
+ case OMP_CLAUSE_ALIGNED:
+ if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op
+ (&OMP_CLAUSE_ALIGNED_ALIGNMENT (clause), &dummy, wi);
+ }
+ /* Like do_decl_clause, but don't add any suppression. */
+ 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)
+ {
+ OMP_CLAUSE_DECL (clause)
+ = get_local_debug_decl (info, decl, field);
+ need_frame = true;
+ }
+ }
+ 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:
+ case OMP_CLAUSE_MERGEABLE:
+ case OMP_CLAUSE_PROC_BIND:
break;
default:
= info->context;
walk_body (convert_local_reference_stmt,
convert_local_reference_op, info,
- OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+ &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
walk_body (convert_local_reference_stmt,
convert_local_reference_op, info,
- OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+ &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
= old_context;
}
case OMP_CLAUSE_LASTPRIVATE:
walk_body (convert_local_reference_stmt,
convert_local_reference_op, info,
- OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ break;
+
+ case OMP_CLAUSE_LINEAR:
+ walk_body (convert_local_reference_stmt,
+ convert_local_reference_op, info,
+ &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause));
break;
default:
info->new_local_var_chain = NULL;
walk_body (convert_local_reference_stmt, convert_local_reference_op, info,
- gimple_omp_body (stmt));
+ gimple_omp_body_ptr (stmt));
if (info->new_local_var_chain)
declare_vars (info->new_local_var_chain,
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,
+ walk_gimple_omp_for (as_a <gomp_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, gimple_omp_body_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
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, gimple_omp_body_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
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, gimple_omp_body_ptr (stmt));
+ info->suppress_expansion = save_suppress;
+ break;
+
+ case GIMPLE_OMP_TARGET:
+ if (!is_gimple_omp_offloaded (stmt))
+ {
+ save_suppress = info->suppress_expansion;
+ convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+ info->suppress_expansion = save_suppress;
+ walk_body (convert_local_reference_stmt, convert_local_reference_op,
+ info, gimple_omp_body_ptr (stmt));
+ break;
+ }
+ save_suppress = info->suppress_expansion;
+ if (convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi))
+ {
+ tree c;
+ (void) get_frame_type (info);
+ c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP);
+ OMP_CLAUSE_DECL (c) = info->frame_decl;
+ OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TOFROM);
+ OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (info->frame_decl);
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_target_clauses (stmt);
+ gimple_omp_target_set_clauses (as_a <gomp_target *> (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_ptr (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_TEAMS:
+ save_suppress = info->suppress_expansion;
+ convert_local_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+ walk_body (convert_local_reference_stmt, convert_local_reference_op,
+ info, gimple_omp_body_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
walk_body (convert_local_reference_stmt, convert_local_reference_op,
- info, gimple_omp_body (stmt));
+ info, gimple_omp_body_ptr (stmt));
break;
case GIMPLE_COND:
*handled_ops_p = false;
return NULL_TREE;
+ case GIMPLE_ASSIGN:
+ if (gimple_clobber_p (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ if (!use_pointer_in_frame (lhs)
+ && lookup_field_for_decl (info, lhs, NO_INSERT))
+ {
+ gsi_replace (gsi, gimple_build_nop (), true);
+ break;
+ }
+ }
+ *handled_ops_p = false;
+ return NULL_TREE;
+
+ case GIMPLE_BIND:
+ for (tree var = gimple_bind_vars (as_a <gbind *> (stmt));
+ var;
+ var = DECL_CHAIN (var))
+ if (TREE_CODE (var) == NAMELIST_DECL)
+ {
+ /* Adjust decls mentioned in NAMELIST_DECL. */
+ tree decls = NAMELIST_DECL_ASSOCIATED_DECL (var);
+ tree decl;
+ unsigned int i;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (decls), i, decl)
+ {
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ continue;
+ if (decl_function_context (decl) == info->context
+ && !use_pointer_in_frame (decl))
+ {
+ tree field = lookup_field_for_decl (info, decl, NO_INSERT);
+ if (field)
+ {
+ CONSTRUCTOR_ELT (decls, i)->value
+ = get_local_debug_decl (info, decl, field);
+ }
+ }
+ }
+ }
+
+ *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. */
{
struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
tree label, new_label, target_context, x, field;
- void **slot;
- gimple call;
+ gcall *call;
gimple stmt = gsi_stmt (*gsi);
if (gimple_code (stmt) != GIMPLE_GOTO)
(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. */
- slot = pointer_map_insert (i->var_map, label);
+ tree *slot = &i->var_map->get_or_insert (label);
if (*slot == NULL)
{
new_label = create_artificial_label (UNKNOWN_LOCATION);
*slot = new_label;
}
else
- new_label = (tree) *slot;
+ new_label = *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->gsi);
+ x = get_frame_field (info, target_context, field, gsi);
x = build_addr (x, target_context);
- x = gsi_gimplify_val (info, x, &wi->gsi);
- call = gimple_build_call (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2,
- build_addr (new_label, target_context), x);
- gsi_replace (&wi->gsi, call, false);
+ x = gsi_gimplify_val (info, x, gsi);
+ call = gimple_build_call (builtin_decl_implicit (BUILT_IN_NONLOCAL_GOTO),
+ 2, build_addr (new_label, target_context), x);
+ gsi_replace (gsi, call, false);
/* We have handled all of STMT's operands, no need to keep going. */
*handled_ops_p = true;
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);
+ glabel *stmt = dyn_cast <glabel *> (gsi_stmt (*gsi));
- if (gimple_code (stmt) != GIMPLE_LABEL)
+ if (!stmt)
{
*handled_ops_p = false;
return NULL_TREE;
label = gimple_label_label (stmt);
- slot = pointer_map_contains (info->var_map, label);
+ tree *slot = info->var_map->get (label);
if (!slot)
{
*handled_ops_p = false;
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;
+ gcall *call;
*walk_subtrees = 0;
switch (TREE_CODE (t))
/* Do machine-specific ugliness. Normally this will involve
computing extra alignment, but it can really be anything. */
- builtin = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
+ builtin = builtin_decl_implicit (BUILT_IN_ADJUST_TRAMPOLINE);
call = gimple_build_call (builtin, 1, x);
x = init_tmp_var_with_call (info, &wi->gsi, call);
convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
struct walk_stmt_info *wi)
{
+ struct nesting_info *info = (struct nesting_info *) wi->info;
gimple stmt = gsi_stmt (*gsi);
switch (gimple_code (stmt))
for (i = 0; i < nargs; i++)
walk_tree (gimple_call_arg_ptr (stmt, i), convert_tramp_reference_op,
wi, NULL);
+ break;
+ }
- *handled_ops_p = true;
- return NULL_TREE;
+ case GIMPLE_OMP_TARGET:
+ if (!is_gimple_omp_offloaded (stmt))
+ {
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+ /* FALLTHRU */
+ case GIMPLE_OMP_PARALLEL:
+ case GIMPLE_OMP_TASK:
+ {
+ tree save_local_var_chain;
+ walk_gimple_op (stmt, convert_tramp_reference_op, wi);
+ save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+ walk_body (convert_tramp_reference_stmt, convert_tramp_reference_op,
+ info, gimple_omp_body_ptr (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;
}
+ break;
default:
- break;
+ *handled_ops_p = false;
+ return NULL_TREE;
}
- *handled_ops_p = false;
+ *handled_ops_p = true;
return NULL_TREE;
}
target_context = decl_function_context (decl);
if (target_context && DECL_STATIC_CHAIN (decl))
{
- gimple_call_set_chain (stmt, get_static_chain (info, target_context,
- &wi->gsi));
+ gimple_call_set_chain (as_a <gcall *> (stmt),
+ get_static_chain (info, target_context,
+ &wi->gsi));
info->static_chain_added |= (1 << (info->context != target_context));
}
break;
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));
+ walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
for (i = 0; i < 2; i++)
{
tree c, decl;
info->static_chain_added |= save_static_chain_added;
break;
+ case GIMPLE_OMP_TARGET:
+ if (!is_gimple_omp_offloaded (stmt))
+ {
+ walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
+ break;
+ }
+ save_static_chain_added = info->static_chain_added;
+ info->static_chain_added = 0;
+ walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (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_target_clauses (stmt);
+ c;
+ c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_DECL (c) == decl)
+ break;
+ if (c == NULL)
+ {
+ c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP);
+ OMP_CLAUSE_DECL (c) = decl;
+ OMP_CLAUSE_SET_MAP_KIND (c, i ? GOMP_MAP_TO : GOMP_MAP_TOFROM);
+ OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl);
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_target_clauses (stmt);
+ gimple_omp_target_set_clauses (as_a <gomp_target *> (stmt),
+ c);
+ }
+ }
+ info->static_chain_added |= save_static_chain_added;
+ break;
+
case GIMPLE_OMP_FOR:
walk_body (convert_gimple_call, NULL, info,
- gimple_omp_for_pre_body (stmt));
+ gimple_omp_for_pre_body_ptr (stmt));
/* FALLTHRU */
case GIMPLE_OMP_SECTIONS:
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_SINGLE:
+ case GIMPLE_OMP_TEAMS:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_CRITICAL:
- walk_body (convert_gimple_call, NULL, info, gimple_omp_body (stmt));
+ walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
break;
default:
static void
convert_all_function_calls (struct nesting_info *root)
{
+ unsigned int chain_count = 0, old_chain_count, iter_count;
struct nesting_info *n;
- int iter_count;
- bool any_changed;
/* First, optimistically clear static_chain for all decls that haven't
- used the static chain already for variable access. */
+ used the static chain already for variable access. But always create
+ it if not optimizing. This makes it possible to reconstruct the static
+ nesting tree at run time and thus to resolve up-level references from
+ within the debugger. */
FOR_EACH_NEST_INFO (n, root)
{
tree decl = n->context;
- if (!n->outer || (!n->chain_decl && !n->chain_field))
+ if (!optimize)
+ {
+ if (n->inner)
+ (void) get_frame_type (n);
+ if (n->outer)
+ (void) get_chain_decl (n);
+ }
+ else if (!n->outer || (!n->chain_decl && !n->chain_field))
{
DECL_STATIC_CHAIN (decl) = 0;
if (dump_file && (dump_flags & TDF_DETAILS))
}
else
DECL_STATIC_CHAIN (decl) = 1;
+ chain_count += DECL_STATIC_CHAIN (decl);
}
/* Walk the functions and perform transformations. Note that these
iter_count = 0;
do
{
- any_changed = false;
+ old_chain_count = chain_count;
+ chain_count = 0;
iter_count++;
if (dump_file && (dump_flags & TDF_DETAILS))
FOR_EACH_NEST_INFO (n, root)
{
tree decl = n->context;
- bool old_static_chain = DECL_STATIC_CHAIN (decl);
-
walk_function (convert_tramp_reference_stmt,
convert_tramp_reference_op, n);
walk_function (convert_gimple_call, NULL, n);
-
- /* If a call to another function created the use of a chain
- within this function, we'll have to continue iteration. */
- if (!old_static_chain && DECL_STATIC_CHAIN (decl))
- any_changed = true;
+ chain_count += DECL_STATIC_CHAIN (decl);
}
}
- while (any_changed);
+ while (chain_count != old_chain_count);
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "convert_all_function_calls iterations: %d\n\n",
+ fprintf (dump_file, "convert_all_function_calls iterations: %u\n\n",
iter_count);
}
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);
+ tree *slot = nid->root->var_map->get (decl);
if (slot)
return (tree) *slot;
{
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);
+ tree *slot = root->var_map->get (t);
if (slot)
- return (tree) *slot;
+ return *slot;
}
return NULL;
}
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;
- }
- }
+ for (var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
+ if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
+ {
+ val = DECL_VALUE_EXPR (var);
+ type = TREE_TYPE (var);
+
+ if (!(TREE_CODE (val) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (val, 0)) == VAR_DECL
+ && variably_modified_type_p (type, NULL)))
+ continue;
+
+ if (root->var_map->get (TREE_OPERAND (val, 0))
+ || walk_tree (&type, contains_remapped_vars, root, 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.cb.decl_map = new hash_map<tree, tree>;
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))
+ for (; var; var = DECL_CHAIN (var))
+ if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
{
struct nesting_info *i;
- tree newt, t, context;
+ tree newt, 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)
+ type = TREE_TYPE (var);
+
+ if (!(TREE_CODE (val) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (val, 0)) == VAR_DECL
+ && variably_modified_type_p (type, NULL)))
+ continue;
+
+ tree *slot = root->var_map->get (TREE_OPERAND (val, 0));
+ if (!slot && !walk_tree (&type, contains_remapped_vars, root, NULL))
continue;
context = decl_function_context (var);
if (i == NULL)
continue;
+ /* Fully expand value expressions. This avoids having debug variables
+ only referenced from them and that can be swept during GC. */
+ if (slot)
+ {
+ tree t = (tree) *slot;
+ gcc_assert (DECL_P (t) && DECL_HAS_VALUE_EXPR_P (t));
+ val = build1 (INDIRECT_REF, TREE_TYPE (val), DECL_VALUE_EXPR (t));
+ }
+
id.cb.src_fn = i->context;
id.cb.dst_fn = i->context;
id.cb.src_cfun = DECL_STRUCT_FUNCTION (root->context);
while (POINTER_TYPE_P (newt) && !TYPE_NAME (newt))
{
newt = TREE_TYPE (newt);
- t = TREE_TYPE (t);
+ type = TREE_TYPE (type);
}
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))
+ && newt != type
+ && TYPE_NAME (newt) == TYPE_NAME (type))
TYPE_NAME (newt) = remap_decl (TYPE_NAME (newt), &id.cb);
walk_tree (&val, copy_tree_body_r, &id.cb, NULL);
SET_DECL_VALUE_EXPR (var, val);
}
- pointer_map_destroy (id.cb.decl_map);
+ delete id.cb.decl_map;
+}
+
+/* Fold the MEM_REF *E. */
+bool
+fold_mem_refs (tree *const &e, void *data ATTRIBUTE_UNUSED)
+{
+ tree *ref_p = CONST_CAST2 (tree *, const tree *, (const tree *)e);
+ *ref_p = fold (*ref_p);
+ return true;
}
/* Do "everything else" to clean up or complete state collected by the
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);
+ adjust = &DECL_CHAIN (*adjust))
+ gcc_assert (DECL_CHAIN (*adjust));
+ *adjust = DECL_CHAIN (*adjust);
- TREE_CHAIN (root->frame_decl) = NULL_TREE;
+ DECL_CHAIN (root->frame_decl) = NULL_TREE;
declare_vars (root->frame_decl,
gimple_seq_first_stmt (gimple_body (context)), true);
}
if (root->any_parm_remapped)
{
tree p;
- for (p = DECL_ARGUMENTS (context); p ; p = TREE_CHAIN (p))
+ for (p = DECL_ARGUMENTS (context); p ; p = DECL_CHAIN (p))
{
tree field, x, y;
else
x = p;
- 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)
{
gimple_stmt_iterator gsi = gsi_last (stmt_list);
x = init_tmp_var (root, x, &gsi);
- gimple_assign_set_rhs1 (stmt, x);
}
+
+ 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);
}
}
root->frame_decl, field, NULL_TREE);
arg1 = build_addr (x, context);
- x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
+ x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE);
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)
{
- gimple bind;
+ gbind *bind;
annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context));
- bind = gimple_seq_first_stmt (gimple_body (context));
+ bind = gimple_seq_first_stmt_as_a_bind (gimple_body (context));
gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind));
gimple_bind_set_body (bind, stmt_list);
}
if (root->debug_var_chain)
{
tree debug_var;
- gimple scope;
+ gbind *scope;
remap_vla_decls (DECL_INITIAL (root->context), root);
for (debug_var = root->debug_var_chain; debug_var;
- debug_var = TREE_CHAIN (debug_var))
+ debug_var = DECL_CHAIN (debug_var))
if (variably_modified_type_p (TREE_TYPE (debug_var), NULL))
break;
memset (&id, 0, sizeof (id));
id.cb.copy_decl = nesting_copy_decl;
- id.cb.decl_map = pointer_map_create ();
+ id.cb.decl_map = new hash_map<tree, tree>;
id.root = root;
- for (; debug_var; debug_var = TREE_CHAIN (debug_var))
+ for (; debug_var; debug_var = DECL_CHAIN (debug_var))
if (variably_modified_type_p (TREE_TYPE (debug_var), NULL))
{
tree type = TREE_TYPE (debug_var);
TYPE_NAME (newt) = remap_decl (TYPE_NAME (newt), &id.cb);
}
- pointer_map_destroy (id.cb.decl_map);
+ delete id.cb.decl_map;
}
- scope = gimple_seq_first_stmt (gimple_body (root->context));
+ scope = gimple_seq_first_stmt_as_a_bind (gimple_body (root->context));
if (gimple_bind_block (scope))
declare_vars (root->debug_var_chain, scope, true);
else
root->debug_var_chain);
}
+ /* Fold the rewritten MEM_REF trees. */
+ root->mem_refs->traverse<void *, fold_mem_refs> (NULL);
+
/* Dump the translated tree function. */
if (dump_file)
{
static void
unnest_nesting_tree_1 (struct nesting_info *root)
{
- struct cgraph_node *node = cgraph_node (root->context);
+ struct cgraph_node *node = cgraph_node::get (root->context);
/* For nested functions update the cgraph to reflect unnesting.
We also delay finalizing of these functions up to this point. */
if (node->origin)
{
- cgraph_unnest_node (cgraph_node (root->context));
- cgraph_finalize_function (root->context, true);
+ node->unnest ();
+ cgraph_node::finalize_function (root->context, true);
}
}
do
{
next = iter_nestinfo_next (node);
- pointer_map_destroy (node->var_map);
- pointer_map_destroy (node->field_map);
+ delete node->var_map;
+ delete node->field_map;
+ delete node->mem_refs;
free (node);
node = next;
}
struct nesting_info *root;
/* If there are no nested functions, there's nothing to do. */
- cgn = cgraph_node (fndecl);
+ cgn = cgraph_node::get (fndecl);
if (!cgn->nested)
return;