The implementation here is much more direct. Everything that can be
referenced by an inner function is a member of an explicitly created
- structure herein called the "nonlocal frame struct". The incomming
+ structure herein called the "nonlocal frame struct". The incoming
static chain for a nested function is a pointer to this struct in
the parent. In this way, we settle on known offsets from a known
base, and so are decoupled from the logic that places objects in the
{
tree tmp_var;
-#if defined ENABLE_CHECKING
- /* If the type is an array or a type which must be created by the
+ /* If the type is of variable size or a type which must be created by the
frontend, something is wrong. Note that we explicitly allow
incomplete types here, since we create them ourselves here. */
- if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type))
- abort ();
- if (TYPE_SIZE_UNIT (type)
- && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
- abort ();
-#endif
+ gcc_assert (!TREE_ADDRESSABLE (type));
+ gcc_assert (!TYPE_SIZE_UNIT (type)
+ || TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
tmp_var = create_tmp_var_raw (type, prefix);
DECL_CONTEXT (tmp_var) = info->context;
TREE_CHAIN (tmp_var) = info->new_local_var_chain;
+ DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
info->new_local_var_chain = tmp_var;
return tmp_var;
/* Take the address of EXP. Mark it for addressability as necessary. */
-static tree
+tree
build_addr (tree exp)
{
tree base = exp;
- while (TREE_CODE (base) == COMPONENT_REF || TREE_CODE (base) == ARRAY_REF)
+
+ while (TREE_CODE (base) == REALPART_EXPR || TREE_CODE (base) == IMAGPART_EXPR
+ || handled_component_p (base))
base = TREE_OPERAND (base, 0);
+
if (DECL_P (base))
TREE_ADDRESSABLE (base) = 1;
slot = htab_find_slot (info->var_map, &dummy, insert);
if (!slot)
{
- if (insert == INSERT)
- abort ();
+ gcc_assert (insert != INSERT);
return NULL;
}
elt = *slot;
/* Note that this variable is *not* entered into any BIND_EXPR;
the construction of this variable is handled specially in
- expand_function_start and initialize_inlined_parameters. */
- decl = create_tmp_var_raw (type, "CHAIN");
+ expand_function_start and initialize_inlined_parameters.
+ Note also that it's represented as a parameter. This is more
+ close to the truth, since the initial value does come from
+ the caller. */
+ decl = build_decl (PARM_DECL, create_tmp_var_name ("CHAIN"), type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_USED (decl) = 1;
DECL_CONTEXT (decl) = info->context;
- decl->decl.seen_in_bind_expr = 1;
-
- /* The initialization of CHAIN is not visible to the tree-ssa
- analyzers and optimizers. Thus we do not want to issue
- warnings for CHAIN. */
- TREE_NO_WARNING (decl) = 1;
+ DECL_ARG_TYPE (decl) = type;
/* Tell tree-inline.c that we never write to this variable, so
it can copy-prop the replacement value immediately. */
/* Similarly, but only do so to force EXP to satisfy is_gimple_val. */
static tree
-gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
{
if (is_gimple_val (exp))
return exp;
align = STACK_BOUNDARY;
}
- t = build_index_type (build_int_2 (size - 1, 0));
+ t = build_index_type (build_int_cst (NULL_TREE, size - 1));
t = build_array_type (char_type_node, t);
t = build_decl (FIELD_DECL, get_identifier ("__data"), t);
DECL_ALIGN (t) = align;
slot = htab_find_slot (info->var_map, &dummy, insert);
if (!slot)
{
- if (insert == INSERT)
- abort ();
+ gcc_assert (insert != INSERT);
return NULL;
}
elt = *slot;
/* For __builtin_nonlocal_goto, we need N words. The first is the
frame pointer, the rest is for the target's stack pointer save
- area. The number of words is controled by STACK_SAVEAREA_MODE;
+ area. The number of words is controlled by STACK_SAVEAREA_MODE;
not the best interface, but it'll do for now. */
if (Pmode == ptr_mode)
type = ptr_type_node;
size = size / GET_MODE_SIZE (Pmode);
size = size + 1;
- type = build_array_type (type, build_index_type (build_int_2 (size, 0)));
+ type = build_array_type
+ (type, build_index_type (build_int_cst (NULL_TREE, size)));
field = make_node (FIELD_DECL);
DECL_NAME (field) = get_identifier ("__nl_goto_buf");
break;
case CATCH_EXPR:
walk_stmts (wi, &CATCH_BODY (t));
+ break;
case EH_FILTER_EXPR:
walk_stmts (wi, &EH_FILTER_FAILURE (t));
break;
tree field = get_chain_field (i);
x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
- x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+ x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, tsi);
}
}
tree field = get_chain_field (i);
x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
- x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+ x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
x = init_tmp_var (info, x, tsi);
}
x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
}
- x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+ x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
return x;
}
where we only accept variables (and min_invariant, presumably),
then compute the address into a temporary. */
if (save_val_only)
- *tp = gimplify_val (wi->info, t, &wi->tsi);
+ *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
}
}
break;
- case COMPONENT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
- wi->val_only = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
- wi->val_only = true;
- break;
-
+ case COMPONENT_REF:
case ARRAY_REF:
- wi->val_only = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
- wi->val_only = true;
- walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL);
- break;
-
+ case ARRAY_RANGE_REF:
case BIT_FIELD_REF:
- wi->val_only = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
+ /* Go down this entire nest and just look at the final prefix and
+ anything that describes the references. Otherwise, we lose track
+ of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */
wi->val_only = true;
- walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL);
- walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, NULL);
+ for (; handled_component_p (t)
+ || TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR;
+ tp = &TREE_OPERAND (t, 0), t = *tp)
+ {
+ if (TREE_CODE (t) == COMPONENT_REF)
+ walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+ NULL);
+ else if (TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi,
+ NULL);
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
+ NULL);
+ }
+ }
+ wi->val_only = false;
+ walk_tree (tp, convert_nonlocal_reference, wi, NULL);
break;
default:
- if (!DECL_P (t) && !TYPE_P (t))
+ if (!IS_TYPE_OR_DECL_P (t))
{
*walk_subtrees = 1;
wi->val_only = true;
{
struct walk_stmt_info *wi = data;
struct nesting_info *info = wi->info;
- tree t = *tp, field, x, y;
+ tree t = *tp, field, x;
switch (TREE_CODE (t))
{
/* If we are in a context where we only accept values, then
compute the address into a temporary. */
if (save_val_only)
- *tp = gimplify_val (wi->info, t, &wi->tsi);
+ *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
}
}
break;
- case CALL_EXPR:
- *walk_subtrees = 1;
-
- /* Ready for some fun? We need to recognize
- __builtin_stack_alloc (&x, n)
- and insert
- FRAME.x = &x
- after that. X should have use_pointer_in_frame set. We can't
- do this any earlier, since we can't meaningfully evaluate &x. */
-
- x = get_callee_fndecl (t);
- if (!x || DECL_BUILT_IN_CLASS (x) != BUILT_IN_NORMAL)
- break;
- if (DECL_FUNCTION_CODE (x) != BUILT_IN_STACK_ALLOC)
- break;
- t = TREE_VALUE (TREE_OPERAND (t, 1));
- if (TREE_CODE (t) != ADDR_EXPR)
- abort ();
- t = TREE_OPERAND (t, 0);
- if (TREE_CODE (t) != VAR_DECL)
- abort ();
- field = lookup_field_for_decl (info, t, NO_INSERT);
- if (!field)
- break;
- if (!use_pointer_in_frame (t))
- abort ();
-
- x = build_addr (t);
- y = get_frame_field (info, info->context, field, &wi->tsi);
- x = build (MODIFY_EXPR, void_type_node, y, x);
- SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
- tsi_link_after (&wi->tsi, x, TSI_SAME_STMT);
- break;
-
- case COMPONENT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
- wi->val_only = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
- wi->val_only = true;
- break;
-
+ case COMPONENT_REF:
case ARRAY_REF:
- wi->val_only = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
- wi->val_only = true;
- walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL);
- break;
-
+ case ARRAY_RANGE_REF:
case BIT_FIELD_REF:
- wi->val_only = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
+ /* Go down this entire nest and just look at the final prefix and
+ anything that describes the references. Otherwise, we lose track
+ of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */
wi->val_only = true;
- walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL);
- walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, NULL);
+ for (; handled_component_p (t)
+ || TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR;
+ tp = &TREE_OPERAND (t, 0), t = *tp)
+ {
+ if (TREE_CODE (t) == COMPONENT_REF)
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+ NULL);
+ else if (TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi,
+ NULL);
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
+ NULL);
+ walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
+ NULL);
+ }
+ }
+ wi->val_only = false;
+ walk_tree (tp, convert_local_reference, wi, NULL);
break;
default:
- if (!DECL_P (t) && !TYPE_P (t))
+ if (!IS_TYPE_OR_DECL_P (t))
{
*walk_subtrees = 1;
wi->val_only = true;
/* The original user label may also be use for a normal goto, therefore
we must create a new label that will actually receive the abnormal
control transfer. This new label will be marked LABEL_NONLOCAL; this
- mark will trigger proper behaviour in the cfg, as well as cause the
+ mark will trigger proper behavior in the cfg, as well as cause the
(hairy target-specific) non-local goto receiver code to be generated
when we expand rtl. */
new_label = create_artificial_label ();
field = get_nl_goto_field (i);
x = get_frame_field (info, target_context, field, &wi->tsi);
x = build_addr (x);
- x = gimplify_val (info, x, &wi->tsi);
+ x = tsi_gimplify_val (info, x, &wi->tsi);
arg = tree_cons (NULL, x, NULL);
x = build_addr (new_label);
arg = tree_cons (NULL, x, arg);
/* Compute the address of the field holding the trampoline. */
x = get_frame_field (info, target_context, x, &wi->tsi);
x = build_addr (x);
- x = gimplify_val (info, x, &wi->tsi);
+ x = tsi_gimplify_val (info, x, &wi->tsi);
arg = tree_cons (NULL, x, NULL);
/* Do machine-specific ugliness. Normally this will involve
break;
default:
- if (!DECL_P (t) && !TYPE_P (t))
+ if (!IS_TYPE_OR_DECL_P (t))
*walk_subtrees = 1;
break;
}
case RETURN_EXPR:
case MODIFY_EXPR:
- /* Only return and modify may contain calls. */
+ case WITH_SIZE_EXPR:
+ /* Only return modify and with_size_expr may contain calls. */
*walk_subtrees = 1;
break;
if (root->outer && !root->chain_decl && !root->chain_field)
DECL_NO_STATIC_CHAIN (root->context) = 1;
else
- {
-#ifdef ENABLE_CHECKING
- if (DECL_NO_STATIC_CHAIN (root->context))
- abort ();
-#endif
- }
+ gcc_assert (!DECL_NO_STATIC_CHAIN (root->context));
root = root->next;
}
tree stmt_list = NULL;
tree context = root->context;
struct function *sf;
+ struct cgraph_node *node;
/* If we created a non-local frame type or decl, we need to lay them
out at this time. */
x = p;
y = build (COMPONENT_REF, TREE_TYPE (field),
- root->frame_decl, field);
+ root->frame_decl, field, NULL_TREE);
x = build (MODIFY_EXPR, TREE_TYPE (field), y, x);
append_to_statement_list (x, &stmt_list);
}
from chain_decl. */
if (root->chain_field)
{
- tree x;
- x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
- root->frame_decl, root->chain_field);
+ tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
+ root->frame_decl, root->chain_field, NULL_TREE);
x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
append_to_statement_list (x, &stmt_list);
}
arg = tree_cons (NULL, x, arg);
x = build (COMPONENT_REF, TREE_TYPE (field),
- root->frame_decl, field);
+ root->frame_decl, field, NULL_TREE);
x = build_addr (x);
arg = tree_cons (NULL, x, arg);
sf->has_nonlocal_label = 1;
}
- /* Make sure all new local variables get insertted into the
+ /* Make sure all new local variables get inserted into the
proper BIND_EXPR. */
if (root->new_local_var_chain)
declare_tmp_vars (root->new_local_var_chain,
/* Dump the translated tree function. */
dump_function (TDI_nested, root->context);
+ node = cgraph_node (root->context);
+
+ /* For nested functions update the cgraph to reflect unnesting.
+ We also delay finalizing of these functions up to this point. */
+ if (node->origin)
+ {
+ cgraph_unnest_node (cgraph_node (root->context));
+ cgraph_finalize_function (root->context, true);
+ }
}
static void