/* Nested function decomposition for GIMPLE.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2021 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 "target.h"
+#include "rtl.h"
#include "tree.h"
+#include "gimple.h"
+#include "memmodel.h"
+#include "tm_p.h"
#include "stringpool.h"
+#include "cgraph.h"
+#include "fold-const.h"
#include "stor-layout.h"
-#include "tm_p.h"
-#include "function.h"
-#include "tree-dump.h"
+#include "dumpfile.h"
#include "tree-inline.h"
-#include "pointer-set.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
#include "gimplify.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
-#include "tree-iterator.h"
-#include "bitmap.h"
-#include "cgraph.h"
#include "tree-cfg.h"
-#include "expr.h" /* FIXME: For STACK_SAVEAREA_MODE and SAVE_NONLOCAL. */
+#include "explow.h"
#include "langhooks.h"
#include "gimple-low.h"
+#include "gomp-constants.h"
+#include "diagnostic.h"
+#include "alloc-pool.h"
+#include "tree-nested.h"
+#include "symbol-summary.h"
+#include "symtab-thunks.h"
+
+/* Summary of nested functions. */
+static function_summary <nested_function_info *>
+ *nested_function_sum = NULL;
+
+/* Return nested_function_info, if available. */
+nested_function_info *
+nested_function_info::get (cgraph_node *node)
+{
+ if (!nested_function_sum)
+ return NULL;
+ return nested_function_sum->get (node);
+}
+/* Return nested_function_info possibly creating new one. */
+nested_function_info *
+nested_function_info::get_create (cgraph_node *node)
+{
+ if (!nested_function_sum)
+ {
+ nested_function_sum = new function_summary <nested_function_info *>
+ (symtab);
+ nested_function_sum->disable_insertion_hook ();
+ }
+ return nested_function_sum->get_create (node);
+}
+
+/* cgraph_node is no longer nested function; update cgraph accordingly. */
+void
+unnest_function (cgraph_node *node)
+{
+ nested_function_info *info = nested_function_info::get (node);
+ cgraph_node **node2 = &nested_function_info::get
+ (nested_function_origin (node))->nested;
+
+ gcc_checking_assert (info->origin);
+ while (*node2 != node)
+ node2 = &nested_function_info::get (*node2)->next_nested;
+ *node2 = info->next_nested;
+ info->next_nested = NULL;
+ info->origin = NULL;
+ nested_function_sum->remove (node);
+}
+
+/* Destructor: unlink function from nested function lists. */
+nested_function_info::~nested_function_info ()
+{
+ cgraph_node *next;
+ for (cgraph_node *n = nested; n; n = next)
+ {
+ nested_function_info *info = nested_function_info::get (n);
+ next = info->next_nested;
+ info->origin = NULL;
+ info->next_nested = NULL;
+ }
+ nested = NULL;
+ if (origin)
+ {
+ cgraph_node **node2
+ = &nested_function_info::get (origin)->nested;
+
+ nested_function_info *info;
+ while ((info = nested_function_info::get (*node2)) != this && info)
+ node2 = &info->next_nested;
+ *node2 = next_nested;
+ }
+}
+
+/* Free nested function info summaries. */
+void
+nested_function_info::release ()
+{
+ if (nested_function_sum)
+ delete (nested_function_sum);
+ nested_function_sum = NULL;
+}
+
+/* If NODE is nested function, record it. */
+void
+maybe_record_nested_function (cgraph_node *node)
+{
+ /* All nested functions gets lowered during the construction of symtab. */
+ if (symtab->state > CONSTRUCTION)
+ return;
+ if (DECL_CONTEXT (node->decl)
+ && TREE_CODE (DECL_CONTEXT (node->decl)) == FUNCTION_DECL)
+ {
+ cgraph_node *origin = cgraph_node::get_create (DECL_CONTEXT (node->decl));
+ nested_function_info *info = nested_function_info::get_create (node);
+ nested_function_info *origin_info
+ = nested_function_info::get_create (origin);
+
+ info->origin = origin;
+ info->next_nested = origin_info->nested;
+ origin_info->nested = node;
+ }
+}
/* The object of this pass is to lower the representation of a set of nested
functions in order to expose all of the gory details of the various
struct nesting_info *inner;
struct nesting_info *next;
- struct pointer_map_t *field_map;
- struct pointer_map_t *var_map;
- struct pointer_set_t *mem_refs;
+ hash_map<tree, tree> *field_map;
+ hash_map<tree, tree> *var_map;
+ hash_set<tree *> *mem_refs;
bitmap suppress_expansion;
tree context;
tree chain_decl;
tree nl_goto_field;
+ bool thunk_p;
bool any_parm_remapped;
bool any_tramp_created;
+ bool any_descr_created;
char static_chain_added;
};
DECL_CONTEXT (tmp_var) = info->context;
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)
- DECL_GIMPLE_REG_P (tmp_var) = 1;
info->new_local_var_chain = tmp_var;
return tmp_var;
}
+/* Like build_simple_mem_ref, but set TREE_THIS_NOTRAP on the result. */
+
+static tree
+build_simple_mem_ref_notrap (tree ptr)
+{
+ tree t = build_simple_mem_ref (ptr);
+ TREE_THIS_NOTRAP (t) = 1;
+ return t;
+}
+
/* Take the address of EXP to be used within function CONTEXT.
Mark it for addressability as necessary. */
tree
-build_addr (tree exp, tree context)
+build_addr (tree exp)
{
- tree base = exp;
- tree save_context;
- tree retval;
-
- while (handled_component_p (base))
- base = TREE_OPERAND (base, 0);
-
- if (DECL_P (base))
- TREE_ADDRESSABLE (base) = 1;
-
- /* Building the ADDR_EXPR will compute a set of properties for
- that ADDR_EXPR. Those properties are unfortunately context
- specific, i.e., they are dependent on CURRENT_FUNCTION_DECL.
-
- Temporarily set CURRENT_FUNCTION_DECL to the desired context,
- build the ADDR_EXPR, then restore CURRENT_FUNCTION_DECL. That
- way the properties are for the ADDR_EXPR are computed properly. */
- save_context = current_function_decl;
- current_function_decl = context;
- retval = build_fold_addr_expr (exp);
- current_function_decl = save_context;
- return retval;
+ mark_addressable (exp);
+ return build_fold_addr_expr (exp);
}
/* Insert FIELD into TYPE, sorted by alignment requirements. */
/* Set correct alignment for frame struct type. */
if (TYPE_ALIGN (type) < DECL_ALIGN (field))
- TYPE_ALIGN (type) = DECL_ALIGN (field);
+ SET_TYPE_ALIGN (type, DECL_ALIGN (field));
}
/* Build or return the RECORD_TYPE that describes the frame state that is
free (name);
info->frame_type = type;
- info->frame_decl = create_tmp_var_for (info, type, "FRAME");
+
+ /* Do not put info->frame_decl on info->new_local_var_chain,
+ so that we can declare it in the lexical blocks, which
+ makes sure virtual regs that end up appearing in its RTL
+ expression get substituted in instantiate_virtual_regs. */
+ info->frame_decl = create_tmp_var_raw (type, "FRAME");
+ DECL_CONTEXT (info->frame_decl) = info->context;
DECL_NONLOCAL_FRAME (info->frame_decl) = 1;
+ DECL_SEEN_IN_BIND_EXPR_P (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
local frame structure in the first place. */
TREE_ADDRESSABLE (info->frame_decl) = 1;
}
+
return type;
}
-/* Return true if DECL should be referenced by pointer in the non-local
- frame structure. */
+/* Return true if DECL should be referenced by pointer in the non-local frame
+ structure. */
static bool
use_pointer_in_frame (tree decl)
{
if (TREE_CODE (decl) == PARM_DECL)
{
- /* It's illegal to copy TREE_ADDRESSABLE, impossible to copy variable
- sized decls, and inefficient to copy large aggregates. Don't bother
- moving anything but scalar variables. */
+ /* It's illegal to copy TREE_ADDRESSABLE, impossible to copy variable-
+ sized DECLs, and inefficient to copy large aggregates. Don't bother
+ moving anything but scalar parameters. */
return AGGREGATE_TYPE_P (TREE_TYPE (decl));
}
else
{
- /* Variable sized types make things "interesting" in the frame. */
- return DECL_SIZE (decl) == NULL || !TREE_CONSTANT (DECL_SIZE (decl));
+ /* Variable-sized DECLs can only come from OMP clauses at this point
+ since the gimplifier has already turned the regular variables into
+ pointers. Do the same as the gimplifier. */
+ return !DECL_SIZE (decl) || TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST;
}
}
lookup_field_for_decl (struct nesting_info *info, tree decl,
enum insert_option insert)
{
- void **slot;
+ gcc_checking_assert (decl_function_context (decl) == info->context);
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 type = get_frame_type (info);
tree field = make_node (FIELD_DECL);
DECL_NAME (field) = DECL_NAME (decl);
if (use_pointer_in_frame (decl))
{
TREE_TYPE (field) = build_pointer_type (TREE_TYPE (decl));
- DECL_ALIGN (field) = TYPE_ALIGN (TREE_TYPE (field));
+ SET_DECL_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field)));
DECL_NONADDRESSABLE_P (field) = 1;
}
else
{
- TREE_TYPE (field) = TREE_TYPE (decl);
- DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (decl);
- DECL_ALIGN (field) = DECL_ALIGN (decl);
- DECL_USER_ALIGN (field) = DECL_USER_ALIGN (decl);
- TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (decl);
- DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (decl);
- TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (decl);
+ TREE_TYPE (field) = TREE_TYPE (decl);
+ DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (decl);
+ SET_DECL_ALIGN (field, DECL_ALIGN (decl));
+ DECL_USER_ALIGN (field) = DECL_USER_ALIGN (decl);
+ DECL_IGNORED_P (field) = DECL_IGNORED_P (decl);
+ DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (decl);
+ TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (decl);
+ copy_warning (field, decl);
+
+ /* Declare the transformation and adjust the original DECL. For a
+ variable or for a parameter when not optimizing, we make it point
+ to the field in the frame directly. For a parameter, we don't do
+ it when optimizing because the variable tracking pass will already
+ do the job, */
+ if (VAR_P (decl) || !optimize)
+ {
+ tree x
+ = build3 (COMPONENT_REF, TREE_TYPE (field), info->frame_decl,
+ field, NULL_TREE);
+
+ /* If the next declaration is a PARM_DECL pointing to the DECL,
+ we need to adjust its VALUE_EXPR directly, since chains of
+ VALUE_EXPRs run afoul of garbage collection. This occurs
+ in Ada for Out parameters that aren't copied in. */
+ tree next = DECL_CHAIN (decl);
+ if (next
+ && TREE_CODE (next) == PARM_DECL
+ && DECL_HAS_VALUE_EXPR_P (next)
+ && DECL_VALUE_EXPR (next) == decl)
+ SET_DECL_VALUE_EXPR (next, x);
+
+ SET_DECL_VALUE_EXPR (decl, x);
+ DECL_HAS_VALUE_EXPR_P (decl) = 1;
+ }
}
- insert_field_into_struct (get_frame_type (info), field);
+ insert_field_into_struct (type, field);
*slot = field;
if (TREE_CODE (decl) == PARM_DECL)
info->any_parm_remapped = true;
}
- return (tree) *slot;
+ return *slot;
}
/* Build or return the variable that holds the static chain within
field = make_node (FIELD_DECL);
DECL_NAME (field) = get_identifier ("__chain");
TREE_TYPE (field) = type;
- DECL_ALIGN (field) = TYPE_ALIGN (type);
+ SET_DECL_ALIGN (field, TYPE_ALIGN (type));
DECL_NONADDRESSABLE_P (field) = 1;
insert_field_into_struct (get_frame_type (info), field);
static tree
init_tmp_var_with_call (struct nesting_info *info, gimple_stmt_iterator *gsi,
- gimple call)
+ gcall *call)
{
tree t;
init_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi)
{
tree t;
- gimple stmt;
+ gimple *stmt;
t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
stmt = gimple_build_assign (t, exp);
save_tmp_var (struct nesting_info *info, tree exp, gimple_stmt_iterator *gsi)
{
tree t;
- gimple stmt;
+ gimple *stmt;
t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
stmt = gimple_build_assign (exp, t);
t = build_array_type (char_type_node, t);
t = build_decl (DECL_SOURCE_LOCATION (info->context),
FIELD_DECL, get_identifier ("__data"), t);
- DECL_ALIGN (t) = align;
+ SET_DECL_ALIGN (t, align);
DECL_USER_ALIGN (t) = 1;
trampoline_type = make_node (RECORD_TYPE);
return trampoline_type;
}
+/* Build or return the type used to represent a nested function descriptor. */
+
+static GTY(()) tree descriptor_type;
+
+static tree
+get_descriptor_type (struct nesting_info *info)
+{
+ /* The base alignment is that of a function. */
+ const unsigned align = FUNCTION_ALIGNMENT (FUNCTION_BOUNDARY);
+ tree t;
+
+ if (descriptor_type)
+ return descriptor_type;
+
+ t = build_index_type (integer_one_node);
+ t = build_array_type (ptr_type_node, t);
+ t = build_decl (DECL_SOURCE_LOCATION (info->context),
+ FIELD_DECL, get_identifier ("__data"), t);
+ SET_DECL_ALIGN (t, MAX (TYPE_ALIGN (ptr_type_node), align));
+ DECL_USER_ALIGN (t) = 1;
+
+ descriptor_type = make_node (RECORD_TYPE);
+ TYPE_NAME (descriptor_type) = get_identifier ("__builtin_descriptor");
+ TYPE_FIELDS (descriptor_type) = t;
+ layout_type (descriptor_type);
+ DECL_CONTEXT (t) = descriptor_type;
+
+ return descriptor_type;
+}
+
+/* Given DECL, a nested function, find or create an element in the
+ var map for this function. */
+
+static tree
+lookup_element_for_decl (struct nesting_info *info, tree decl,
+ enum insert_option insert)
+{
+ if (insert == NO_INSERT)
+ {
+ tree *slot = info->var_map->get (decl);
+ return slot ? *slot : NULL_TREE;
+ }
+
+ tree *slot = &info->var_map->get_or_insert (decl);
+ if (!*slot)
+ *slot = build_tree_list (NULL_TREE, NULL_TREE);
+
+ return (tree) *slot;
+}
+
+/* Given DECL, a nested function, create a field in the non-local
+ frame structure for this function. */
+
+static tree
+create_field_for_decl (struct nesting_info *info, tree decl, tree type)
+{
+ tree field = make_node (FIELD_DECL);
+ DECL_NAME (field) = DECL_NAME (decl);
+ TREE_TYPE (field) = type;
+ TREE_ADDRESSABLE (field) = 1;
+ insert_field_into_struct (get_frame_type (info), field);
+ return field;
+}
+
/* Given DECL, a nested function, find or create a field in the non-local
frame structure for a trampoline for this function. */
lookup_tramp_for_decl (struct nesting_info *info, tree decl,
enum insert_option insert)
{
- void **slot;
+ tree elt, field;
- if (insert == NO_INSERT)
+ elt = lookup_element_for_decl (info, decl, insert);
+ if (!elt)
+ return NULL_TREE;
+
+ field = TREE_PURPOSE (elt);
+
+ if (!field && insert == INSERT)
{
- slot = pointer_map_contains (info->var_map, decl);
- return slot ? (tree) *slot : NULL_TREE;
+ field = create_field_for_decl (info, decl, get_trampoline_type (info));
+ TREE_PURPOSE (elt) = field;
+ info->any_tramp_created = true;
}
- slot = pointer_map_insert (info->var_map, decl);
- if (!*slot)
- {
- tree field = make_node (FIELD_DECL);
- DECL_NAME (field) = DECL_NAME (decl);
- TREE_TYPE (field) = get_trampoline_type (info);
- TREE_ADDRESSABLE (field) = 1;
+ return field;
+}
- insert_field_into_struct (get_frame_type (info), field);
- *slot = field;
+/* Given DECL, a nested function, find or create a field in the non-local
+ frame structure for a descriptor for this function. */
- info->any_tramp_created = true;
+static tree
+lookup_descr_for_decl (struct nesting_info *info, tree decl,
+ enum insert_option insert)
+{
+ tree elt, field;
+
+ elt = lookup_element_for_decl (info, decl, insert);
+ if (!elt)
+ return NULL_TREE;
+
+ field = TREE_VALUE (elt);
+
+ if (!field && insert == INSERT)
+ {
+ field = create_field_for_decl (info, decl, get_descriptor_type (info));
+ TREE_VALUE (elt) = field;
+ info->any_descr_created = true;
}
- return (tree) *slot;
+ return field;
}
/* Build or return the field within the non-local frame state that holds
else
type = lang_hooks.types.type_for_mode (Pmode, 1);
- size = GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL));
+ scalar_int_mode mode
+ = as_a <scalar_int_mode> (STACK_SAVEAREA_MODE (SAVE_NONLOCAL));
+ size = GET_MODE_SIZE (mode);
size = size / GET_MODE_SIZE (Pmode);
size = size + 1;
field = make_node (FIELD_DECL);
DECL_NAME (field) = get_identifier ("__nl_goto_buf");
TREE_TYPE (field) = type;
- DECL_ALIGN (field) = TYPE_ALIGN (type);
+ SET_DECL_ALIGN (field, TYPE_ALIGN (type));
TREE_ADDRESSABLE (field) = 1;
insert_field_into_struct (get_frame_type (info), field);
/* 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)
{
static bool
check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
{
- struct cgraph_node *cgn = cgraph_get_node (fndecl);
+ struct cgraph_node *cgn = cgraph_node::get (fndecl);
tree arg;
- for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn); cgn;
+ cgn = next_nested_function (cgn))
{
for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = DECL_CHAIN (arg))
if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
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->mem_refs = pointer_set_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;
+ info->thunk_p = cgn->thunk;
- for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn); cgn;
+ cgn = next_nested_function (cgn))
{
struct nesting_info *sub = create_nesting_tree (cgn);
sub->outer = info;
if (info->context == target_context)
{
- x = build_addr (info->frame_decl, target_context);
+ x = build_addr (info->frame_decl);
+ info->static_chain_added |= 1;
}
else
{
x = get_chain_decl (info);
+ info->static_chain_added |= 2;
for (i = info->outer; i->context != target_context; i = i->outer)
{
tree field = get_chain_field (i);
- x = build_simple_mem_ref (x);
+ x = build_simple_mem_ref_notrap (x);
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, gsi);
}
/* Make sure frame_decl gets created. */
(void) get_frame_type (info);
x = info->frame_decl;
+ info->static_chain_added |= 1;
}
else
{
x = get_chain_decl (info);
+ info->static_chain_added |= 2;
for (i = info->outer; i->context != target_context; i = i->outer)
{
tree field = get_chain_field (i);
- x = build_simple_mem_ref (x);
+ x = build_simple_mem_ref_notrap (x);
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, gsi);
}
- x = build_simple_mem_ref (x);
+ x = build_simple_mem_ref_notrap (x);
}
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
+ TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (field);
return x;
}
/* 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);
(void) get_frame_type (info);
x = info->frame_decl;
i = info;
+ info->static_chain_added |= 1;
}
else
{
x = get_chain_decl (info);
+ info->static_chain_added |= 2;
for (i = info->outer; i->context != target_context; i = i->outer)
{
field = get_chain_field (i);
- x = build_simple_mem_ref (x);
+ x = build_simple_mem_ref_notrap (x);
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
}
- x = build_simple_mem_ref (x);
+ x = build_simple_mem_ref_notrap (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 = build_simple_mem_ref (x);
+ x = build_simple_mem_ref_notrap (x);
/* ??? We should be remapping types as well, surely. */
new_decl = build_decl (DECL_SOURCE_LOCATION (decl),
DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
if ((TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL
- || TREE_CODE (decl) == VAR_DECL)
+ || VAR_P (decl))
&& DECL_BY_REFERENCE (decl))
DECL_BY_REFERENCE (new_decl) = 1;
/* FALLTHRU */
case PARM_DECL:
- if (decl_function_context (t) != info->context)
- {
- tree x;
- wi->changed = true;
+ {
+ tree x, target_context = decl_function_context (t);
- x = get_nonlocal_debug_decl (info, t);
- if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
- {
- tree target_context = decl_function_context (t);
- struct nesting_info *i;
- for (i = info->outer; i->context != target_context; i = i->outer)
- continue;
- x = lookup_field_for_decl (i, t, INSERT);
- x = get_frame_field (info, target_context, x, &wi->gsi);
- if (use_pointer_in_frame (t))
- {
- x = init_tmp_var (info, x, &wi->gsi);
- x = build_simple_mem_ref (x);
- }
- }
+ if (info->context == target_context)
+ break;
- if (wi->val_only)
- {
- if (wi->is_lhs)
- x = save_tmp_var (info, x, &wi->gsi);
- else
+ wi->changed = true;
+
+ if (bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+ x = get_nonlocal_debug_decl (info, t);
+ else
+ {
+ struct nesting_info *i = info;
+ while (i && i->context != target_context)
+ i = i->outer;
+ /* If none of the outer contexts is the target context, this means
+ that the VAR or PARM_DECL is referenced in a wrong context. */
+ if (!i)
+ internal_error ("%s from %s referenced in %s",
+ IDENTIFIER_POINTER (DECL_NAME (t)),
+ IDENTIFIER_POINTER (DECL_NAME (target_context)),
+ IDENTIFIER_POINTER (DECL_NAME (info->context)));
+
+ x = lookup_field_for_decl (i, t, INSERT);
+ x = get_frame_field (info, target_context, x, &wi->gsi);
+ if (use_pointer_in_frame (t))
+ {
x = init_tmp_var (info, x, &wi->gsi);
- }
+ x = build_simple_mem_ref_notrap (x);
+ }
+ }
- *tp = x;
- }
+ if (wi->val_only)
+ {
+ if (wi->is_lhs)
+ x = save_tmp_var (info, x, &wi->gsi);
+ else
+ x = init_tmp_var (info, x, &wi->gsi);
+ }
+
+ *tp = x;
+ }
break;
case LABEL_DECL:
save_context = current_function_decl;
current_function_decl = info->context;
recompute_tree_invariant_for_addr_expr (t);
- current_function_decl = save_context;
/* If the callback converted the address argument in a context
where we only accept variables (and min_invariant, presumably),
if (save_val_only)
*tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
t, &wi->gsi);
+ current_function_decl = save_context;
}
}
break;
{
struct nesting_info *const info = (struct nesting_info *) wi->info;
bool need_chain = false, need_stmts = false;
- tree clause, decl;
+ tree clause, decl, *pdecl;
int dummy;
bitmap new_suppress;
for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
{
+ pdecl = NULL;
switch (OMP_CLAUSE_CODE (clause))
{
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
+ case OMP_CLAUSE_TASK_REDUCTION:
if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
need_stmts = true;
+ if (TREE_CODE (OMP_CLAUSE_DECL (clause)) == MEM_REF)
+ {
+ pdecl = &TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0);
+ if (TREE_CODE (*pdecl) == POINTER_PLUS_EXPR)
+ pdecl = &TREE_OPERAND (*pdecl, 0);
+ if (TREE_CODE (*pdecl) == INDIRECT_REF
+ || TREE_CODE (*pdecl) == ADDR_EXPR)
+ pdecl = &TREE_OPERAND (*pdecl, 0);
+ }
goto do_decl_clause;
case OMP_CLAUSE_LASTPRIVATE:
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:
case OMP_CLAUSE_SHARED:
+ case OMP_CLAUSE_TO_DECLARE:
+ case OMP_CLAUSE_LINK:
+ case OMP_CLAUSE_USE_DEVICE_PTR:
+ case OMP_CLAUSE_USE_DEVICE_ADDR:
+ case OMP_CLAUSE_IS_DEVICE_PTR:
+ case OMP_CLAUSE_DETACH:
do_decl_clause:
- decl = OMP_CLAUSE_DECL (clause);
- if (TREE_CODE (decl) == VAR_DECL
+ if (pdecl == NULL)
+ pdecl = &OMP_CLAUSE_DECL (clause);
+ decl = *pdecl;
+ if (VAR_P (decl)
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
break;
if (decl_function_context (decl) != info->context)
{
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_SHARED)
+ OMP_CLAUSE_SHARED_READONLY (clause) = 0;
bitmap_set_bit (new_suppress, DECL_UID (decl));
- OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
+ *pdecl = get_nonlocal_debug_decl (info, decl);
if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_PRIVATE)
need_chain = true;
}
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_SIMDLEN:
+ case OMP_CLAUSE_PRIORITY:
+ case OMP_CLAUSE_GRAINSIZE:
+ case OMP_CLAUSE_NUM_TASKS:
+ case OMP_CLAUSE_HINT:
+ case OMP_CLAUSE_FILTER:
+ case OMP_CLAUSE_NUM_GANGS:
+ case OMP_CLAUSE_NUM_WORKERS:
+ case OMP_CLAUSE_VECTOR_LENGTH:
+ case OMP_CLAUSE_GANG:
+ case OMP_CLAUSE_WORKER:
+ case OMP_CLAUSE_VECTOR:
+ case OMP_CLAUSE_ASYNC:
+ case OMP_CLAUSE_WAIT:
+ /* Several OpenACC clauses have optional arguments. Check if they
+ are present. */
+ if (OMP_CLAUSE_OPERAND (clause, 0))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
+ &dummy, wi);
+ }
+
+ /* The gang clause accepts two arguments. */
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_GANG
+ && OMP_CLAUSE_GANG_STATIC_EXPR (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op
+ (&OMP_CLAUSE_GANG_STATIC_EXPR (clause), &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;
- convert_nonlocal_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
- &dummy, wi);
+ 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);
+ }
+ /* FALLTHRU */
+ case OMP_CLAUSE_NONTEMPORAL:
+ do_decl_clause_no_supp:
+ /* Like do_decl_clause, but don't add any suppression. */
+ decl = OMP_CLAUSE_DECL (clause);
+ if (VAR_P (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);
+ need_chain = true;
+ }
+ break;
+
+ case OMP_CLAUSE_ALLOCATE:
+ if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op
+ (&OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause), &dummy, wi);
+ }
+ goto do_decl_clause_no_supp;
+
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_TILE:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_MERGEABLE:
+ case OMP_CLAUSE_PROC_BIND:
+ case OMP_CLAUSE_NOGROUP:
+ case OMP_CLAUSE_THREADS:
+ case OMP_CLAUSE_SIMD:
+ case OMP_CLAUSE_DEFAULTMAP:
+ case OMP_CLAUSE_ORDER:
+ case OMP_CLAUSE_SEQ:
+ case OMP_CLAUSE_INDEPENDENT:
+ case OMP_CLAUSE_AUTO:
+ case OMP_CLAUSE_IF_PRESENT:
+ case OMP_CLAUSE_FINALIZE:
+ case OMP_CLAUSE_BIND:
+ case OMP_CLAUSE__CONDTEMP_:
+ case OMP_CLAUSE__SCANTEMP_:
break;
+ /* The following clause belongs to the OpenACC cache directive, which
+ is discarded during gimplification. */
+ case OMP_CLAUSE__CACHE_:
+ /* The following clauses are only allowed in the OpenMP declare simd
+ directive, so not seen here. */
+ case OMP_CLAUSE_UNIFORM:
+ case OMP_CLAUSE_INBRANCH:
+ case OMP_CLAUSE_NOTINBRANCH:
+ /* The following clauses are only allowed on OpenMP cancel and
+ cancellation point directives, which at this point have already
+ been lowered into a function call. */
+ case OMP_CLAUSE_FOR:
+ case OMP_CLAUSE_PARALLEL:
+ case OMP_CLAUSE_SECTIONS:
+ case OMP_CLAUSE_TASKGROUP:
+ /* The following clauses are only added during OMP lowering; nested
+ function decomposition happens before that. */
+ case OMP_CLAUSE__LOOPTEMP_:
+ case OMP_CLAUSE__REDUCTEMP_:
+ case OMP_CLAUSE__SIMDUID_:
+ case OMP_CLAUSE__SIMT_:
+ /* The following clauses are only allowed on OpenACC 'routine'
+ directives, not seen here. */
+ case OMP_CLAUSE_NOHOST:
+ /* Anything else. */
default:
gcc_unreachable ();
}
switch (OMP_CLAUSE_CODE (clause))
{
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
+ case OMP_CLAUSE_TASK_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;
+ if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ = info->context;
+ tree save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+ gimple_seq *seq = &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause);
walk_body (convert_nonlocal_reference_stmt,
- convert_nonlocal_reference_op, info,
- &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
+ convert_nonlocal_reference_op, info, seq);
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (*seq), false);
+ info->new_local_var_chain = NULL;
+ seq = &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause);
walk_body (convert_nonlocal_reference_stmt,
- convert_nonlocal_reference_op, info,
- &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
+ convert_nonlocal_reference_op, info, seq);
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (*seq), false);
+ info->new_local_var_chain = save_local_var_chain;
DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
= old_context;
+ if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ = old_context;
}
break;
case OMP_CLAUSE_LASTPRIVATE:
- walk_body (convert_nonlocal_reference_stmt,
- convert_nonlocal_reference_op, info,
- &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
+ {
+ tree save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+ gimple_seq *seq = &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause);
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info, seq);
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (*seq), false);
+ info->new_local_var_chain = save_local_var_chain;
+ }
+ break;
+
+ case OMP_CLAUSE_LINEAR:
+ {
+ tree save_local_var_chain = info->new_local_var_chain;
+ info->new_local_var_chain = NULL;
+ gimple_seq *seq = &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause);
+ walk_body (convert_nonlocal_reference_stmt,
+ convert_nonlocal_reference_op, info, seq);
+ if (info->new_local_var_chain)
+ declare_vars (info->new_local_var_chain,
+ gimple_seq_first_stmt (*seq), false);
+ info->new_local_var_chain = save_local_var_chain;
+ }
break;
default:
if (domain)
{
t = TYPE_MIN_VALUE (domain);
- if (t && (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL)
+ if (t && (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
&& decl_function_context (t) != info->context)
get_nonlocal_debug_decl (info, t);
t = TYPE_MAX_VALUE (domain);
- if (t && (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL)
+ if (t && (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
&& decl_function_context (t) != info->context)
get_nonlocal_debug_decl (info, t);
}
}
}
-/* Create nonlocal debug decls for nonlocal VLA array bounds for VLAs
- in BLOCK. */
-
-static void
-note_nonlocal_block_vlas (struct nesting_info *info, tree block)
-{
- tree var;
-
- for (var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
- if (TREE_CODE (var) == VAR_DECL
- && variably_modified_type_p (TREE_TYPE (var), NULL)
- && DECL_HAS_VALUE_EXPR_P (var)
- && decl_function_context (var) != info->context)
- note_nonlocal_vla_type (info, TREE_TYPE (var));
-}
-
/* Callback for walk_gimple_stmt. Rewrite all references to VAR and
PARM_DECLs that belong to outer functions. This handles statements
that are not handled via the standard recursion done in
struct nesting_info *info = (struct nesting_info *) wi->info;
tree save_local_var_chain;
bitmap save_suppress;
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
switch (gimple_code (stmt))
{
{
wi->val_only = true;
wi->is_lhs = false;
- *handled_ops_p = true;
+ *handled_ops_p = false;
return NULL_TREE;
}
break;
+ case GIMPLE_OMP_TEAMS:
+ if (!gimple_omp_teams_host (as_a <gomp_teams *> (stmt)))
+ {
+ 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;
+ }
+ /* FALLTHRU */
+
case GIMPLE_OMP_PARALLEL:
case GIMPLE_OMP_TASK:
save_suppress = info->suppress_expansion;
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_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
- case GIMPLE_OMP_TARGET:
+ case GIMPLE_OMP_SCOPE:
save_suppress = info->suppress_expansion;
- convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+ convert_nonlocal_omp_clauses (gimple_omp_scope_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_TEAMS:
+ case GIMPLE_OMP_TASKGROUP:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (gimple_omp_taskgroup_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_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;
- convert_nonlocal_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+ 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_SECTION:
case GIMPLE_OMP_MASTER:
- case GIMPLE_OMP_TASKGROUP:
+ case GIMPLE_OMP_MASKED:
case GIMPLE_OMP_ORDERED:
+ case GIMPLE_OMP_SCAN:
walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
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);
+
+ 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 (VAR_P (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;
*handled_ops_p = false;
return NULL_TREE;
+ case GIMPLE_ASSIGN:
+ if (gimple_clobber_p (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ if (DECL_P (lhs)
+ && !(TREE_STATIC (lhs) || DECL_EXTERNAL (lhs))
+ && decl_function_context (lhs) != info->context)
+ {
+ gsi_replace (gsi, gimple_build_nop (), true);
+ break;
+ }
+ }
+ *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. */
/* 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_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
if ((TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL
- || TREE_CODE (decl) == VAR_DECL)
+ || VAR_P (decl))
&& DECL_BY_REFERENCE (decl))
DECL_BY_REFERENCE (new_decl) = 1;
/* FALLTHRU */
case PARM_DECL:
- if (decl_function_context (t) == info->context)
+ if (t != info->frame_decl && decl_function_context (t) == info->context)
{
/* If we copied a pointer to the frame, then the original decl
is used unchanged in the parent function. */
break;
wi->changed = true;
- x = get_local_debug_decl (info, t, field);
- if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+ if (bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
+ x = get_local_debug_decl (info, t, field);
+ else
x = get_frame_field (info, info->context, field, &wi->gsi);
if (wi->val_only)
save_context = current_function_decl;
current_function_decl = info->context;
recompute_tree_invariant_for_addr_expr (t);
- current_function_decl = save_context;
/* If we are in a context where we only accept values, then
compute the address into a temporary. */
if (save_val_only)
*tp = gsi_gimplify_val ((struct nesting_info *) wi->info,
t, &wi->gsi);
+ current_function_decl = save_context;
}
break;
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)))
- pointer_set_insert (info->mem_refs, tp);
+ info->mem_refs->add (tp);
wi->val_only = save_val_only;
break;
{
struct nesting_info *const info = (struct nesting_info *) wi->info;
bool need_frame = false, need_stmts = false;
- tree clause, decl;
+ tree clause, decl, *pdecl;
int dummy;
bitmap new_suppress;
for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
{
+ pdecl = NULL;
switch (OMP_CLAUSE_CODE (clause))
{
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
+ case OMP_CLAUSE_TASK_REDUCTION:
if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
need_stmts = true;
+ if (TREE_CODE (OMP_CLAUSE_DECL (clause)) == MEM_REF)
+ {
+ pdecl = &TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0);
+ if (TREE_CODE (*pdecl) == POINTER_PLUS_EXPR)
+ pdecl = &TREE_OPERAND (*pdecl, 0);
+ if (TREE_CODE (*pdecl) == INDIRECT_REF
+ || TREE_CODE (*pdecl) == ADDR_EXPR)
+ pdecl = &TREE_OPERAND (*pdecl, 0);
+ }
goto do_decl_clause;
case OMP_CLAUSE_LASTPRIVATE:
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:
case OMP_CLAUSE_SHARED:
+ case OMP_CLAUSE_TO_DECLARE:
+ case OMP_CLAUSE_LINK:
+ case OMP_CLAUSE_USE_DEVICE_PTR:
+ case OMP_CLAUSE_USE_DEVICE_ADDR:
+ case OMP_CLAUSE_IS_DEVICE_PTR:
+ case OMP_CLAUSE_DETACH:
do_decl_clause:
- decl = OMP_CLAUSE_DECL (clause);
- if (TREE_CODE (decl) == VAR_DECL
+ if (pdecl == NULL)
+ pdecl = &OMP_CLAUSE_DECL (clause);
+ decl = *pdecl;
+ if (VAR_P (decl)
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
break;
if (decl_function_context (decl) == info->context
tree field = lookup_field_for_decl (info, decl, NO_INSERT);
if (field)
{
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_SHARED)
+ OMP_CLAUSE_SHARED_READONLY (clause) = 0;
bitmap_set_bit (new_suppress, DECL_UID (decl));
- OMP_CLAUSE_DECL (clause)
- = get_local_debug_decl (info, decl, field);
+ *pdecl = get_local_debug_decl (info, decl, field);
need_frame = true;
}
}
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_SIMDLEN:
+ case OMP_CLAUSE_PRIORITY:
+ case OMP_CLAUSE_GRAINSIZE:
+ case OMP_CLAUSE_NUM_TASKS:
+ case OMP_CLAUSE_HINT:
+ case OMP_CLAUSE_FILTER:
+ case OMP_CLAUSE_NUM_GANGS:
+ case OMP_CLAUSE_NUM_WORKERS:
+ case OMP_CLAUSE_VECTOR_LENGTH:
+ case OMP_CLAUSE_GANG:
+ case OMP_CLAUSE_WORKER:
+ case OMP_CLAUSE_VECTOR:
+ case OMP_CLAUSE_ASYNC:
+ case OMP_CLAUSE_WAIT:
+ /* Several OpenACC clauses have optional arguments. Check if they
+ are present. */
+ if (OMP_CLAUSE_OPERAND (clause, 0))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op (&OMP_CLAUSE_OPERAND (clause, 0),
+ &dummy, wi);
+ }
+
+ /* The gang clause accepts two arguments. */
+ if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_GANG
+ && OMP_CLAUSE_GANG_STATIC_EXPR (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_nonlocal_reference_op
+ (&OMP_CLAUSE_GANG_STATIC_EXPR (clause), &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;
- convert_local_reference_op (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
- wi);
+ 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);
+ }
+ /* FALLTHRU */
+ case OMP_CLAUSE_NONTEMPORAL:
+ do_decl_clause_no_supp:
+ /* Like do_decl_clause, but don't add any suppression. */
+ decl = OMP_CLAUSE_DECL (clause);
+ if (VAR_P (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_ALLOCATE:
+ if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
+ {
+ wi->val_only = true;
+ wi->is_lhs = false;
+ convert_local_reference_op
+ (&OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause), &dummy, wi);
+ }
+ goto do_decl_clause_no_supp;
+
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_TILE:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_MERGEABLE:
+ case OMP_CLAUSE_PROC_BIND:
+ case OMP_CLAUSE_NOGROUP:
+ case OMP_CLAUSE_THREADS:
+ case OMP_CLAUSE_SIMD:
+ case OMP_CLAUSE_DEFAULTMAP:
+ case OMP_CLAUSE_ORDER:
+ case OMP_CLAUSE_SEQ:
+ case OMP_CLAUSE_INDEPENDENT:
+ case OMP_CLAUSE_AUTO:
+ case OMP_CLAUSE_IF_PRESENT:
+ case OMP_CLAUSE_FINALIZE:
+ case OMP_CLAUSE_BIND:
+ case OMP_CLAUSE__CONDTEMP_:
+ case OMP_CLAUSE__SCANTEMP_:
break;
+ /* The following clause belongs to the OpenACC cache directive, which
+ is discarded during gimplification. */
+ case OMP_CLAUSE__CACHE_:
+ /* The following clauses are only allowed in the OpenMP declare simd
+ directive, so not seen here. */
+ case OMP_CLAUSE_UNIFORM:
+ case OMP_CLAUSE_INBRANCH:
+ case OMP_CLAUSE_NOTINBRANCH:
+ /* The following clauses are only allowed on OpenMP cancel and
+ cancellation point directives, which at this point have already
+ been lowered into a function call. */
+ case OMP_CLAUSE_FOR:
+ case OMP_CLAUSE_PARALLEL:
+ case OMP_CLAUSE_SECTIONS:
+ case OMP_CLAUSE_TASKGROUP:
+ /* The following clauses are only added during OMP lowering; nested
+ function decomposition happens before that. */
+ case OMP_CLAUSE__LOOPTEMP_:
+ case OMP_CLAUSE__REDUCTEMP_:
+ case OMP_CLAUSE__SIMDUID_:
+ case OMP_CLAUSE__SIMT_:
+ /* The following clauses are only allowed on OpenACC 'routine'
+ directives, not seen here. */
+ case OMP_CLAUSE_NOHOST:
+ /* Anything else. */
default:
gcc_unreachable ();
}
switch (OMP_CLAUSE_CODE (clause))
{
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
+ case OMP_CLAUSE_TASK_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;
+ if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ = info->context;
walk_body (convert_local_reference_stmt,
convert_local_reference_op, info,
&OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
&OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
= old_context;
+ if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+ = old_context;
}
break;
&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:
break;
}
struct nesting_info *info = (struct nesting_info *) wi->info;
tree save_local_var_chain;
bitmap save_suppress;
- gimple stmt = gsi_stmt (*gsi);
+ char save_static_chain_added;
+ bool frame_decl_added;
+ gimple *stmt = gsi_stmt (*gsi);
switch (gimple_code (stmt))
{
+ case GIMPLE_OMP_TEAMS:
+ if (!gimple_omp_teams_host (as_a <gomp_teams *> (stmt)))
+ {
+ 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;
+ }
+ /* FALLTHRU */
+
case GIMPLE_OMP_PARALLEL:
case GIMPLE_OMP_TASK:
save_suppress = info->suppress_expansion;
+ frame_decl_added = false;
if (convert_local_omp_clauses (gimple_omp_taskreg_clauses_ptr (stmt),
wi))
{
- tree c;
+ tree c = build_omp_clause (gimple_location (stmt),
+ OMP_CLAUSE_SHARED);
(void) get_frame_type (info);
- c = build_omp_clause (gimple_location (stmt),
- OMP_CLAUSE_SHARED);
OMP_CLAUSE_DECL (c) = info->frame_decl;
OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
gimple_omp_taskreg_set_clauses (stmt, c);
+ info->static_chain_added |= 4;
+ frame_decl_added = true;
}
save_local_var_chain = info->new_local_var_chain;
+ save_static_chain_added = info->static_chain_added;
info->new_local_var_chain = NULL;
+ info->static_chain_added = 0;
walk_body (convert_local_reference_stmt, convert_local_reference_op, info,
gimple_omp_body_ptr (stmt));
+ if ((info->static_chain_added & 4) != 0 && !frame_decl_added)
+ {
+ tree c = build_omp_clause (gimple_location (stmt),
+ OMP_CLAUSE_SHARED);
+ (void) get_frame_type (info);
+ OMP_CLAUSE_DECL (c) = info->frame_decl;
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+ info->static_chain_added |= 4;
+ gimple_omp_taskreg_set_clauses (stmt, c);
+ }
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;
+ info->static_chain_added |= save_static_chain_added;
break;
case GIMPLE_OMP_FOR:
save_suppress = info->suppress_expansion;
convert_local_omp_clauses (gimple_omp_for_clauses_ptr (stmt), wi);
- walk_gimple_omp_for (stmt, convert_local_reference_stmt,
+ 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_ptr (stmt));
info->suppress_expansion = save_suppress;
break;
- case GIMPLE_OMP_TARGET:
+ case GIMPLE_OMP_SCOPE:
save_suppress = info->suppress_expansion;
- convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi);
+ convert_local_omp_clauses (gimple_omp_scope_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_TEAMS:
+ case GIMPLE_OMP_TASKGROUP:
save_suppress = info->suppress_expansion;
- convert_local_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi);
+ convert_local_omp_clauses (gimple_omp_taskgroup_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_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;
+ frame_decl_added = false;
+ if (convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi))
+ {
+ tree c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP);
+ (void) get_frame_type (info);
+ 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);
+ info->static_chain_added |= 4;
+ frame_decl_added = true;
+ }
+
+ save_local_var_chain = info->new_local_var_chain;
+ save_static_chain_added = info->static_chain_added;
+ info->new_local_var_chain = NULL;
+ info->static_chain_added = 0;
+
+ walk_body (convert_local_reference_stmt, convert_local_reference_op, info,
+ gimple_omp_body_ptr (stmt));
+
+ if ((info->static_chain_added & 4) != 0 && !frame_decl_added)
+ {
+ tree c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP);
+ (void) get_frame_type (info);
+ 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);
+ info->static_chain_added |= 4;
+ }
+
+ 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;
+ info->static_chain_added |= save_static_chain_added;
+ break;
+
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_MASTER:
- case GIMPLE_OMP_TASKGROUP:
+ case GIMPLE_OMP_MASKED:
case GIMPLE_OMP_ORDERED:
+ case GIMPLE_OMP_SCAN:
walk_body (convert_local_reference_stmt, convert_local_reference_op,
info, gimple_omp_body_ptr (stmt));
break;
if (gimple_clobber_p (stmt))
{
tree lhs = gimple_assign_lhs (stmt);
- if (!use_pointer_in_frame (lhs)
+ if (DECL_P (lhs)
+ && decl_function_context (lhs) == info->context
+ && !use_pointer_in_frame (lhs)
&& lookup_field_for_decl (info, lhs, NO_INSERT))
{
gsi_replace (gsi, gimple_build_nop (), true);
*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 (VAR_P (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;
- gimple stmt = gsi_stmt (*gsi);
+ 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, gsi);
- x = build_addr (x, target_context);
+ x = build_addr (x);
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);
+ 2, build_addr (new_label), x);
gsi_replace (gsi, call, false);
/* We have handled all of STMT's operands, no need to keep going. */
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;
gsi_prev (&tmp_gsi);
if (gsi_end_p (tmp_gsi) || gimple_stmt_may_fallthru (gsi_stmt (tmp_gsi)))
{
- gimple stmt = gimple_build_goto (label);
+ gimple *stmt = gimple_build_goto (label);
gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
}
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;
+ bool descr;
+ gcall *call;
*walk_subtrees = 0;
switch (TREE_CODE (t))
we need to insert the trampoline. */
for (i = info; i->context != target_context; i = i->outer)
continue;
- x = lookup_tramp_for_decl (i, decl, INSERT);
+
+ /* Decide whether to generate a descriptor or a trampoline. */
+ descr = FUNC_ADDR_BY_DESCRIPTOR (t) && !flag_trampolines;
+
+ if (descr)
+ x = lookup_descr_for_decl (i, decl, INSERT);
+ else
+ x = lookup_tramp_for_decl (i, decl, INSERT);
/* Compute the address of the field holding the trampoline. */
x = get_frame_field (info, target_context, x, &wi->gsi);
- x = build_addr (x, target_context);
+ x = build_addr (x);
x = gsi_gimplify_val (info, x, &wi->gsi);
/* Do machine-specific ugliness. Normally this will involve
computing extra alignment, but it can really be anything. */
- builtin = builtin_decl_implicit (BUILT_IN_ADJUST_TRAMPOLINE);
+ if (descr)
+ builtin = builtin_decl_implicit (BUILT_IN_ADJUST_DESCRIPTOR);
+ else
+ 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);
struct walk_stmt_info *wi)
{
struct nesting_info *info = (struct nesting_info *) wi->info;
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
switch (gimple_code (stmt))
{
break;
}
+ case GIMPLE_OMP_TEAMS:
+ if (!gimple_omp_teams_host (as_a <gomp_teams *> (stmt)))
+ {
+ *handled_ops_p = false;
+ return NULL_TREE;
+ }
+ goto do_parallel;
+
+ 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:
+ do_parallel:
{
- tree save_local_var_chain;
+ tree save_local_var_chain = info->new_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;
+ char save_static_chain_added = info->static_chain_added;
+ info->static_chain_added = 0;
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);
+ for (int i = 0; i < 2; i++)
+ {
+ tree c, decl;
+ if ((info->static_chain_added & (1 << i)) == 0)
+ continue;
+ decl = i ? get_chain_decl (info) : info->frame_decl;
+ /* Don't add CHAIN.* or FRAME.* twice. */
+ for (c = gimple_omp_taskreg_clauses (stmt);
+ c;
+ c = OMP_CLAUSE_CHAIN (c))
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
+ && OMP_CLAUSE_DECL (c) == decl)
+ break;
+ if (c == NULL && gimple_code (stmt) != GIMPLE_OMP_TARGET)
+ {
+ c = build_omp_clause (gimple_location (stmt),
+ i ? OMP_CLAUSE_FIRSTPRIVATE
+ : OMP_CLAUSE_SHARED);
+ OMP_CLAUSE_DECL (c) = decl;
+ OMP_CLAUSE_CHAIN (c) = gimple_omp_taskreg_clauses (stmt);
+ gimple_omp_taskreg_set_clauses (stmt, c);
+ }
+ else 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->new_local_var_chain = save_local_var_chain;
+ info->static_chain_added |= save_static_chain_added;
}
break;
default:
*handled_ops_p = false;
return NULL_TREE;
- break;
}
*handled_ops_p = true;
tree decl, target_context;
char save_static_chain_added;
int i;
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
switch (gimple_code (stmt))
{
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));
+ struct nesting_info *i = info;
+ while (i && i->context != target_context)
+ i = i->outer;
+ /* If none of the outer contexts is the target context, this means
+ that the function is called in a wrong context. */
+ if (!i)
+ internal_error ("%s from %s called in %s",
+ IDENTIFIER_POINTER (DECL_NAME (decl)),
+ IDENTIFIER_POINTER (DECL_NAME (target_context)),
+ IDENTIFIER_POINTER (DECL_NAME (info->context)));
+
+ 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_TEAMS:
+ if (!gimple_omp_teams_host (as_a <gomp_teams *> (stmt)))
+ {
+ walk_body (convert_gimple_call, NULL, info,
+ gimple_omp_body_ptr (stmt));
+ break;
+ }
+ /* FALLTHRU */
+
case GIMPLE_OMP_PARALLEL:
case GIMPLE_OMP_TASK:
save_static_chain_added = info->static_chain_added;
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_ptr (stmt));
case GIMPLE_OMP_SECTIONS:
case GIMPLE_OMP_SECTION:
case GIMPLE_OMP_SINGLE:
- case GIMPLE_OMP_TARGET:
- case GIMPLE_OMP_TEAMS:
+ case GIMPLE_OMP_SCOPE:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_MASKED:
case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
+ case GIMPLE_OMP_SCAN:
case GIMPLE_OMP_CRITICAL:
walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
break;
struct nesting_info *n;
/* 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)
{
+ if (n->thunk_p)
+ continue;
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))
chain_count += DECL_STATIC_CHAIN (decl);
}
+ FOR_EACH_NEST_INFO (n, root)
+ if (n->thunk_p)
+ {
+ tree decl = n->context;
+ tree alias = thunk_info::get (cgraph_node::get (decl))->alias;
+ DECL_STATIC_CHAIN (decl) = DECL_STATIC_CHAIN (alias);
+ }
+
/* Walk the functions and perform transformations. Note that these
transformations can induce new uses of the static chain, which in turn
require re-examining all users of the decl. */
FOR_EACH_NEST_INFO (n, root)
{
+ if (n->thunk_p)
+ continue;
tree decl = n->context;
walk_function (convert_tramp_reference_stmt,
convert_tramp_reference_op, n);
walk_function (convert_gimple_call, NULL, n);
chain_count += DECL_STATIC_CHAIN (decl);
}
+
+ FOR_EACH_NEST_INFO (n, root)
+ if (n->thunk_p)
+ {
+ tree decl = n->context;
+ tree alias = thunk_info::get (cgraph_node::get (decl))->alias;
+ DECL_STATIC_CHAIN (decl) = DECL_STATIC_CHAIN (alias);
+ }
}
while (chain_count != old_chain_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;
return new_decl;
}
- if (TREE_CODE (decl) == VAR_DECL
+ if (VAR_P (decl)
|| TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL)
return decl;
{
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;
}
remap_vla_decls (subblock, root);
for (var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
- if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
+ if (VAR_P (var) && DECL_HAS_VALUE_EXPR_P (var))
{
val = DECL_VALUE_EXPR (var);
type = TREE_TYPE (var);
&& variably_modified_type_p (type, NULL)))
continue;
- if (pointer_map_contains (root->var_map, TREE_OPERAND (val, 0))
+ if (root->var_map->get (TREE_OPERAND (val, 0))
|| walk_tree (&type, contains_remapped_vars, root, 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 (; var; var = DECL_CHAIN (var))
- if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
+ if (VAR_P (var) && DECL_HAS_VALUE_EXPR_P (var))
{
struct nesting_info *i;
tree newt, context;
- void **slot;
val = DECL_VALUE_EXPR (var);
type = TREE_TYPE (var);
&& variably_modified_type_p (type, NULL)))
continue;
- slot = pointer_map_contains (root->var_map, TREE_OPERAND (val, 0));
+ tree *slot = root->var_map->get (TREE_OPERAND (val, 0));
if (!slot && !walk_tree (&type, contains_remapped_vars, root, NULL))
continue;
SET_DECL_VALUE_EXPR (var, val);
}
- pointer_map_destroy (id.cb.decl_map);
+ delete id.cb.decl_map;
+}
+
+/* Fixup VLA decls in BLOCK and subblocks if remapped variables are
+ involved. */
+
+static void
+fixup_vla_decls (tree block)
+{
+ for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
+ if (VAR_P (var) && DECL_HAS_VALUE_EXPR_P (var))
+ {
+ tree val = DECL_VALUE_EXPR (var);
+
+ if (!(TREE_CODE (val) == INDIRECT_REF
+ && VAR_P (TREE_OPERAND (val, 0))
+ && DECL_HAS_VALUE_EXPR_P (TREE_OPERAND (val, 0))))
+ continue;
+
+ /* Fully expand value expressions. This avoids having debug variables
+ only referenced from them and that can be swept during GC. */
+ val = build1 (INDIRECT_REF, TREE_TYPE (val),
+ DECL_VALUE_EXPR (TREE_OPERAND (val, 0)));
+ SET_DECL_VALUE_EXPR (var, val);
+ }
+
+ for (tree sub = BLOCK_SUBBLOCKS (block); sub; sub = BLOCK_CHAIN (sub))
+ fixup_vla_decls (sub);
}
/* Fold the MEM_REF *E. */
-static bool
-fold_mem_refs (const void *e, void *data ATTRIBUTE_UNUSED)
+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
- various walking passes -- lay out the types and decls, generate code
- to initialize the frame decl, store critical expressions in the
- struct function for rtl to find. */
+/* Given DECL, a nested function, build an initialization call for FIELD,
+ the trampoline or descriptor for DECL, using FUNC as the function. */
+
+static gcall *
+build_init_call_stmt (struct nesting_info *info, tree decl, tree field,
+ tree func)
+{
+ tree arg1, arg2, arg3, x;
+
+ gcc_assert (DECL_STATIC_CHAIN (decl));
+ arg3 = build_addr (info->frame_decl);
+
+ arg2 = build_addr (decl);
+
+ x = build3 (COMPONENT_REF, TREE_TYPE (field),
+ info->frame_decl, field, NULL_TREE);
+ arg1 = build_addr (x);
+
+ return gimple_build_call (func, 3, arg1, arg2, arg3);
+}
+
+/* Do "everything else" to clean up or complete state collected by the various
+ walking passes -- create a field to hold the frame base address, lay out the
+ types and decls, generate code to initialize the frame decl, store critical
+ expressions in the struct function for rtl to find. */
static void
finalize_nesting_tree_1 (struct nesting_info *root)
{
- gimple_seq stmt_list;
- gimple stmt;
+ gimple_seq stmt_list = NULL;
+ gimple *stmt;
tree context = root->context;
struct function *sf;
- stmt_list = NULL;
+ if (root->thunk_p)
+ return;
/* If we created a non-local frame type or decl, we need to lay them
out at this time. */
if (root->frame_type)
{
+ /* Debugging information needs to compute the frame base address of the
+ parent frame out of the static chain from the nested frame.
+
+ The static chain is the address of the FRAME record, so one could
+ imagine it would be possible to compute the frame base address just
+ adding a constant offset to this address. Unfortunately, this is not
+ possible: if the FRAME object has alignment constraints that are
+ stronger than the stack, then the offset between the frame base and
+ the FRAME object will be dynamic.
+
+ What we do instead is to append a field to the FRAME object that holds
+ the frame base address: then debug info just has to fetch this
+ field. */
+
+ /* Debugging information will refer to the CFA as the frame base
+ address: we will do the same here. */
+ const tree frame_addr_fndecl
+ = builtin_decl_explicit (BUILT_IN_DWARF_CFA);
+
+ /* Create a field in the FRAME record to hold the frame base address for
+ this stack frame. Since it will be used only by the debugger, put it
+ at the end of the record in order not to shift all other offsets. */
+ tree fb_decl = make_node (FIELD_DECL);
+
+ DECL_NAME (fb_decl) = get_identifier ("FRAME_BASE.PARENT");
+ TREE_TYPE (fb_decl) = ptr_type_node;
+ TREE_ADDRESSABLE (fb_decl) = 1;
+ DECL_CONTEXT (fb_decl) = root->frame_type;
+ TYPE_FIELDS (root->frame_type) = chainon (TYPE_FIELDS (root->frame_type),
+ fb_decl);
+
/* In some cases the frame type will trigger the -Wpadded warning.
This is not helpful; suppress it. */
int save_warn_padded = warn_padded;
- tree *adjust;
-
warn_padded = 0;
layout_type (root->frame_type);
warn_padded = save_warn_padded;
layout_decl (root->frame_decl, 0);
- /* Remove root->frame_decl from root->new_local_var_chain, so
- that we can declare it also in the lexical blocks, which
- helps ensure virtual regs that end up appearing in its RTL
- expression get substituted in instantiate_virtual_regs(). */
- for (adjust = &root->new_local_var_chain;
- *adjust != root->frame_decl;
- adjust = &DECL_CHAIN (*adjust))
- gcc_assert (DECL_CHAIN (*adjust));
- *adjust = DECL_CHAIN (*adjust);
-
- DECL_CHAIN (root->frame_decl) = NULL_TREE;
+ /* Initialize the frame base address field. If the builtin we need is
+ not available, set it to NULL so that debugging information does not
+ reference junk. */
+ tree fb_ref = build3 (COMPONENT_REF, TREE_TYPE (fb_decl),
+ root->frame_decl, fb_decl, NULL_TREE);
+ tree fb_tmp;
+
+ if (frame_addr_fndecl != NULL_TREE)
+ {
+ gcall *fb_gimple = gimple_build_call (frame_addr_fndecl, 1,
+ integer_zero_node);
+ gimple_stmt_iterator gsi = gsi_last (stmt_list);
+
+ fb_tmp = init_tmp_var_with_call (root, &gsi, fb_gimple);
+ }
+ else
+ fb_tmp = build_int_cst (TREE_TYPE (fb_ref), 0);
+ gimple_seq_add_stmt (&stmt_list,
+ gimple_build_assign (fb_ref, fb_tmp));
+
declare_vars (root->frame_decl,
gimple_seq_first_stmt (gimple_body (context)), true);
}
- /* If any parameters were referenced non-locally, then we need to
- insert a copy. Likewise, if any variables were referenced by
- pointer, we need to initialize the address. */
+ /* If any parameters were referenced non-locally, then we need to insert
+ a copy or a pointer. */
if (root->any_parm_remapped)
{
tree p;
continue;
if (use_pointer_in_frame (p))
- x = build_addr (p, context);
+ x = build_addr (p);
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);
}
}
struct nesting_info *i;
for (i = root->inner; i ; i = i->next)
{
- tree arg1, arg2, arg3, x, field;
+ tree field, x;
field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
if (!field)
continue;
- gcc_assert (DECL_STATIC_CHAIN (i->context));
- arg3 = build_addr (root->frame_decl, context);
+ x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE);
+ stmt = build_init_call_stmt (root, i->context, field, x);
+ gimple_seq_add_stmt (&stmt_list, stmt);
+ }
+ }
- arg2 = build_addr (i->context, context);
+ /* If descriptors were created, then we need to initialize them. */
+ if (root->any_descr_created)
+ {
+ struct nesting_info *i;
+ for (i = root->inner; i ; i = i->next)
+ {
+ tree field, x;
- x = build3 (COMPONENT_REF, TREE_TYPE (field),
- root->frame_decl, field, NULL_TREE);
- arg1 = build_addr (x, context);
+ field = lookup_descr_for_decl (root, i->context, NO_INSERT);
+ if (!field)
+ continue;
- x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE);
- stmt = gimple_build_call (x, 3, arg1, arg2, arg3);
+ x = builtin_decl_implicit (BUILT_IN_INIT_DESCRIPTOR);
+ stmt = build_init_call_stmt (root, i->context, field, x);
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);
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 = DECL_CHAIN (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
= chainon (BLOCK_VARS (DECL_INITIAL (root->context)),
root->debug_var_chain);
}
+ else
+ fixup_vla_decls (DECL_INITIAL (root->context));
/* Fold the rewritten MEM_REF trees. */
- pointer_set_traverse (root->mem_refs, fold_mem_refs, NULL);
+ 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_get_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)
+ if (nested_function_info::get (node)->origin)
{
- cgraph_unnest_node (node);
- cgraph_finalize_function (root->context, true);
+ unnest_function (node);
+ if (!root->thunk_p)
+ 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);
- pointer_set_destroy (node->mem_refs);
+ delete node->var_map;
+ delete node->field_map;
+ delete node->mem_refs;
free (node);
node = next;
}
struct cgraph_node *iter;
if (!gimple_body (root->decl))
gimplify_function_tree (root->decl);
- for (iter = root->nested; iter; iter = iter->next_nested)
- gimplify_all_functions (iter);
+ for (iter = first_nested_function (root); iter;
+ iter = next_nested_function (iter))
+ if (!iter->thunk)
+ gimplify_all_functions (iter);
}
/* Main entry point for this pass. Process FNDECL and all of its nested
struct nesting_info *root;
/* If there are no nested functions, there's nothing to do. */
- cgn = cgraph_get_node (fndecl);
- if (!cgn->nested)
+ cgn = cgraph_node::get (fndecl);
+ if (!first_nested_function (cgn))
return;
gimplify_all_functions (cgn);
- dump_file = dump_begin (TDI_nested, &dump_flags);
+ set_dump_file (dump_begin (TDI_nested, &dump_flags));
if (dump_file)
fprintf (dump_file, "\n;; Function %s\n\n",
lang_hooks.decl_printable_name (fndecl, 2));
if (dump_file)
{
dump_end (TDI_nested, dump_file);
- dump_file = NULL;
+ set_dump_file (NULL);
}
}