1404b540aSrobert /* Nested function decomposition for trees.
2404b540aSrobert Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
3404b540aSrobert
4404b540aSrobert This file is part of GCC.
5404b540aSrobert
6404b540aSrobert GCC is free software; you can redistribute it and/or modify
7404b540aSrobert it under the terms of the GNU General Public License as published by
8404b540aSrobert the Free Software Foundation; either version 2, or (at your option)
9404b540aSrobert any later version.
10404b540aSrobert
11404b540aSrobert GCC is distributed in the hope that it will be useful,
12404b540aSrobert but WITHOUT ANY WARRANTY; without even the implied warranty of
13404b540aSrobert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14404b540aSrobert GNU General Public License for more details.
15404b540aSrobert
16404b540aSrobert You should have received a copy of the GNU General Public License
17404b540aSrobert along with GCC; see the file COPYING. If not, write to
18404b540aSrobert the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19404b540aSrobert Boston, MA 02110-1301, USA. */
20404b540aSrobert
21404b540aSrobert #include "config.h"
22404b540aSrobert #include "system.h"
23404b540aSrobert #include "coretypes.h"
24404b540aSrobert #include "tm.h"
25404b540aSrobert #include "tree.h"
26404b540aSrobert #include "rtl.h"
27404b540aSrobert #include "tm_p.h"
28404b540aSrobert #include "function.h"
29404b540aSrobert #include "tree-dump.h"
30404b540aSrobert #include "tree-inline.h"
31404b540aSrobert #include "tree-gimple.h"
32404b540aSrobert #include "tree-iterator.h"
33404b540aSrobert #include "tree-flow.h"
34404b540aSrobert #include "cgraph.h"
35404b540aSrobert #include "expr.h"
36404b540aSrobert #include "langhooks.h"
37404b540aSrobert #include "ggc.h"
38404b540aSrobert
39404b540aSrobert
40404b540aSrobert /* The object of this pass is to lower the representation of a set of nested
41404b540aSrobert functions in order to expose all of the gory details of the various
42404b540aSrobert nonlocal references. We want to do this sooner rather than later, in
43404b540aSrobert order to give us more freedom in emitting all of the functions in question.
44404b540aSrobert
45404b540aSrobert Back in olden times, when gcc was young, we developed an insanely
46404b540aSrobert complicated scheme whereby variables which were referenced nonlocally
47404b540aSrobert were forced to live in the stack of the declaring function, and then
48404b540aSrobert the nested functions magically discovered where these variables were
49404b540aSrobert placed. In order for this scheme to function properly, it required
50404b540aSrobert that the outer function be partially expanded, then we switch to
51404b540aSrobert compiling the inner function, and once done with those we switch back
52404b540aSrobert to compiling the outer function. Such delicate ordering requirements
53404b540aSrobert makes it difficult to do whole translation unit optimizations
54404b540aSrobert involving such functions.
55404b540aSrobert
56404b540aSrobert The implementation here is much more direct. Everything that can be
57404b540aSrobert referenced by an inner function is a member of an explicitly created
58404b540aSrobert structure herein called the "nonlocal frame struct". The incoming
59404b540aSrobert static chain for a nested function is a pointer to this struct in
60404b540aSrobert the parent. In this way, we settle on known offsets from a known
61404b540aSrobert base, and so are decoupled from the logic that places objects in the
62404b540aSrobert function's stack frame. More importantly, we don't have to wait for
63404b540aSrobert that to happen -- since the compilation of the inner function is no
64404b540aSrobert longer tied to a real stack frame, the nonlocal frame struct can be
65404b540aSrobert allocated anywhere. Which means that the outer function is now
66404b540aSrobert inlinable.
67404b540aSrobert
68404b540aSrobert Theory of operation here is very simple. Iterate over all the
69404b540aSrobert statements in all the functions (depth first) several times,
70404b540aSrobert allocating structures and fields on demand. In general we want to
71404b540aSrobert examine inner functions first, so that we can avoid making changes
72404b540aSrobert to outer functions which are unnecessary.
73404b540aSrobert
74404b540aSrobert The order of the passes matters a bit, in that later passes will be
75404b540aSrobert skipped if it is discovered that the functions don't actually interact
76404b540aSrobert at all. That is, they're nested in the lexical sense but could have
77404b540aSrobert been written as independent functions without change. */
78404b540aSrobert
79404b540aSrobert
80404b540aSrobert struct var_map_elt GTY(())
81404b540aSrobert {
82404b540aSrobert tree old;
83404b540aSrobert tree new;
84404b540aSrobert };
85404b540aSrobert
86404b540aSrobert struct nesting_info GTY ((chain_next ("%h.next")))
87404b540aSrobert {
88404b540aSrobert struct nesting_info *outer;
89404b540aSrobert struct nesting_info *inner;
90404b540aSrobert struct nesting_info *next;
91404b540aSrobert
92404b540aSrobert htab_t GTY ((param_is (struct var_map_elt))) field_map;
93404b540aSrobert htab_t GTY ((param_is (struct var_map_elt))) var_map;
94404b540aSrobert bitmap suppress_expansion;
95404b540aSrobert
96404b540aSrobert tree context;
97404b540aSrobert tree new_local_var_chain;
98404b540aSrobert tree debug_var_chain;
99404b540aSrobert tree frame_type;
100404b540aSrobert tree frame_decl;
101404b540aSrobert tree chain_field;
102404b540aSrobert tree chain_decl;
103404b540aSrobert tree nl_goto_field;
104404b540aSrobert
105404b540aSrobert bool any_parm_remapped;
106404b540aSrobert bool any_tramp_created;
107404b540aSrobert char static_chain_added;
108404b540aSrobert };
109404b540aSrobert
110404b540aSrobert
111404b540aSrobert /* Hashing and equality functions for nesting_info->var_map. */
112404b540aSrobert
113404b540aSrobert static hashval_t
var_map_hash(const void * x)114404b540aSrobert var_map_hash (const void *x)
115404b540aSrobert {
116404b540aSrobert const struct var_map_elt *a = (const struct var_map_elt *) x;
117404b540aSrobert return htab_hash_pointer (a->old);
118404b540aSrobert }
119404b540aSrobert
120404b540aSrobert static int
var_map_eq(const void * x,const void * y)121404b540aSrobert var_map_eq (const void *x, const void *y)
122404b540aSrobert {
123404b540aSrobert const struct var_map_elt *a = (const struct var_map_elt *) x;
124404b540aSrobert const struct var_map_elt *b = (const struct var_map_elt *) y;
125404b540aSrobert return a->old == b->old;
126404b540aSrobert }
127404b540aSrobert
128404b540aSrobert /* We're working in so many different function contexts simultaneously,
129404b540aSrobert that create_tmp_var is dangerous. Prevent mishap. */
130404b540aSrobert #define create_tmp_var cant_use_create_tmp_var_here_dummy
131404b540aSrobert
132404b540aSrobert /* Like create_tmp_var, except record the variable for registration at
133404b540aSrobert the given nesting level. */
134404b540aSrobert
135404b540aSrobert static tree
create_tmp_var_for(struct nesting_info * info,tree type,const char * prefix)136404b540aSrobert create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix)
137404b540aSrobert {
138404b540aSrobert tree tmp_var;
139404b540aSrobert
140404b540aSrobert /* If the type is of variable size or a type which must be created by the
141404b540aSrobert frontend, something is wrong. Note that we explicitly allow
142404b540aSrobert incomplete types here, since we create them ourselves here. */
143404b540aSrobert gcc_assert (!TREE_ADDRESSABLE (type));
144404b540aSrobert gcc_assert (!TYPE_SIZE_UNIT (type)
145404b540aSrobert || TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
146404b540aSrobert
147404b540aSrobert tmp_var = create_tmp_var_raw (type, prefix);
148404b540aSrobert DECL_CONTEXT (tmp_var) = info->context;
149404b540aSrobert TREE_CHAIN (tmp_var) = info->new_local_var_chain;
150404b540aSrobert DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
151404b540aSrobert if (TREE_CODE (type) == COMPLEX_TYPE)
152404b540aSrobert DECL_COMPLEX_GIMPLE_REG_P (tmp_var) = 1;
153404b540aSrobert
154404b540aSrobert info->new_local_var_chain = tmp_var;
155404b540aSrobert
156404b540aSrobert return tmp_var;
157404b540aSrobert }
158404b540aSrobert
159404b540aSrobert /* Take the address of EXP to be used within function CONTEXT.
160404b540aSrobert Mark it for addressability as necessary. */
161404b540aSrobert
162404b540aSrobert tree
build_addr(tree exp,tree context)163404b540aSrobert build_addr (tree exp, tree context)
164404b540aSrobert {
165404b540aSrobert tree base = exp;
166404b540aSrobert tree save_context;
167404b540aSrobert tree retval;
168404b540aSrobert
169404b540aSrobert while (handled_component_p (base))
170404b540aSrobert base = TREE_OPERAND (base, 0);
171404b540aSrobert
172404b540aSrobert if (DECL_P (base))
173404b540aSrobert TREE_ADDRESSABLE (base) = 1;
174404b540aSrobert
175404b540aSrobert /* Building the ADDR_EXPR will compute a set of properties for
176404b540aSrobert that ADDR_EXPR. Those properties are unfortunately context
177404b540aSrobert specific. ie, they are dependent on CURRENT_FUNCTION_DECL.
178404b540aSrobert
179404b540aSrobert Temporarily set CURRENT_FUNCTION_DECL to the desired context,
180404b540aSrobert build the ADDR_EXPR, then restore CURRENT_FUNCTION_DECL. That
181404b540aSrobert way the properties are for the ADDR_EXPR are computed properly. */
182404b540aSrobert save_context = current_function_decl;
183404b540aSrobert current_function_decl = context;
184404b540aSrobert retval = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
185404b540aSrobert current_function_decl = save_context;;
186404b540aSrobert return retval;
187404b540aSrobert }
188404b540aSrobert
189404b540aSrobert /* Insert FIELD into TYPE, sorted by alignment requirements. */
190404b540aSrobert
191404b540aSrobert void
insert_field_into_struct(tree type,tree field)192404b540aSrobert insert_field_into_struct (tree type, tree field)
193404b540aSrobert {
194404b540aSrobert tree *p;
195404b540aSrobert
196404b540aSrobert DECL_CONTEXT (field) = type;
197404b540aSrobert
198404b540aSrobert for (p = &TYPE_FIELDS (type); *p ; p = &TREE_CHAIN (*p))
199404b540aSrobert if (DECL_ALIGN (field) >= DECL_ALIGN (*p))
200404b540aSrobert break;
201404b540aSrobert
202404b540aSrobert TREE_CHAIN (field) = *p;
203404b540aSrobert *p = field;
204404b540aSrobert }
205404b540aSrobert
206404b540aSrobert /* Build or return the RECORD_TYPE that describes the frame state that is
207404b540aSrobert shared between INFO->CONTEXT and its nested functions. This record will
208404b540aSrobert not be complete until finalize_nesting_tree; up until that point we'll
209404b540aSrobert be adding fields as necessary.
210404b540aSrobert
211404b540aSrobert We also build the DECL that represents this frame in the function. */
212404b540aSrobert
213404b540aSrobert static tree
get_frame_type(struct nesting_info * info)214404b540aSrobert get_frame_type (struct nesting_info *info)
215404b540aSrobert {
216404b540aSrobert tree type = info->frame_type;
217404b540aSrobert if (!type)
218404b540aSrobert {
219404b540aSrobert char *name;
220404b540aSrobert
221404b540aSrobert type = make_node (RECORD_TYPE);
222404b540aSrobert
223404b540aSrobert name = concat ("FRAME.",
224404b540aSrobert IDENTIFIER_POINTER (DECL_NAME (info->context)),
225404b540aSrobert NULL);
226404b540aSrobert TYPE_NAME (type) = get_identifier (name);
227404b540aSrobert free (name);
228404b540aSrobert
229404b540aSrobert info->frame_type = type;
230404b540aSrobert info->frame_decl = create_tmp_var_for (info, type, "FRAME");
231404b540aSrobert
232404b540aSrobert /* ??? Always make it addressable for now, since it is meant to
233404b540aSrobert be pointed to by the static chain pointer. This pessimizes
234404b540aSrobert when it turns out that no static chains are needed because
235404b540aSrobert the nested functions referencing non-local variables are not
236404b540aSrobert reachable, but the true pessimization is to create the non-
237404b540aSrobert local frame structure in the first place. */
238404b540aSrobert TREE_ADDRESSABLE (info->frame_decl) = 1;
239404b540aSrobert }
240404b540aSrobert return type;
241404b540aSrobert }
242404b540aSrobert
243404b540aSrobert /* Return true if DECL should be referenced by pointer in the non-local
244404b540aSrobert frame structure. */
245404b540aSrobert
246404b540aSrobert static bool
use_pointer_in_frame(tree decl)247404b540aSrobert use_pointer_in_frame (tree decl)
248404b540aSrobert {
249404b540aSrobert if (TREE_CODE (decl) == PARM_DECL)
250404b540aSrobert {
251404b540aSrobert /* It's illegal to copy TREE_ADDRESSABLE, impossible to copy variable
252404b540aSrobert sized decls, and inefficient to copy large aggregates. Don't bother
253404b540aSrobert moving anything but scalar variables. */
254404b540aSrobert return AGGREGATE_TYPE_P (TREE_TYPE (decl));
255404b540aSrobert }
256404b540aSrobert else
257404b540aSrobert {
258404b540aSrobert /* Variable sized types make things "interesting" in the frame. */
259404b540aSrobert return DECL_SIZE (decl) == NULL || !TREE_CONSTANT (DECL_SIZE (decl));
260404b540aSrobert }
261404b540aSrobert }
262404b540aSrobert
263404b540aSrobert /* Given DECL, a non-locally accessed variable, find or create a field
264404b540aSrobert in the non-local frame structure for the given nesting context. */
265404b540aSrobert
266404b540aSrobert static tree
lookup_field_for_decl(struct nesting_info * info,tree decl,enum insert_option insert)267404b540aSrobert lookup_field_for_decl (struct nesting_info *info, tree decl,
268404b540aSrobert enum insert_option insert)
269404b540aSrobert {
270404b540aSrobert struct var_map_elt *elt, dummy;
271404b540aSrobert void **slot;
272404b540aSrobert tree field;
273404b540aSrobert
274404b540aSrobert dummy.old = decl;
275404b540aSrobert slot = htab_find_slot (info->field_map, &dummy, insert);
276404b540aSrobert if (!slot)
277404b540aSrobert {
278404b540aSrobert gcc_assert (insert != INSERT);
279404b540aSrobert return NULL;
280404b540aSrobert }
281404b540aSrobert elt = (struct var_map_elt *) *slot;
282404b540aSrobert
283404b540aSrobert if (!elt && insert == INSERT)
284404b540aSrobert {
285404b540aSrobert field = make_node (FIELD_DECL);
286404b540aSrobert DECL_NAME (field) = DECL_NAME (decl);
287404b540aSrobert
288404b540aSrobert if (use_pointer_in_frame (decl))
289404b540aSrobert {
290404b540aSrobert TREE_TYPE (field) = build_pointer_type (TREE_TYPE (decl));
291404b540aSrobert DECL_ALIGN (field) = TYPE_ALIGN (TREE_TYPE (field));
292404b540aSrobert DECL_NONADDRESSABLE_P (field) = 1;
293404b540aSrobert }
294404b540aSrobert else
295404b540aSrobert {
296404b540aSrobert TREE_TYPE (field) = TREE_TYPE (decl);
297404b540aSrobert DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (decl);
298404b540aSrobert DECL_ALIGN (field) = DECL_ALIGN (decl);
299404b540aSrobert DECL_USER_ALIGN (field) = DECL_USER_ALIGN (decl);
300404b540aSrobert TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (decl);
301404b540aSrobert DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (decl);
302404b540aSrobert TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (decl);
303404b540aSrobert }
304404b540aSrobert
305404b540aSrobert insert_field_into_struct (get_frame_type (info), field);
306404b540aSrobert
307404b540aSrobert elt = GGC_NEW (struct var_map_elt);
308404b540aSrobert elt->old = decl;
309404b540aSrobert elt->new = field;
310404b540aSrobert *slot = elt;
311404b540aSrobert
312404b540aSrobert if (TREE_CODE (decl) == PARM_DECL)
313404b540aSrobert info->any_parm_remapped = true;
314404b540aSrobert }
315404b540aSrobert else
316404b540aSrobert field = elt ? elt->new : NULL;
317404b540aSrobert
318404b540aSrobert return field;
319404b540aSrobert }
320404b540aSrobert
321404b540aSrobert /* Build or return the variable that holds the static chain within
322404b540aSrobert INFO->CONTEXT. This variable may only be used within INFO->CONTEXT. */
323404b540aSrobert
324404b540aSrobert static tree
get_chain_decl(struct nesting_info * info)325404b540aSrobert get_chain_decl (struct nesting_info *info)
326404b540aSrobert {
327404b540aSrobert tree decl = info->chain_decl;
328404b540aSrobert if (!decl)
329404b540aSrobert {
330404b540aSrobert tree type;
331404b540aSrobert
332404b540aSrobert type = get_frame_type (info->outer);
333404b540aSrobert type = build_pointer_type (type);
334404b540aSrobert
335404b540aSrobert /* Note that this variable is *not* entered into any BIND_EXPR;
336404b540aSrobert the construction of this variable is handled specially in
337404b540aSrobert expand_function_start and initialize_inlined_parameters.
338404b540aSrobert Note also that it's represented as a parameter. This is more
339404b540aSrobert close to the truth, since the initial value does come from
340404b540aSrobert the caller. */
341404b540aSrobert decl = build_decl (PARM_DECL, create_tmp_var_name ("CHAIN"), type);
342404b540aSrobert DECL_ARTIFICIAL (decl) = 1;
343404b540aSrobert DECL_IGNORED_P (decl) = 1;
344404b540aSrobert TREE_USED (decl) = 1;
345404b540aSrobert DECL_CONTEXT (decl) = info->context;
346404b540aSrobert DECL_ARG_TYPE (decl) = type;
347404b540aSrobert
348404b540aSrobert /* Tell tree-inline.c that we never write to this variable, so
349404b540aSrobert it can copy-prop the replacement value immediately. */
350404b540aSrobert TREE_READONLY (decl) = 1;
351404b540aSrobert
352404b540aSrobert info->chain_decl = decl;
353404b540aSrobert }
354404b540aSrobert return decl;
355404b540aSrobert }
356404b540aSrobert
357404b540aSrobert /* Build or return the field within the non-local frame state that holds
358404b540aSrobert the static chain for INFO->CONTEXT. This is the way to walk back up
359404b540aSrobert multiple nesting levels. */
360404b540aSrobert
361404b540aSrobert static tree
get_chain_field(struct nesting_info * info)362404b540aSrobert get_chain_field (struct nesting_info *info)
363404b540aSrobert {
364404b540aSrobert tree field = info->chain_field;
365404b540aSrobert if (!field)
366404b540aSrobert {
367404b540aSrobert tree type = build_pointer_type (get_frame_type (info->outer));
368404b540aSrobert
369404b540aSrobert field = make_node (FIELD_DECL);
370404b540aSrobert DECL_NAME (field) = get_identifier ("__chain");
371404b540aSrobert TREE_TYPE (field) = type;
372404b540aSrobert DECL_ALIGN (field) = TYPE_ALIGN (type);
373404b540aSrobert DECL_NONADDRESSABLE_P (field) = 1;
374404b540aSrobert
375404b540aSrobert insert_field_into_struct (get_frame_type (info), field);
376404b540aSrobert
377404b540aSrobert info->chain_field = field;
378404b540aSrobert }
379404b540aSrobert return field;
380404b540aSrobert }
381404b540aSrobert
382404b540aSrobert /* Copy EXP into a temporary. Allocate the temporary in the context of
383404b540aSrobert INFO and insert the initialization statement before TSI. */
384404b540aSrobert
385404b540aSrobert static tree
init_tmp_var(struct nesting_info * info,tree exp,tree_stmt_iterator * tsi)386404b540aSrobert init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
387404b540aSrobert {
388404b540aSrobert tree t, stmt;
389404b540aSrobert
390404b540aSrobert t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
391404b540aSrobert stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), t, exp);
392404b540aSrobert SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
393404b540aSrobert tsi_link_before (tsi, stmt, TSI_SAME_STMT);
394404b540aSrobert
395404b540aSrobert return t;
396404b540aSrobert }
397404b540aSrobert
398404b540aSrobert /* Similarly, but only do so to force EXP to satisfy is_gimple_val. */
399404b540aSrobert
400404b540aSrobert static tree
tsi_gimplify_val(struct nesting_info * info,tree exp,tree_stmt_iterator * tsi)401404b540aSrobert tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
402404b540aSrobert {
403404b540aSrobert if (is_gimple_val (exp))
404404b540aSrobert return exp;
405404b540aSrobert else
406404b540aSrobert return init_tmp_var (info, exp, tsi);
407404b540aSrobert }
408404b540aSrobert
409404b540aSrobert /* Similarly, but copy from the temporary and insert the statement
410404b540aSrobert after the iterator. */
411404b540aSrobert
412404b540aSrobert static tree
save_tmp_var(struct nesting_info * info,tree exp,tree_stmt_iterator * tsi)413404b540aSrobert save_tmp_var (struct nesting_info *info, tree exp,
414404b540aSrobert tree_stmt_iterator *tsi)
415404b540aSrobert {
416404b540aSrobert tree t, stmt;
417404b540aSrobert
418404b540aSrobert t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
419404b540aSrobert stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), exp, t);
420404b540aSrobert SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
421404b540aSrobert tsi_link_after (tsi, stmt, TSI_SAME_STMT);
422404b540aSrobert
423404b540aSrobert return t;
424404b540aSrobert }
425404b540aSrobert
426404b540aSrobert /* Build or return the type used to represent a nested function trampoline. */
427404b540aSrobert
428404b540aSrobert static GTY(()) tree trampoline_type;
429404b540aSrobert
430404b540aSrobert static tree
get_trampoline_type(void)431404b540aSrobert get_trampoline_type (void)
432404b540aSrobert {
433404b540aSrobert tree record, t;
434404b540aSrobert unsigned align, size;
435404b540aSrobert
436404b540aSrobert if (trampoline_type)
437404b540aSrobert return trampoline_type;
438404b540aSrobert
439404b540aSrobert align = TRAMPOLINE_ALIGNMENT;
440404b540aSrobert size = TRAMPOLINE_SIZE;
441404b540aSrobert
442404b540aSrobert /* If we won't be able to guarantee alignment simply via TYPE_ALIGN,
443404b540aSrobert then allocate extra space so that we can do dynamic alignment. */
444404b540aSrobert if (align > STACK_BOUNDARY)
445404b540aSrobert {
446404b540aSrobert size += ((align/BITS_PER_UNIT) - 1) & -(STACK_BOUNDARY/BITS_PER_UNIT);
447404b540aSrobert align = STACK_BOUNDARY;
448404b540aSrobert }
449404b540aSrobert
450404b540aSrobert t = build_index_type (build_int_cst (NULL_TREE, size - 1));
451404b540aSrobert t = build_array_type (char_type_node, t);
452404b540aSrobert t = build_decl (FIELD_DECL, get_identifier ("__data"), t);
453404b540aSrobert DECL_ALIGN (t) = align;
454404b540aSrobert DECL_USER_ALIGN (t) = 1;
455404b540aSrobert
456404b540aSrobert record = make_node (RECORD_TYPE);
457404b540aSrobert TYPE_NAME (record) = get_identifier ("__builtin_trampoline");
458404b540aSrobert TYPE_FIELDS (record) = t;
459404b540aSrobert layout_type (record);
460404b540aSrobert
461404b540aSrobert return record;
462404b540aSrobert }
463404b540aSrobert
464404b540aSrobert /* Given DECL, a nested function, find or create a field in the non-local
465404b540aSrobert frame structure for a trampoline for this function. */
466404b540aSrobert
467404b540aSrobert static tree
lookup_tramp_for_decl(struct nesting_info * info,tree decl,enum insert_option insert)468404b540aSrobert lookup_tramp_for_decl (struct nesting_info *info, tree decl,
469404b540aSrobert enum insert_option insert)
470404b540aSrobert {
471404b540aSrobert struct var_map_elt *elt, dummy;
472404b540aSrobert void **slot;
473404b540aSrobert tree field;
474404b540aSrobert
475404b540aSrobert dummy.old = decl;
476404b540aSrobert slot = htab_find_slot (info->var_map, &dummy, insert);
477404b540aSrobert if (!slot)
478404b540aSrobert {
479404b540aSrobert gcc_assert (insert != INSERT);
480404b540aSrobert return NULL;
481404b540aSrobert }
482404b540aSrobert elt = (struct var_map_elt *) *slot;
483404b540aSrobert
484404b540aSrobert if (!elt && insert == INSERT)
485404b540aSrobert {
486404b540aSrobert field = make_node (FIELD_DECL);
487404b540aSrobert DECL_NAME (field) = DECL_NAME (decl);
488404b540aSrobert TREE_TYPE (field) = get_trampoline_type ();
489404b540aSrobert TREE_ADDRESSABLE (field) = 1;
490404b540aSrobert
491404b540aSrobert insert_field_into_struct (get_frame_type (info), field);
492404b540aSrobert
493404b540aSrobert elt = GGC_NEW (struct var_map_elt);
494404b540aSrobert elt->old = decl;
495404b540aSrobert elt->new = field;
496404b540aSrobert *slot = elt;
497404b540aSrobert
498404b540aSrobert info->any_tramp_created = true;
499404b540aSrobert }
500404b540aSrobert else
501404b540aSrobert field = elt ? elt->new : NULL;
502404b540aSrobert
503404b540aSrobert return field;
504404b540aSrobert }
505404b540aSrobert
506404b540aSrobert /* Build or return the field within the non-local frame state that holds
507404b540aSrobert the non-local goto "jmp_buf". The buffer itself is maintained by the
508404b540aSrobert rtl middle-end as dynamic stack space is allocated. */
509404b540aSrobert
510404b540aSrobert static tree
get_nl_goto_field(struct nesting_info * info)511404b540aSrobert get_nl_goto_field (struct nesting_info *info)
512404b540aSrobert {
513404b540aSrobert tree field = info->nl_goto_field;
514404b540aSrobert if (!field)
515404b540aSrobert {
516404b540aSrobert unsigned size;
517404b540aSrobert tree type;
518404b540aSrobert
519404b540aSrobert /* For __builtin_nonlocal_goto, we need N words. The first is the
520404b540aSrobert frame pointer, the rest is for the target's stack pointer save
521404b540aSrobert area. The number of words is controlled by STACK_SAVEAREA_MODE;
522404b540aSrobert not the best interface, but it'll do for now. */
523404b540aSrobert if (Pmode == ptr_mode)
524404b540aSrobert type = ptr_type_node;
525404b540aSrobert else
526404b540aSrobert type = lang_hooks.types.type_for_mode (Pmode, 1);
527404b540aSrobert
528404b540aSrobert size = GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL));
529404b540aSrobert size = size / GET_MODE_SIZE (Pmode);
530404b540aSrobert size = size + 1;
531404b540aSrobert
532404b540aSrobert type = build_array_type
533404b540aSrobert (type, build_index_type (build_int_cst (NULL_TREE, size)));
534404b540aSrobert
535404b540aSrobert field = make_node (FIELD_DECL);
536404b540aSrobert DECL_NAME (field) = get_identifier ("__nl_goto_buf");
537404b540aSrobert TREE_TYPE (field) = type;
538404b540aSrobert DECL_ALIGN (field) = TYPE_ALIGN (type);
539404b540aSrobert TREE_ADDRESSABLE (field) = 1;
540404b540aSrobert
541404b540aSrobert insert_field_into_struct (get_frame_type (info), field);
542404b540aSrobert
543404b540aSrobert info->nl_goto_field = field;
544404b540aSrobert }
545404b540aSrobert
546404b540aSrobert return field;
547404b540aSrobert }
548404b540aSrobert
549404b540aSrobert /* Helper function for walk_stmts. Walk output operands of an ASM_EXPR. */
550404b540aSrobert
551404b540aSrobert static void
walk_asm_expr(struct walk_stmt_info * wi,tree stmt)552404b540aSrobert walk_asm_expr (struct walk_stmt_info *wi, tree stmt)
553404b540aSrobert {
554404b540aSrobert int noutputs = list_length (ASM_OUTPUTS (stmt));
555404b540aSrobert const char **oconstraints
556404b540aSrobert = (const char **) alloca ((noutputs) * sizeof (const char *));
557404b540aSrobert int i;
558404b540aSrobert tree link;
559404b540aSrobert const char *constraint;
560404b540aSrobert bool allows_mem, allows_reg, is_inout;
561404b540aSrobert
562404b540aSrobert wi->is_lhs = true;
563404b540aSrobert for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
564404b540aSrobert {
565404b540aSrobert constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
566404b540aSrobert oconstraints[i] = constraint;
567404b540aSrobert parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
568404b540aSrobert &allows_reg, &is_inout);
569404b540aSrobert
570404b540aSrobert wi->val_only = (allows_reg || !allows_mem);
571404b540aSrobert walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
572404b540aSrobert }
573404b540aSrobert
574404b540aSrobert for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
575404b540aSrobert {
576404b540aSrobert constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
577404b540aSrobert parse_input_constraint (&constraint, 0, 0, noutputs, 0,
578404b540aSrobert oconstraints, &allows_mem, &allows_reg);
579404b540aSrobert
580404b540aSrobert wi->val_only = (allows_reg || !allows_mem);
581404b540aSrobert /* Although input "m" is not really a LHS, we need a lvalue. */
582404b540aSrobert wi->is_lhs = !wi->val_only;
583404b540aSrobert walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
584404b540aSrobert }
585404b540aSrobert
586404b540aSrobert wi->is_lhs = false;
587404b540aSrobert wi->val_only = true;
588404b540aSrobert }
589404b540aSrobert
590404b540aSrobert /* Iterate over all sub-statements of *TP calling walk_tree with
591404b540aSrobert WI->CALLBACK for every sub-expression in each statement found. */
592404b540aSrobert
593404b540aSrobert void
walk_stmts(struct walk_stmt_info * wi,tree * tp)594404b540aSrobert walk_stmts (struct walk_stmt_info *wi, tree *tp)
595404b540aSrobert {
596404b540aSrobert tree t = *tp;
597404b540aSrobert int walk_subtrees;
598404b540aSrobert
599404b540aSrobert if (!t)
600404b540aSrobert return;
601404b540aSrobert
602404b540aSrobert if (wi->want_locations && EXPR_HAS_LOCATION (t))
603404b540aSrobert input_location = EXPR_LOCATION (t);
604404b540aSrobert
605404b540aSrobert switch (TREE_CODE (t))
606404b540aSrobert {
607404b540aSrobert case STATEMENT_LIST:
608404b540aSrobert {
609404b540aSrobert tree_stmt_iterator i;
610404b540aSrobert for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
611404b540aSrobert {
612404b540aSrobert wi->tsi = i;
613404b540aSrobert walk_stmts (wi, tsi_stmt_ptr (i));
614404b540aSrobert }
615404b540aSrobert }
616404b540aSrobert break;
617404b540aSrobert
618404b540aSrobert case COND_EXPR:
619404b540aSrobert walk_tree (&COND_EXPR_COND (t), wi->callback, wi, NULL);
620404b540aSrobert walk_stmts (wi, &COND_EXPR_THEN (t));
621404b540aSrobert walk_stmts (wi, &COND_EXPR_ELSE (t));
622404b540aSrobert break;
623404b540aSrobert case CATCH_EXPR:
624404b540aSrobert walk_stmts (wi, &CATCH_BODY (t));
625404b540aSrobert break;
626404b540aSrobert case EH_FILTER_EXPR:
627404b540aSrobert walk_stmts (wi, &EH_FILTER_FAILURE (t));
628404b540aSrobert break;
629404b540aSrobert case TRY_CATCH_EXPR:
630404b540aSrobert case TRY_FINALLY_EXPR:
631404b540aSrobert walk_stmts (wi, &TREE_OPERAND (t, 0));
632404b540aSrobert walk_stmts (wi, &TREE_OPERAND (t, 1));
633404b540aSrobert break;
634404b540aSrobert
635404b540aSrobert case BIND_EXPR:
636404b540aSrobert if (wi->want_bind_expr)
637404b540aSrobert {
638404b540aSrobert walk_subtrees = 1;
639404b540aSrobert wi->callback (tp, &walk_subtrees, wi);
640404b540aSrobert if (!walk_subtrees)
641404b540aSrobert break;
642404b540aSrobert }
643404b540aSrobert walk_stmts (wi, &BIND_EXPR_BODY (t));
644404b540aSrobert break;
645404b540aSrobert
646404b540aSrobert case RETURN_EXPR:
647404b540aSrobert if (wi->want_return_expr)
648404b540aSrobert {
649404b540aSrobert walk_subtrees = 1;
650404b540aSrobert wi->callback (tp, &walk_subtrees, wi);
651404b540aSrobert if (!walk_subtrees)
652404b540aSrobert break;
653404b540aSrobert }
654404b540aSrobert walk_stmts (wi, &TREE_OPERAND (t, 0));
655404b540aSrobert break;
656404b540aSrobert
657404b540aSrobert case MODIFY_EXPR:
658404b540aSrobert /* A formal temporary lhs may use a COMPONENT_REF rhs. */
659404b540aSrobert wi->val_only = !is_gimple_formal_tmp_var (TREE_OPERAND (t, 0));
660404b540aSrobert walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL);
661404b540aSrobert
662404b540aSrobert /* If the rhs is appropriate for a memory, we may use a
663404b540aSrobert COMPONENT_REF on the lhs. */
664404b540aSrobert wi->val_only = !is_gimple_mem_rhs (TREE_OPERAND (t, 1));
665404b540aSrobert wi->is_lhs = true;
666404b540aSrobert walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
667404b540aSrobert
668404b540aSrobert wi->val_only = true;
669404b540aSrobert wi->is_lhs = false;
670404b540aSrobert break;
671404b540aSrobert
672404b540aSrobert case ASM_EXPR:
673404b540aSrobert walk_asm_expr (wi, *tp);
674404b540aSrobert break;
675404b540aSrobert
676404b540aSrobert default:
677404b540aSrobert wi->val_only = true;
678404b540aSrobert walk_tree (tp, wi->callback, wi, NULL);
679404b540aSrobert break;
680404b540aSrobert }
681404b540aSrobert }
682404b540aSrobert
683404b540aSrobert /* Invoke CALLBACK on all statements of *STMT_P. */
684404b540aSrobert
685404b540aSrobert static void
walk_body(walk_tree_fn callback,struct nesting_info * info,tree * stmt_p)686404b540aSrobert walk_body (walk_tree_fn callback, struct nesting_info *info, tree *stmt_p)
687404b540aSrobert {
688404b540aSrobert struct walk_stmt_info wi;
689404b540aSrobert
690404b540aSrobert memset (&wi, 0, sizeof (wi));
691404b540aSrobert wi.callback = callback;
692404b540aSrobert wi.info = info;
693404b540aSrobert wi.val_only = true;
694404b540aSrobert
695404b540aSrobert walk_stmts (&wi, stmt_p);
696404b540aSrobert }
697404b540aSrobert
698404b540aSrobert /* Invoke CALLBACK on all statements of INFO->CONTEXT. */
699404b540aSrobert
700404b540aSrobert static inline void
walk_function(walk_tree_fn callback,struct nesting_info * info)701404b540aSrobert walk_function (walk_tree_fn callback, struct nesting_info *info)
702404b540aSrobert {
703404b540aSrobert walk_body (callback, info, &DECL_SAVED_TREE (info->context));
704404b540aSrobert }
705404b540aSrobert
706404b540aSrobert /* Similarly for ROOT and all functions nested underneath, depth first. */
707404b540aSrobert
708404b540aSrobert static void
walk_all_functions(walk_tree_fn callback,struct nesting_info * root)709404b540aSrobert walk_all_functions (walk_tree_fn callback, struct nesting_info *root)
710404b540aSrobert {
711404b540aSrobert do
712404b540aSrobert {
713404b540aSrobert if (root->inner)
714404b540aSrobert walk_all_functions (callback, root->inner);
715404b540aSrobert walk_function (callback, root);
716404b540aSrobert root = root->next;
717404b540aSrobert }
718404b540aSrobert while (root);
719404b540aSrobert }
720404b540aSrobert
721404b540aSrobert /* We have to check for a fairly pathological case. The operands of function
722404b540aSrobert nested function are to be interpreted in the context of the enclosing
723404b540aSrobert function. So if any are variably-sized, they will get remapped when the
724404b540aSrobert enclosing function is inlined. But that remapping would also have to be
725404b540aSrobert done in the types of the PARM_DECLs of the nested function, meaning the
726404b540aSrobert argument types of that function will disagree with the arguments in the
727404b540aSrobert calls to that function. So we'd either have to make a copy of the nested
728404b540aSrobert function corresponding to each time the enclosing function was inlined or
729404b540aSrobert add a VIEW_CONVERT_EXPR to each such operand for each call to the nested
730404b540aSrobert function. The former is not practical. The latter would still require
731404b540aSrobert detecting this case to know when to add the conversions. So, for now at
732404b540aSrobert least, we don't inline such an enclosing function.
733404b540aSrobert
734404b540aSrobert We have to do that check recursively, so here return indicating whether
735404b540aSrobert FNDECL has such a nested function. ORIG_FN is the function we were
736404b540aSrobert trying to inline to use for checking whether any argument is variably
737404b540aSrobert modified by anything in it.
738404b540aSrobert
739404b540aSrobert It would be better to do this in tree-inline.c so that we could give
740404b540aSrobert the appropriate warning for why a function can't be inlined, but that's
741404b540aSrobert too late since the nesting structure has already been flattened and
742404b540aSrobert adding a flag just to record this fact seems a waste of a flag. */
743404b540aSrobert
744404b540aSrobert static bool
check_for_nested_with_variably_modified(tree fndecl,tree orig_fndecl)745404b540aSrobert check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl)
746404b540aSrobert {
747404b540aSrobert struct cgraph_node *cgn = cgraph_node (fndecl);
748404b540aSrobert tree arg;
749404b540aSrobert
750404b540aSrobert for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
751404b540aSrobert {
752404b540aSrobert for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg))
753881a61e9Srobert if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
754404b540aSrobert return true;
755404b540aSrobert
756404b540aSrobert if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl))
757404b540aSrobert return true;
758404b540aSrobert }
759404b540aSrobert
760404b540aSrobert return false;
761404b540aSrobert }
762404b540aSrobert
763404b540aSrobert /* Construct our local datastructure describing the function nesting
764404b540aSrobert tree rooted by CGN. */
765404b540aSrobert
766404b540aSrobert static struct nesting_info *
create_nesting_tree(struct cgraph_node * cgn)767404b540aSrobert create_nesting_tree (struct cgraph_node *cgn)
768404b540aSrobert {
769404b540aSrobert struct nesting_info *info = GGC_CNEW (struct nesting_info);
770404b540aSrobert info->field_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
771404b540aSrobert info->var_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
772404b540aSrobert info->suppress_expansion = BITMAP_GGC_ALLOC ();
773404b540aSrobert info->context = cgn->decl;
774404b540aSrobert
775404b540aSrobert for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
776404b540aSrobert {
777404b540aSrobert struct nesting_info *sub = create_nesting_tree (cgn);
778404b540aSrobert sub->outer = info;
779404b540aSrobert sub->next = info->inner;
780404b540aSrobert info->inner = sub;
781404b540aSrobert }
782404b540aSrobert
783404b540aSrobert /* See discussion at check_for_nested_with_variably_modified for a
784404b540aSrobert discussion of why this has to be here. */
785404b540aSrobert if (check_for_nested_with_variably_modified (info->context, info->context))
786404b540aSrobert DECL_UNINLINABLE (info->context) = true;
787404b540aSrobert
788404b540aSrobert return info;
789404b540aSrobert }
790404b540aSrobert
791404b540aSrobert /* Return an expression computing the static chain for TARGET_CONTEXT
792404b540aSrobert from INFO->CONTEXT. Insert any necessary computations before TSI. */
793404b540aSrobert
794404b540aSrobert static tree
get_static_chain(struct nesting_info * info,tree target_context,tree_stmt_iterator * tsi)795404b540aSrobert get_static_chain (struct nesting_info *info, tree target_context,
796404b540aSrobert tree_stmt_iterator *tsi)
797404b540aSrobert {
798404b540aSrobert struct nesting_info *i;
799404b540aSrobert tree x;
800404b540aSrobert
801404b540aSrobert if (info->context == target_context)
802404b540aSrobert {
803404b540aSrobert x = build_addr (info->frame_decl, target_context);
804404b540aSrobert }
805404b540aSrobert else
806404b540aSrobert {
807404b540aSrobert x = get_chain_decl (info);
808404b540aSrobert
809404b540aSrobert for (i = info->outer; i->context != target_context; i = i->outer)
810404b540aSrobert {
811404b540aSrobert tree field = get_chain_field (i);
812404b540aSrobert
813404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
814404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
815404b540aSrobert x = init_tmp_var (info, x, tsi);
816404b540aSrobert }
817404b540aSrobert }
818404b540aSrobert
819404b540aSrobert return x;
820404b540aSrobert }
821404b540aSrobert
822404b540aSrobert /* Return an expression referencing FIELD from TARGET_CONTEXT's non-local
823404b540aSrobert frame as seen from INFO->CONTEXT. Insert any necessary computations
824404b540aSrobert before TSI. */
825404b540aSrobert
826404b540aSrobert static tree
get_frame_field(struct nesting_info * info,tree target_context,tree field,tree_stmt_iterator * tsi)827404b540aSrobert get_frame_field (struct nesting_info *info, tree target_context,
828404b540aSrobert tree field, tree_stmt_iterator *tsi)
829404b540aSrobert {
830404b540aSrobert struct nesting_info *i;
831404b540aSrobert tree x;
832404b540aSrobert
833404b540aSrobert if (info->context == target_context)
834404b540aSrobert {
835404b540aSrobert /* Make sure frame_decl gets created. */
836404b540aSrobert (void) get_frame_type (info);
837404b540aSrobert x = info->frame_decl;
838404b540aSrobert }
839404b540aSrobert else
840404b540aSrobert {
841404b540aSrobert x = get_chain_decl (info);
842404b540aSrobert
843404b540aSrobert for (i = info->outer; i->context != target_context; i = i->outer)
844404b540aSrobert {
845404b540aSrobert tree field = get_chain_field (i);
846404b540aSrobert
847404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
848404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
849404b540aSrobert x = init_tmp_var (info, x, tsi);
850404b540aSrobert }
851404b540aSrobert
852404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
853404b540aSrobert }
854404b540aSrobert
855404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
856404b540aSrobert return x;
857404b540aSrobert }
858404b540aSrobert
859404b540aSrobert /* A subroutine of convert_nonlocal_reference. Create a local variable
860404b540aSrobert in the nested function with DECL_VALUE_EXPR set to reference the true
861404b540aSrobert variable in the parent function. This is used both for debug info
862404b540aSrobert and in OpenMP lowering. */
863404b540aSrobert
864404b540aSrobert static tree
get_nonlocal_debug_decl(struct nesting_info * info,tree decl)865404b540aSrobert get_nonlocal_debug_decl (struct nesting_info *info, tree decl)
866404b540aSrobert {
867404b540aSrobert struct var_map_elt *elt, dummy;
868404b540aSrobert tree target_context;
869404b540aSrobert struct nesting_info *i;
870404b540aSrobert tree x, field, new_decl;
871404b540aSrobert void **slot;
872404b540aSrobert
873404b540aSrobert dummy.old = decl;
874404b540aSrobert slot = htab_find_slot (info->var_map, &dummy, INSERT);
875404b540aSrobert elt = *slot;
876404b540aSrobert
877404b540aSrobert if (elt)
878404b540aSrobert return elt->new;
879404b540aSrobert
880404b540aSrobert target_context = decl_function_context (decl);
881404b540aSrobert
882404b540aSrobert /* A copy of the code in get_frame_field, but without the temporaries. */
883404b540aSrobert if (info->context == target_context)
884404b540aSrobert {
885404b540aSrobert /* Make sure frame_decl gets created. */
886404b540aSrobert (void) get_frame_type (info);
887404b540aSrobert x = info->frame_decl;
888404b540aSrobert i = info;
889404b540aSrobert }
890404b540aSrobert else
891404b540aSrobert {
892404b540aSrobert x = get_chain_decl (info);
893404b540aSrobert for (i = info->outer; i->context != target_context; i = i->outer)
894404b540aSrobert {
895404b540aSrobert field = get_chain_field (i);
896404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
897404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
898404b540aSrobert }
899404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
900404b540aSrobert }
901404b540aSrobert
902404b540aSrobert field = lookup_field_for_decl (i, decl, INSERT);
903404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
904404b540aSrobert if (use_pointer_in_frame (decl))
905404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
906404b540aSrobert
907404b540aSrobert /* ??? We should be remapping types as well, surely. */
908404b540aSrobert new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
909404b540aSrobert DECL_CONTEXT (new_decl) = info->context;
910404b540aSrobert DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
911404b540aSrobert DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
912404b540aSrobert DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
913404b540aSrobert TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
914404b540aSrobert TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
915404b540aSrobert TREE_READONLY (new_decl) = TREE_READONLY (decl);
916404b540aSrobert TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
917404b540aSrobert DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
918404b540aSrobert
919404b540aSrobert SET_DECL_VALUE_EXPR (new_decl, x);
920404b540aSrobert DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
921404b540aSrobert
922404b540aSrobert elt = ggc_alloc (sizeof (*elt));
923404b540aSrobert elt->old = decl;
924404b540aSrobert elt->new = new_decl;
925404b540aSrobert *slot = elt;
926404b540aSrobert
927404b540aSrobert TREE_CHAIN (new_decl) = info->debug_var_chain;
928404b540aSrobert info->debug_var_chain = new_decl;
929404b540aSrobert
930404b540aSrobert return new_decl;
931404b540aSrobert }
932404b540aSrobert
933404b540aSrobert /* Called via walk_function+walk_tree, rewrite all references to VAR
934404b540aSrobert and PARM_DECLs that belong to outer functions.
935404b540aSrobert
936404b540aSrobert The rewrite will involve some number of structure accesses back up
937404b540aSrobert the static chain. E.g. for a variable FOO up one nesting level it'll
938404b540aSrobert be CHAIN->FOO. For two levels it'll be CHAIN->__chain->FOO. Further
939404b540aSrobert indirections apply to decls for which use_pointer_in_frame is true. */
940404b540aSrobert
941404b540aSrobert static bool convert_nonlocal_omp_clauses (tree *, struct walk_stmt_info *);
942404b540aSrobert
943404b540aSrobert static tree
convert_nonlocal_reference(tree * tp,int * walk_subtrees,void * data)944404b540aSrobert convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
945404b540aSrobert {
946404b540aSrobert struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
947404b540aSrobert struct nesting_info *info = wi->info;
948404b540aSrobert tree t = *tp;
949404b540aSrobert tree save_local_var_chain;
950404b540aSrobert bitmap save_suppress;
951404b540aSrobert
952404b540aSrobert *walk_subtrees = 0;
953404b540aSrobert switch (TREE_CODE (t))
954404b540aSrobert {
955404b540aSrobert case VAR_DECL:
956404b540aSrobert /* Non-automatic variables are never processed. */
957404b540aSrobert if (TREE_STATIC (t) || DECL_EXTERNAL (t))
958404b540aSrobert break;
959404b540aSrobert /* FALLTHRU */
960404b540aSrobert
961404b540aSrobert case PARM_DECL:
962404b540aSrobert if (decl_function_context (t) != info->context)
963404b540aSrobert {
964404b540aSrobert tree x;
965404b540aSrobert wi->changed = true;
966404b540aSrobert
967404b540aSrobert x = get_nonlocal_debug_decl (info, t);
968404b540aSrobert if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
969404b540aSrobert {
970404b540aSrobert tree target_context = decl_function_context (t);
971404b540aSrobert struct nesting_info *i;
972404b540aSrobert for (i = info->outer; i->context != target_context; i = i->outer)
973404b540aSrobert continue;
974404b540aSrobert x = lookup_field_for_decl (i, t, INSERT);
975404b540aSrobert x = get_frame_field (info, target_context, x, &wi->tsi);
976404b540aSrobert if (use_pointer_in_frame (t))
977404b540aSrobert {
978404b540aSrobert x = init_tmp_var (info, x, &wi->tsi);
979404b540aSrobert x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
980404b540aSrobert }
981404b540aSrobert }
982404b540aSrobert
983404b540aSrobert if (wi->val_only)
984404b540aSrobert {
985404b540aSrobert if (wi->is_lhs)
986404b540aSrobert x = save_tmp_var (info, x, &wi->tsi);
987404b540aSrobert else
988404b540aSrobert x = init_tmp_var (info, x, &wi->tsi);
989404b540aSrobert }
990404b540aSrobert
991404b540aSrobert *tp = x;
992404b540aSrobert }
993404b540aSrobert break;
994404b540aSrobert
995404b540aSrobert case GOTO_EXPR:
996404b540aSrobert /* Don't walk non-local gotos for now. */
997404b540aSrobert if (TREE_CODE (GOTO_DESTINATION (t)) != LABEL_DECL)
998404b540aSrobert {
999404b540aSrobert *walk_subtrees = 1;
1000404b540aSrobert wi->val_only = true;
1001404b540aSrobert wi->is_lhs = false;
1002404b540aSrobert }
1003404b540aSrobert break;
1004404b540aSrobert
1005404b540aSrobert case LABEL_DECL:
1006404b540aSrobert /* We're taking the address of a label from a parent function, but
1007404b540aSrobert this is not itself a non-local goto. Mark the label such that it
1008404b540aSrobert will not be deleted, much as we would with a label address in
1009404b540aSrobert static storage. */
1010404b540aSrobert if (decl_function_context (t) != info->context)
1011404b540aSrobert FORCED_LABEL (t) = 1;
1012404b540aSrobert break;
1013404b540aSrobert
1014404b540aSrobert case ADDR_EXPR:
1015404b540aSrobert {
1016404b540aSrobert bool save_val_only = wi->val_only;
1017404b540aSrobert
1018404b540aSrobert wi->val_only = false;
1019404b540aSrobert wi->is_lhs = false;
1020404b540aSrobert wi->changed = false;
1021404b540aSrobert walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
1022404b540aSrobert wi->val_only = true;
1023404b540aSrobert
1024404b540aSrobert if (wi->changed)
1025404b540aSrobert {
1026404b540aSrobert tree save_context;
1027404b540aSrobert
1028404b540aSrobert /* If we changed anything, then TREE_INVARIANT is be wrong,
1029404b540aSrobert since we're no longer directly referencing a decl. */
1030404b540aSrobert save_context = current_function_decl;
1031404b540aSrobert current_function_decl = info->context;
1032404b540aSrobert recompute_tree_invariant_for_addr_expr (t);
1033404b540aSrobert current_function_decl = save_context;
1034404b540aSrobert
1035404b540aSrobert /* If the callback converted the address argument in a context
1036404b540aSrobert where we only accept variables (and min_invariant, presumably),
1037404b540aSrobert then compute the address into a temporary. */
1038404b540aSrobert if (save_val_only)
1039404b540aSrobert *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
1040404b540aSrobert }
1041404b540aSrobert }
1042404b540aSrobert break;
1043404b540aSrobert
1044404b540aSrobert case REALPART_EXPR:
1045404b540aSrobert case IMAGPART_EXPR:
1046404b540aSrobert case COMPONENT_REF:
1047404b540aSrobert case ARRAY_REF:
1048404b540aSrobert case ARRAY_RANGE_REF:
1049404b540aSrobert case BIT_FIELD_REF:
1050404b540aSrobert /* Go down this entire nest and just look at the final prefix and
1051404b540aSrobert anything that describes the references. Otherwise, we lose track
1052404b540aSrobert of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */
1053404b540aSrobert wi->val_only = true;
1054404b540aSrobert wi->is_lhs = false;
1055404b540aSrobert for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
1056404b540aSrobert {
1057404b540aSrobert if (TREE_CODE (t) == COMPONENT_REF)
1058404b540aSrobert walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
1059404b540aSrobert NULL);
1060404b540aSrobert else if (TREE_CODE (t) == ARRAY_REF
1061404b540aSrobert || TREE_CODE (t) == ARRAY_RANGE_REF)
1062404b540aSrobert {
1063404b540aSrobert walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
1064404b540aSrobert NULL);
1065404b540aSrobert walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
1066404b540aSrobert NULL);
1067404b540aSrobert walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi,
1068404b540aSrobert NULL);
1069404b540aSrobert }
1070404b540aSrobert else if (TREE_CODE (t) == BIT_FIELD_REF)
1071404b540aSrobert {
1072404b540aSrobert walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi,
1073404b540aSrobert NULL);
1074404b540aSrobert walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi,
1075404b540aSrobert NULL);
1076404b540aSrobert }
1077404b540aSrobert }
1078404b540aSrobert wi->val_only = false;
1079404b540aSrobert walk_tree (tp, convert_nonlocal_reference, wi, NULL);
1080404b540aSrobert break;
1081404b540aSrobert
1082404b540aSrobert case OMP_PARALLEL:
1083404b540aSrobert save_suppress = info->suppress_expansion;
1084404b540aSrobert if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
1085404b540aSrobert {
1086404b540aSrobert tree c, decl;
1087404b540aSrobert decl = get_chain_decl (info);
1088404b540aSrobert c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
1089404b540aSrobert OMP_CLAUSE_DECL (c) = decl;
1090404b540aSrobert OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
1091404b540aSrobert OMP_PARALLEL_CLAUSES (t) = c;
1092404b540aSrobert }
1093404b540aSrobert
1094404b540aSrobert save_local_var_chain = info->new_local_var_chain;
1095404b540aSrobert info->new_local_var_chain = NULL;
1096404b540aSrobert
1097404b540aSrobert walk_body (convert_nonlocal_reference, info, &OMP_PARALLEL_BODY (t));
1098404b540aSrobert
1099404b540aSrobert if (info->new_local_var_chain)
1100404b540aSrobert declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
1101404b540aSrobert info->new_local_var_chain = save_local_var_chain;
1102404b540aSrobert info->suppress_expansion = save_suppress;
1103404b540aSrobert break;
1104404b540aSrobert
1105404b540aSrobert case OMP_FOR:
1106404b540aSrobert case OMP_SECTIONS:
1107404b540aSrobert case OMP_SINGLE:
1108404b540aSrobert save_suppress = info->suppress_expansion;
1109404b540aSrobert convert_nonlocal_omp_clauses (&OMP_CLAUSES (t), wi);
1110404b540aSrobert walk_body (convert_nonlocal_reference, info, &OMP_BODY (t));
1111404b540aSrobert info->suppress_expansion = save_suppress;
1112404b540aSrobert break;
1113404b540aSrobert
1114404b540aSrobert case OMP_SECTION:
1115404b540aSrobert case OMP_MASTER:
1116404b540aSrobert case OMP_ORDERED:
1117404b540aSrobert walk_body (convert_nonlocal_reference, info, &OMP_BODY (t));
1118404b540aSrobert break;
1119404b540aSrobert
1120404b540aSrobert default:
1121404b540aSrobert if (!IS_TYPE_OR_DECL_P (t))
1122404b540aSrobert {
1123404b540aSrobert *walk_subtrees = 1;
1124404b540aSrobert wi->val_only = true;
1125404b540aSrobert wi->is_lhs = false;
1126404b540aSrobert }
1127404b540aSrobert break;
1128404b540aSrobert }
1129404b540aSrobert
1130404b540aSrobert return NULL_TREE;
1131404b540aSrobert }
1132404b540aSrobert
1133404b540aSrobert static bool
convert_nonlocal_omp_clauses(tree * pclauses,struct walk_stmt_info * wi)1134404b540aSrobert convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
1135404b540aSrobert {
1136404b540aSrobert struct nesting_info *info = wi->info;
1137404b540aSrobert bool need_chain = false;
1138404b540aSrobert tree clause, decl;
1139404b540aSrobert int dummy;
1140404b540aSrobert bitmap new_suppress;
1141404b540aSrobert
1142404b540aSrobert new_suppress = BITMAP_GGC_ALLOC ();
1143404b540aSrobert bitmap_copy (new_suppress, info->suppress_expansion);
1144404b540aSrobert
1145404b540aSrobert for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
1146404b540aSrobert {
1147404b540aSrobert switch (OMP_CLAUSE_CODE (clause))
1148404b540aSrobert {
1149404b540aSrobert case OMP_CLAUSE_PRIVATE:
1150404b540aSrobert case OMP_CLAUSE_FIRSTPRIVATE:
1151404b540aSrobert case OMP_CLAUSE_LASTPRIVATE:
1152404b540aSrobert case OMP_CLAUSE_REDUCTION:
1153404b540aSrobert case OMP_CLAUSE_COPYPRIVATE:
1154404b540aSrobert case OMP_CLAUSE_SHARED:
1155404b540aSrobert decl = OMP_CLAUSE_DECL (clause);
1156404b540aSrobert if (decl_function_context (decl) != info->context)
1157404b540aSrobert {
1158404b540aSrobert bitmap_set_bit (new_suppress, DECL_UID (decl));
1159404b540aSrobert OMP_CLAUSE_DECL (clause) = get_nonlocal_debug_decl (info, decl);
1160404b540aSrobert need_chain = true;
1161404b540aSrobert }
1162404b540aSrobert break;
1163404b540aSrobert
1164404b540aSrobert case OMP_CLAUSE_SCHEDULE:
1165404b540aSrobert if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
1166404b540aSrobert break;
1167404b540aSrobert /* FALLTHRU */
1168404b540aSrobert case OMP_CLAUSE_IF:
1169404b540aSrobert case OMP_CLAUSE_NUM_THREADS:
1170404b540aSrobert wi->val_only = true;
1171404b540aSrobert wi->is_lhs = false;
1172404b540aSrobert convert_nonlocal_reference (&OMP_CLAUSE_OPERAND (clause, 0), &dummy,
1173404b540aSrobert wi);
1174404b540aSrobert break;
1175404b540aSrobert
1176404b540aSrobert case OMP_CLAUSE_NOWAIT:
1177404b540aSrobert case OMP_CLAUSE_ORDERED:
1178404b540aSrobert case OMP_CLAUSE_DEFAULT:
1179404b540aSrobert case OMP_CLAUSE_COPYIN:
1180404b540aSrobert break;
1181404b540aSrobert
1182404b540aSrobert default:
1183404b540aSrobert gcc_unreachable ();
1184404b540aSrobert }
1185404b540aSrobert }
1186404b540aSrobert
1187404b540aSrobert info->suppress_expansion = new_suppress;
1188404b540aSrobert
1189404b540aSrobert return need_chain;
1190404b540aSrobert }
1191404b540aSrobert
1192404b540aSrobert /* A subroutine of convert_local_reference. Create a local variable
1193404b540aSrobert in the parent function with DECL_VALUE_EXPR set to reference the
1194404b540aSrobert field in FRAME. This is used both for debug info and in OpenMP
1195404b540aSrobert lowering. */
1196404b540aSrobert
1197404b540aSrobert static tree
get_local_debug_decl(struct nesting_info * info,tree decl,tree field)1198404b540aSrobert get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
1199404b540aSrobert {
1200404b540aSrobert struct var_map_elt *elt, dummy;
1201404b540aSrobert tree x, new_decl;
1202404b540aSrobert void **slot;
1203404b540aSrobert
1204404b540aSrobert dummy.old = decl;
1205404b540aSrobert slot = htab_find_slot (info->var_map, &dummy, INSERT);
1206404b540aSrobert elt = *slot;
1207404b540aSrobert
1208404b540aSrobert if (elt)
1209404b540aSrobert return elt->new;
1210404b540aSrobert
1211404b540aSrobert /* Make sure frame_decl gets created. */
1212404b540aSrobert (void) get_frame_type (info);
1213404b540aSrobert x = info->frame_decl;
1214404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
1215404b540aSrobert
1216404b540aSrobert new_decl = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
1217404b540aSrobert DECL_CONTEXT (new_decl) = info->context;
1218404b540aSrobert DECL_SOURCE_LOCATION (new_decl) = DECL_SOURCE_LOCATION (decl);
1219404b540aSrobert DECL_ARTIFICIAL (new_decl) = DECL_ARTIFICIAL (decl);
1220404b540aSrobert DECL_IGNORED_P (new_decl) = DECL_IGNORED_P (decl);
1221404b540aSrobert TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (decl);
1222404b540aSrobert TREE_SIDE_EFFECTS (new_decl) = TREE_SIDE_EFFECTS (decl);
1223404b540aSrobert TREE_READONLY (new_decl) = TREE_READONLY (decl);
1224404b540aSrobert TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (decl);
1225404b540aSrobert DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
1226404b540aSrobert
1227404b540aSrobert SET_DECL_VALUE_EXPR (new_decl, x);
1228404b540aSrobert DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
1229404b540aSrobert
1230404b540aSrobert elt = ggc_alloc (sizeof (*elt));
1231404b540aSrobert elt->old = decl;
1232404b540aSrobert elt->new = new_decl;
1233404b540aSrobert *slot = elt;
1234404b540aSrobert
1235404b540aSrobert TREE_CHAIN (new_decl) = info->debug_var_chain;
1236404b540aSrobert info->debug_var_chain = new_decl;
1237404b540aSrobert
1238404b540aSrobert /* Do not emit debug info twice. */
1239404b540aSrobert DECL_IGNORED_P (decl) = 1;
1240404b540aSrobert
1241404b540aSrobert return new_decl;
1242404b540aSrobert }
1243404b540aSrobert
1244404b540aSrobert /* Called via walk_function+walk_tree, rewrite all references to VAR
1245404b540aSrobert and PARM_DECLs that were referenced by inner nested functions.
1246404b540aSrobert The rewrite will be a structure reference to the local frame variable. */
1247404b540aSrobert
1248404b540aSrobert static bool convert_local_omp_clauses (tree *, struct walk_stmt_info *);
1249404b540aSrobert
1250404b540aSrobert static tree
convert_local_reference(tree * tp,int * walk_subtrees,void * data)1251404b540aSrobert convert_local_reference (tree *tp, int *walk_subtrees, void *data)
1252404b540aSrobert {
1253404b540aSrobert struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1254404b540aSrobert struct nesting_info *info = wi->info;
1255404b540aSrobert tree t = *tp, field, x;
1256404b540aSrobert bool save_val_only;
1257404b540aSrobert tree save_local_var_chain;
1258404b540aSrobert bitmap save_suppress;
1259404b540aSrobert
1260404b540aSrobert *walk_subtrees = 0;
1261404b540aSrobert switch (TREE_CODE (t))
1262404b540aSrobert {
1263404b540aSrobert case VAR_DECL:
1264404b540aSrobert /* Non-automatic variables are never processed. */
1265404b540aSrobert if (TREE_STATIC (t) || DECL_EXTERNAL (t))
1266404b540aSrobert break;
1267404b540aSrobert /* FALLTHRU */
1268404b540aSrobert
1269404b540aSrobert case PARM_DECL:
1270404b540aSrobert if (decl_function_context (t) == info->context)
1271404b540aSrobert {
1272404b540aSrobert /* If we copied a pointer to the frame, then the original decl
1273404b540aSrobert is used unchanged in the parent function. */
1274404b540aSrobert if (use_pointer_in_frame (t))
1275404b540aSrobert break;
1276404b540aSrobert
1277404b540aSrobert /* No need to transform anything if no child references the
1278404b540aSrobert variable. */
1279404b540aSrobert field = lookup_field_for_decl (info, t, NO_INSERT);
1280404b540aSrobert if (!field)
1281404b540aSrobert break;
1282404b540aSrobert wi->changed = true;
1283404b540aSrobert
1284404b540aSrobert x = get_local_debug_decl (info, t, field);
1285404b540aSrobert if (!bitmap_bit_p (info->suppress_expansion, DECL_UID (t)))
1286404b540aSrobert x = get_frame_field (info, info->context, field, &wi->tsi);
1287404b540aSrobert
1288404b540aSrobert if (wi->val_only)
1289404b540aSrobert {
1290404b540aSrobert if (wi->is_lhs)
1291404b540aSrobert x = save_tmp_var (info, x, &wi->tsi);
1292404b540aSrobert else
1293404b540aSrobert x = init_tmp_var (info, x, &wi->tsi);
1294404b540aSrobert }
1295404b540aSrobert
1296404b540aSrobert *tp = x;
1297404b540aSrobert }
1298404b540aSrobert break;
1299404b540aSrobert
1300404b540aSrobert case ADDR_EXPR:
1301404b540aSrobert save_val_only = wi->val_only;
1302404b540aSrobert wi->val_only = false;
1303404b540aSrobert wi->is_lhs = false;
1304404b540aSrobert wi->changed = false;
1305404b540aSrobert walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
1306404b540aSrobert wi->val_only = save_val_only;
1307404b540aSrobert
1308404b540aSrobert /* If we converted anything ... */
1309404b540aSrobert if (wi->changed)
1310404b540aSrobert {
1311404b540aSrobert tree save_context;
1312404b540aSrobert
1313404b540aSrobert /* Then the frame decl is now addressable. */
1314404b540aSrobert TREE_ADDRESSABLE (info->frame_decl) = 1;
1315404b540aSrobert
1316404b540aSrobert save_context = current_function_decl;
1317404b540aSrobert current_function_decl = info->context;
1318404b540aSrobert recompute_tree_invariant_for_addr_expr (t);
1319404b540aSrobert current_function_decl = save_context;
1320404b540aSrobert
1321404b540aSrobert /* If we are in a context where we only accept values, then
1322404b540aSrobert compute the address into a temporary. */
1323404b540aSrobert if (save_val_only)
1324404b540aSrobert *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
1325404b540aSrobert }
1326404b540aSrobert break;
1327404b540aSrobert
1328404b540aSrobert case REALPART_EXPR:
1329404b540aSrobert case IMAGPART_EXPR:
1330404b540aSrobert case COMPONENT_REF:
1331404b540aSrobert case ARRAY_REF:
1332404b540aSrobert case ARRAY_RANGE_REF:
1333404b540aSrobert case BIT_FIELD_REF:
1334404b540aSrobert /* Go down this entire nest and just look at the final prefix and
1335404b540aSrobert anything that describes the references. Otherwise, we lose track
1336404b540aSrobert of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */
1337404b540aSrobert save_val_only = wi->val_only;
1338404b540aSrobert wi->val_only = true;
1339404b540aSrobert wi->is_lhs = false;
1340404b540aSrobert for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
1341404b540aSrobert {
1342404b540aSrobert if (TREE_CODE (t) == COMPONENT_REF)
1343404b540aSrobert walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
1344404b540aSrobert NULL);
1345404b540aSrobert else if (TREE_CODE (t) == ARRAY_REF
1346404b540aSrobert || TREE_CODE (t) == ARRAY_RANGE_REF)
1347404b540aSrobert {
1348404b540aSrobert walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
1349404b540aSrobert NULL);
1350404b540aSrobert walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
1351404b540aSrobert NULL);
1352404b540aSrobert walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi,
1353404b540aSrobert NULL);
1354404b540aSrobert }
1355404b540aSrobert else if (TREE_CODE (t) == BIT_FIELD_REF)
1356404b540aSrobert {
1357404b540aSrobert walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi,
1358404b540aSrobert NULL);
1359404b540aSrobert walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi,
1360404b540aSrobert NULL);
1361404b540aSrobert }
1362404b540aSrobert }
1363404b540aSrobert wi->val_only = false;
1364404b540aSrobert walk_tree (tp, convert_local_reference, wi, NULL);
1365404b540aSrobert wi->val_only = save_val_only;
1366404b540aSrobert break;
1367404b540aSrobert
1368404b540aSrobert case OMP_PARALLEL:
1369404b540aSrobert save_suppress = info->suppress_expansion;
1370404b540aSrobert if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
1371404b540aSrobert {
1372404b540aSrobert tree c;
1373404b540aSrobert (void) get_frame_type (info);
1374404b540aSrobert c = build_omp_clause (OMP_CLAUSE_SHARED);
1375404b540aSrobert OMP_CLAUSE_DECL (c) = info->frame_decl;
1376404b540aSrobert OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
1377404b540aSrobert OMP_PARALLEL_CLAUSES (t) = c;
1378404b540aSrobert }
1379404b540aSrobert
1380404b540aSrobert save_local_var_chain = info->new_local_var_chain;
1381404b540aSrobert info->new_local_var_chain = NULL;
1382404b540aSrobert
1383404b540aSrobert walk_body (convert_local_reference, info, &OMP_PARALLEL_BODY (t));
1384404b540aSrobert
1385404b540aSrobert if (info->new_local_var_chain)
1386404b540aSrobert declare_vars (info->new_local_var_chain, OMP_PARALLEL_BODY (t), false);
1387404b540aSrobert info->new_local_var_chain = save_local_var_chain;
1388404b540aSrobert info->suppress_expansion = save_suppress;
1389404b540aSrobert break;
1390404b540aSrobert
1391404b540aSrobert case OMP_FOR:
1392404b540aSrobert case OMP_SECTIONS:
1393404b540aSrobert case OMP_SINGLE:
1394404b540aSrobert save_suppress = info->suppress_expansion;
1395404b540aSrobert convert_local_omp_clauses (&OMP_CLAUSES (t), wi);
1396404b540aSrobert walk_body (convert_local_reference, info, &OMP_BODY (t));
1397404b540aSrobert info->suppress_expansion = save_suppress;
1398404b540aSrobert break;
1399404b540aSrobert
1400404b540aSrobert case OMP_SECTION:
1401404b540aSrobert case OMP_MASTER:
1402404b540aSrobert case OMP_ORDERED:
1403404b540aSrobert walk_body (convert_local_reference, info, &OMP_BODY (t));
1404404b540aSrobert break;
1405404b540aSrobert
1406404b540aSrobert default:
1407404b540aSrobert if (!IS_TYPE_OR_DECL_P (t))
1408404b540aSrobert {
1409404b540aSrobert *walk_subtrees = 1;
1410404b540aSrobert wi->val_only = true;
1411404b540aSrobert wi->is_lhs = false;
1412404b540aSrobert }
1413404b540aSrobert break;
1414404b540aSrobert }
1415404b540aSrobert
1416404b540aSrobert return NULL_TREE;
1417404b540aSrobert }
1418404b540aSrobert
1419404b540aSrobert static bool
convert_local_omp_clauses(tree * pclauses,struct walk_stmt_info * wi)1420404b540aSrobert convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
1421404b540aSrobert {
1422404b540aSrobert struct nesting_info *info = wi->info;
1423404b540aSrobert bool need_frame = false;
1424404b540aSrobert tree clause, decl;
1425404b540aSrobert int dummy;
1426404b540aSrobert bitmap new_suppress;
1427404b540aSrobert
1428404b540aSrobert new_suppress = BITMAP_GGC_ALLOC ();
1429404b540aSrobert bitmap_copy (new_suppress, info->suppress_expansion);
1430404b540aSrobert
1431404b540aSrobert for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
1432404b540aSrobert {
1433404b540aSrobert switch (OMP_CLAUSE_CODE (clause))
1434404b540aSrobert {
1435404b540aSrobert case OMP_CLAUSE_PRIVATE:
1436404b540aSrobert case OMP_CLAUSE_FIRSTPRIVATE:
1437404b540aSrobert case OMP_CLAUSE_LASTPRIVATE:
1438404b540aSrobert case OMP_CLAUSE_REDUCTION:
1439404b540aSrobert case OMP_CLAUSE_COPYPRIVATE:
1440404b540aSrobert case OMP_CLAUSE_SHARED:
1441404b540aSrobert decl = OMP_CLAUSE_DECL (clause);
1442404b540aSrobert if (decl_function_context (decl) == info->context
1443404b540aSrobert && !use_pointer_in_frame (decl))
1444404b540aSrobert {
1445404b540aSrobert tree field = lookup_field_for_decl (info, decl, NO_INSERT);
1446404b540aSrobert if (field)
1447404b540aSrobert {
1448404b540aSrobert bitmap_set_bit (new_suppress, DECL_UID (decl));
1449404b540aSrobert OMP_CLAUSE_DECL (clause)
1450404b540aSrobert = get_local_debug_decl (info, decl, field);
1451404b540aSrobert need_frame = true;
1452404b540aSrobert }
1453404b540aSrobert }
1454404b540aSrobert break;
1455404b540aSrobert
1456404b540aSrobert case OMP_CLAUSE_SCHEDULE:
1457404b540aSrobert if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
1458404b540aSrobert break;
1459404b540aSrobert /* FALLTHRU */
1460404b540aSrobert case OMP_CLAUSE_IF:
1461404b540aSrobert case OMP_CLAUSE_NUM_THREADS:
1462404b540aSrobert wi->val_only = true;
1463404b540aSrobert wi->is_lhs = false;
1464404b540aSrobert convert_local_reference (&OMP_CLAUSE_OPERAND (clause, 0), &dummy, wi);
1465404b540aSrobert break;
1466404b540aSrobert
1467404b540aSrobert case OMP_CLAUSE_NOWAIT:
1468404b540aSrobert case OMP_CLAUSE_ORDERED:
1469404b540aSrobert case OMP_CLAUSE_DEFAULT:
1470404b540aSrobert case OMP_CLAUSE_COPYIN:
1471404b540aSrobert break;
1472404b540aSrobert
1473404b540aSrobert default:
1474404b540aSrobert gcc_unreachable ();
1475404b540aSrobert }
1476404b540aSrobert }
1477404b540aSrobert
1478404b540aSrobert info->suppress_expansion = new_suppress;
1479404b540aSrobert
1480404b540aSrobert return need_frame;
1481404b540aSrobert }
1482404b540aSrobert
1483404b540aSrobert /* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that
1484404b540aSrobert reference labels from outer functions. The rewrite will be a
1485404b540aSrobert call to __builtin_nonlocal_goto. */
1486404b540aSrobert
1487404b540aSrobert static tree
convert_nl_goto_reference(tree * tp,int * walk_subtrees,void * data)1488404b540aSrobert convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
1489404b540aSrobert {
1490404b540aSrobert struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1491404b540aSrobert struct nesting_info *info = wi->info, *i;
1492404b540aSrobert tree t = *tp, label, new_label, target_context, x, arg, field;
1493404b540aSrobert struct var_map_elt *elt, dummy;
1494404b540aSrobert void **slot;
1495404b540aSrobert
1496404b540aSrobert *walk_subtrees = 0;
1497404b540aSrobert if (TREE_CODE (t) != GOTO_EXPR)
1498404b540aSrobert return NULL_TREE;
1499404b540aSrobert label = GOTO_DESTINATION (t);
1500404b540aSrobert if (TREE_CODE (label) != LABEL_DECL)
1501404b540aSrobert return NULL_TREE;
1502404b540aSrobert target_context = decl_function_context (label);
1503404b540aSrobert if (target_context == info->context)
1504404b540aSrobert return NULL_TREE;
1505404b540aSrobert
1506404b540aSrobert for (i = info->outer; target_context != i->context; i = i->outer)
1507404b540aSrobert continue;
1508404b540aSrobert
1509404b540aSrobert /* The original user label may also be use for a normal goto, therefore
1510404b540aSrobert we must create a new label that will actually receive the abnormal
1511404b540aSrobert control transfer. This new label will be marked LABEL_NONLOCAL; this
1512404b540aSrobert mark will trigger proper behavior in the cfg, as well as cause the
1513404b540aSrobert (hairy target-specific) non-local goto receiver code to be generated
1514404b540aSrobert when we expand rtl. Enter this association into var_map so that we
1515404b540aSrobert can insert the new label into the IL during a second pass. */
1516404b540aSrobert dummy.old = label;
1517404b540aSrobert slot = htab_find_slot (i->var_map, &dummy, INSERT);
1518404b540aSrobert elt = (struct var_map_elt *) *slot;
1519404b540aSrobert if (elt == NULL)
1520404b540aSrobert {
1521404b540aSrobert new_label = create_artificial_label ();
1522404b540aSrobert DECL_NONLOCAL (new_label) = 1;
1523404b540aSrobert
1524404b540aSrobert elt = GGC_NEW (struct var_map_elt);
1525404b540aSrobert elt->old = label;
1526404b540aSrobert elt->new = new_label;
1527404b540aSrobert *slot = elt;
1528404b540aSrobert }
1529404b540aSrobert else
1530404b540aSrobert new_label = elt->new;
1531404b540aSrobert
1532404b540aSrobert /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field). */
1533404b540aSrobert field = get_nl_goto_field (i);
1534404b540aSrobert x = get_frame_field (info, target_context, field, &wi->tsi);
1535404b540aSrobert x = build_addr (x, target_context);
1536404b540aSrobert x = tsi_gimplify_val (info, x, &wi->tsi);
1537404b540aSrobert arg = tree_cons (NULL, x, NULL);
1538404b540aSrobert x = build_addr (new_label, target_context);
1539404b540aSrobert arg = tree_cons (NULL, x, arg);
1540404b540aSrobert x = implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO];
1541404b540aSrobert x = build_function_call_expr (x, arg);
1542404b540aSrobert
1543404b540aSrobert SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
1544404b540aSrobert *tsi_stmt_ptr (wi->tsi) = x;
1545404b540aSrobert
1546404b540aSrobert return NULL_TREE;
1547404b540aSrobert }
1548404b540aSrobert
1549404b540aSrobert /* Called via walk_function+walk_tree, rewrite all LABEL_EXPRs that
1550404b540aSrobert are referenced via nonlocal goto from a nested function. The rewrite
1551404b540aSrobert will involve installing a newly generated DECL_NONLOCAL label, and
1552404b540aSrobert (potentially) a branch around the rtl gunk that is assumed to be
1553404b540aSrobert attached to such a label. */
1554404b540aSrobert
1555404b540aSrobert static tree
convert_nl_goto_receiver(tree * tp,int * walk_subtrees,void * data)1556404b540aSrobert convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data)
1557404b540aSrobert {
1558404b540aSrobert struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1559404b540aSrobert struct nesting_info *info = wi->info;
1560404b540aSrobert tree t = *tp, label, new_label, x;
1561404b540aSrobert struct var_map_elt *elt, dummy;
1562404b540aSrobert tree_stmt_iterator tmp_tsi;
1563404b540aSrobert
1564404b540aSrobert *walk_subtrees = 0;
1565404b540aSrobert if (TREE_CODE (t) != LABEL_EXPR)
1566404b540aSrobert return NULL_TREE;
1567404b540aSrobert label = LABEL_EXPR_LABEL (t);
1568404b540aSrobert
1569404b540aSrobert dummy.old = label;
1570404b540aSrobert elt = (struct var_map_elt *) htab_find (info->var_map, &dummy);
1571404b540aSrobert if (!elt)
1572404b540aSrobert return NULL_TREE;
1573404b540aSrobert new_label = elt->new;
1574404b540aSrobert
1575404b540aSrobert /* If there's any possibility that the previous statement falls through,
1576404b540aSrobert then we must branch around the new non-local label. */
1577404b540aSrobert tmp_tsi = wi->tsi;
1578404b540aSrobert tsi_prev (&tmp_tsi);
1579404b540aSrobert if (tsi_end_p (tmp_tsi) || block_may_fallthru (tsi_stmt (tmp_tsi)))
1580404b540aSrobert {
1581404b540aSrobert x = build1 (GOTO_EXPR, void_type_node, label);
1582404b540aSrobert tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
1583404b540aSrobert }
1584404b540aSrobert x = build1 (LABEL_EXPR, void_type_node, new_label);
1585404b540aSrobert tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
1586404b540aSrobert
1587404b540aSrobert return NULL_TREE;
1588404b540aSrobert }
1589404b540aSrobert
1590404b540aSrobert /* Called via walk_function+walk_tree, rewrite all references to addresses
1591404b540aSrobert of nested functions that require the use of trampolines. The rewrite
1592404b540aSrobert will involve a reference a trampoline generated for the occasion. */
1593404b540aSrobert
1594404b540aSrobert static tree
convert_tramp_reference(tree * tp,int * walk_subtrees,void * data)1595404b540aSrobert convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
1596404b540aSrobert {
1597404b540aSrobert struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1598404b540aSrobert struct nesting_info *info = wi->info, *i;
1599404b540aSrobert tree t = *tp, decl, target_context, x, arg;
1600404b540aSrobert
1601404b540aSrobert *walk_subtrees = 0;
1602404b540aSrobert switch (TREE_CODE (t))
1603404b540aSrobert {
1604404b540aSrobert case ADDR_EXPR:
1605404b540aSrobert /* Build
1606404b540aSrobert T.1 = &CHAIN->tramp;
1607404b540aSrobert T.2 = __builtin_adjust_trampoline (T.1);
1608404b540aSrobert T.3 = (func_type)T.2;
1609404b540aSrobert */
1610404b540aSrobert
1611404b540aSrobert decl = TREE_OPERAND (t, 0);
1612404b540aSrobert if (TREE_CODE (decl) != FUNCTION_DECL)
1613404b540aSrobert break;
1614404b540aSrobert
1615404b540aSrobert /* Only need to process nested functions. */
1616404b540aSrobert target_context = decl_function_context (decl);
1617404b540aSrobert if (!target_context)
1618404b540aSrobert break;
1619404b540aSrobert
1620404b540aSrobert /* If the nested function doesn't use a static chain, then
1621404b540aSrobert it doesn't need a trampoline. */
1622404b540aSrobert if (DECL_NO_STATIC_CHAIN (decl))
1623404b540aSrobert break;
1624404b540aSrobert
1625*85ccd8dfSespie if (!flag_trampolines)
1626*85ccd8dfSespie {
1627*85ccd8dfSespie error ("trampoline code generation is not allowed without -ftrampolines");
1628*85ccd8dfSespie return NULL_TREE;
1629*85ccd8dfSespie }
1630*85ccd8dfSespie if (warn_trampolines)
1631*85ccd8dfSespie {
1632*85ccd8dfSespie warning(0, "local function address taken needing trampoline generation");
1633*85ccd8dfSespie }
1634404b540aSrobert /* Lookup the immediate parent of the callee, as that's where
1635404b540aSrobert we need to insert the trampoline. */
1636404b540aSrobert for (i = info; i->context != target_context; i = i->outer)
1637404b540aSrobert continue;
1638404b540aSrobert x = lookup_tramp_for_decl (i, decl, INSERT);
1639404b540aSrobert
1640404b540aSrobert /* Compute the address of the field holding the trampoline. */
1641404b540aSrobert x = get_frame_field (info, target_context, x, &wi->tsi);
1642404b540aSrobert x = build_addr (x, target_context);
1643404b540aSrobert x = tsi_gimplify_val (info, x, &wi->tsi);
1644404b540aSrobert arg = tree_cons (NULL, x, NULL);
1645404b540aSrobert
1646404b540aSrobert /* Do machine-specific ugliness. Normally this will involve
1647404b540aSrobert computing extra alignment, but it can really be anything. */
1648404b540aSrobert x = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
1649404b540aSrobert x = build_function_call_expr (x, arg);
1650404b540aSrobert x = init_tmp_var (info, x, &wi->tsi);
1651404b540aSrobert
1652404b540aSrobert /* Cast back to the proper function type. */
1653404b540aSrobert x = build1 (NOP_EXPR, TREE_TYPE (t), x);
1654404b540aSrobert x = init_tmp_var (info, x, &wi->tsi);
1655404b540aSrobert
1656404b540aSrobert *tp = x;
1657404b540aSrobert break;
1658404b540aSrobert
1659404b540aSrobert case CALL_EXPR:
1660404b540aSrobert /* Only walk call arguments, lest we generate trampolines for
1661404b540aSrobert direct calls. */
1662404b540aSrobert walk_tree (&TREE_OPERAND (t, 1), convert_tramp_reference, wi, NULL);
1663404b540aSrobert break;
1664404b540aSrobert
1665404b540aSrobert default:
1666404b540aSrobert if (!IS_TYPE_OR_DECL_P (t))
1667404b540aSrobert *walk_subtrees = 1;
1668404b540aSrobert break;
1669404b540aSrobert }
1670404b540aSrobert
1671404b540aSrobert return NULL_TREE;
1672404b540aSrobert }
1673404b540aSrobert
1674404b540aSrobert /* Called via walk_function+walk_tree, rewrite all CALL_EXPRs that
1675404b540aSrobert reference nested functions to make sure that the static chain is
1676404b540aSrobert set up properly for the call. */
1677404b540aSrobert
1678404b540aSrobert static tree
convert_call_expr(tree * tp,int * walk_subtrees,void * data)1679404b540aSrobert convert_call_expr (tree *tp, int *walk_subtrees, void *data)
1680404b540aSrobert {
1681404b540aSrobert struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1682404b540aSrobert struct nesting_info *info = wi->info;
1683404b540aSrobert tree t = *tp, decl, target_context;
1684404b540aSrobert char save_static_chain_added;
1685404b540aSrobert int i;
1686404b540aSrobert
1687404b540aSrobert *walk_subtrees = 0;
1688404b540aSrobert switch (TREE_CODE (t))
1689404b540aSrobert {
1690404b540aSrobert case CALL_EXPR:
1691404b540aSrobert decl = get_callee_fndecl (t);
1692404b540aSrobert if (!decl)
1693404b540aSrobert break;
1694404b540aSrobert target_context = decl_function_context (decl);
1695404b540aSrobert if (target_context && !DECL_NO_STATIC_CHAIN (decl))
1696404b540aSrobert {
1697404b540aSrobert TREE_OPERAND (t, 2)
1698404b540aSrobert = get_static_chain (info, target_context, &wi->tsi);
1699404b540aSrobert info->static_chain_added
1700404b540aSrobert |= (1 << (info->context != target_context));
1701404b540aSrobert }
1702404b540aSrobert break;
1703404b540aSrobert
1704404b540aSrobert case RETURN_EXPR:
1705404b540aSrobert case MODIFY_EXPR:
1706404b540aSrobert case WITH_SIZE_EXPR:
1707404b540aSrobert /* Only return modify and with_size_expr may contain calls. */
1708404b540aSrobert *walk_subtrees = 1;
1709404b540aSrobert break;
1710404b540aSrobert
1711404b540aSrobert case OMP_PARALLEL:
1712404b540aSrobert save_static_chain_added = info->static_chain_added;
1713404b540aSrobert info->static_chain_added = 0;
1714404b540aSrobert walk_body (convert_call_expr, info, &OMP_PARALLEL_BODY (t));
1715404b540aSrobert for (i = 0; i < 2; i++)
1716404b540aSrobert {
1717404b540aSrobert tree c, decl;
1718404b540aSrobert if ((info->static_chain_added & (1 << i)) == 0)
1719404b540aSrobert continue;
1720404b540aSrobert decl = i ? get_chain_decl (info) : info->frame_decl;
1721404b540aSrobert /* Don't add CHAIN.* or FRAME.* twice. */
1722404b540aSrobert for (c = OMP_PARALLEL_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
1723404b540aSrobert if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
1724404b540aSrobert || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
1725404b540aSrobert && OMP_CLAUSE_DECL (c) == decl)
1726404b540aSrobert break;
1727404b540aSrobert if (c == NULL)
1728404b540aSrobert {
1729404b540aSrobert c = build_omp_clause (OMP_CLAUSE_FIRSTPRIVATE);
1730404b540aSrobert OMP_CLAUSE_DECL (c) = decl;
1731404b540aSrobert OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
1732404b540aSrobert OMP_PARALLEL_CLAUSES (t) = c;
1733404b540aSrobert }
1734404b540aSrobert }
1735404b540aSrobert info->static_chain_added |= save_static_chain_added;
1736404b540aSrobert break;
1737404b540aSrobert
1738404b540aSrobert case OMP_FOR:
1739404b540aSrobert case OMP_SECTIONS:
1740404b540aSrobert case OMP_SECTION:
1741404b540aSrobert case OMP_SINGLE:
1742404b540aSrobert case OMP_MASTER:
1743404b540aSrobert case OMP_ORDERED:
1744404b540aSrobert case OMP_CRITICAL:
1745404b540aSrobert walk_body (convert_call_expr, info, &OMP_BODY (t));
1746404b540aSrobert break;
1747404b540aSrobert
1748404b540aSrobert default:
1749404b540aSrobert break;
1750404b540aSrobert }
1751404b540aSrobert
1752404b540aSrobert return NULL_TREE;
1753404b540aSrobert }
1754404b540aSrobert
1755404b540aSrobert /* Walk the nesting tree starting with ROOT, depth first. Convert all
1756404b540aSrobert trampolines and call expressions. On the way back up, determine if
1757404b540aSrobert a nested function actually uses its static chain; if not, remember that. */
1758404b540aSrobert
1759404b540aSrobert static void
convert_all_function_calls(struct nesting_info * root)1760404b540aSrobert convert_all_function_calls (struct nesting_info *root)
1761404b540aSrobert {
1762404b540aSrobert do
1763404b540aSrobert {
1764404b540aSrobert if (root->inner)
1765404b540aSrobert convert_all_function_calls (root->inner);
1766404b540aSrobert
1767404b540aSrobert walk_function (convert_tramp_reference, root);
1768404b540aSrobert walk_function (convert_call_expr, root);
1769404b540aSrobert
1770404b540aSrobert /* If the function does not use a static chain, then remember that. */
1771404b540aSrobert if (root->outer && !root->chain_decl && !root->chain_field)
1772404b540aSrobert DECL_NO_STATIC_CHAIN (root->context) = 1;
1773404b540aSrobert else
1774404b540aSrobert gcc_assert (!DECL_NO_STATIC_CHAIN (root->context));
1775404b540aSrobert
1776404b540aSrobert root = root->next;
1777404b540aSrobert }
1778404b540aSrobert while (root);
1779404b540aSrobert }
1780404b540aSrobert
1781404b540aSrobert /* Do "everything else" to clean up or complete state collected by the
1782404b540aSrobert various walking passes -- lay out the types and decls, generate code
1783404b540aSrobert to initialize the frame decl, store critical expressions in the
1784404b540aSrobert struct function for rtl to find. */
1785404b540aSrobert
1786404b540aSrobert static void
finalize_nesting_tree_1(struct nesting_info * root)1787404b540aSrobert finalize_nesting_tree_1 (struct nesting_info *root)
1788404b540aSrobert {
1789404b540aSrobert tree stmt_list = NULL;
1790404b540aSrobert tree context = root->context;
1791404b540aSrobert struct function *sf;
1792404b540aSrobert
1793404b540aSrobert /* If we created a non-local frame type or decl, we need to lay them
1794404b540aSrobert out at this time. */
1795404b540aSrobert if (root->frame_type)
1796404b540aSrobert {
1797404b540aSrobert /* In some cases the frame type will trigger the -Wpadded warning.
1798404b540aSrobert This is not helpful; suppress it. */
1799404b540aSrobert int save_warn_padded = warn_padded;
1800404b540aSrobert warn_padded = 0;
1801404b540aSrobert layout_type (root->frame_type);
1802404b540aSrobert warn_padded = save_warn_padded;
1803404b540aSrobert layout_decl (root->frame_decl, 0);
1804404b540aSrobert }
1805404b540aSrobert
1806404b540aSrobert /* If any parameters were referenced non-locally, then we need to
1807404b540aSrobert insert a copy. Likewise, if any variables were referenced by
1808404b540aSrobert pointer, we need to initialize the address. */
1809404b540aSrobert if (root->any_parm_remapped)
1810404b540aSrobert {
1811404b540aSrobert tree p;
1812404b540aSrobert for (p = DECL_ARGUMENTS (context); p ; p = TREE_CHAIN (p))
1813404b540aSrobert {
1814404b540aSrobert tree field, x, y;
1815404b540aSrobert
1816404b540aSrobert field = lookup_field_for_decl (root, p, NO_INSERT);
1817404b540aSrobert if (!field)
1818404b540aSrobert continue;
1819404b540aSrobert
1820404b540aSrobert if (use_pointer_in_frame (p))
1821404b540aSrobert x = build_addr (p, context);
1822404b540aSrobert else
1823404b540aSrobert x = p;
1824404b540aSrobert
1825404b540aSrobert y = build3 (COMPONENT_REF, TREE_TYPE (field),
1826404b540aSrobert root->frame_decl, field, NULL_TREE);
1827404b540aSrobert x = build2 (MODIFY_EXPR, TREE_TYPE (field), y, x);
1828404b540aSrobert append_to_statement_list (x, &stmt_list);
1829404b540aSrobert }
1830404b540aSrobert }
1831404b540aSrobert
1832404b540aSrobert /* If a chain_field was created, then it needs to be initialized
1833404b540aSrobert from chain_decl. */
1834404b540aSrobert if (root->chain_field)
1835404b540aSrobert {
1836404b540aSrobert tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field),
1837404b540aSrobert root->frame_decl, root->chain_field, NULL_TREE);
1838404b540aSrobert x = build2 (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
1839404b540aSrobert append_to_statement_list (x, &stmt_list);
1840404b540aSrobert }
1841404b540aSrobert
1842404b540aSrobert /* If trampolines were created, then we need to initialize them. */
1843404b540aSrobert if (root->any_tramp_created)
1844404b540aSrobert {
1845404b540aSrobert struct nesting_info *i;
1846404b540aSrobert for (i = root->inner; i ; i = i->next)
1847404b540aSrobert {
1848404b540aSrobert tree arg, x, field;
1849404b540aSrobert
1850404b540aSrobert field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
1851404b540aSrobert if (!field)
1852404b540aSrobert continue;
1853404b540aSrobert
1854404b540aSrobert if (DECL_NO_STATIC_CHAIN (i->context))
1855404b540aSrobert x = null_pointer_node;
1856404b540aSrobert else
1857404b540aSrobert x = build_addr (root->frame_decl, context);
1858404b540aSrobert arg = tree_cons (NULL, x, NULL);
1859404b540aSrobert
1860404b540aSrobert x = build_addr (i->context, context);
1861404b540aSrobert arg = tree_cons (NULL, x, arg);
1862404b540aSrobert
1863404b540aSrobert x = build3 (COMPONENT_REF, TREE_TYPE (field),
1864404b540aSrobert root->frame_decl, field, NULL_TREE);
1865404b540aSrobert x = build_addr (x, context);
1866404b540aSrobert arg = tree_cons (NULL, x, arg);
1867404b540aSrobert
1868404b540aSrobert x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
1869404b540aSrobert x = build_function_call_expr (x, arg);
1870404b540aSrobert
1871404b540aSrobert append_to_statement_list (x, &stmt_list);
1872404b540aSrobert }
1873404b540aSrobert }
1874404b540aSrobert
1875404b540aSrobert /* If we created initialization statements, insert them. */
1876404b540aSrobert if (stmt_list)
1877404b540aSrobert {
1878404b540aSrobert annotate_all_with_locus (&stmt_list,
1879404b540aSrobert DECL_SOURCE_LOCATION (context));
1880404b540aSrobert append_to_statement_list (BIND_EXPR_BODY (DECL_SAVED_TREE (context)),
1881404b540aSrobert &stmt_list);
1882404b540aSrobert BIND_EXPR_BODY (DECL_SAVED_TREE (context)) = stmt_list;
1883404b540aSrobert }
1884404b540aSrobert
1885404b540aSrobert /* If a chain_decl was created, then it needs to be registered with
1886404b540aSrobert struct function so that it gets initialized from the static chain
1887404b540aSrobert register at the beginning of the function. */
1888404b540aSrobert sf = DECL_STRUCT_FUNCTION (root->context);
1889404b540aSrobert sf->static_chain_decl = root->chain_decl;
1890404b540aSrobert
1891404b540aSrobert /* Similarly for the non-local goto save area. */
1892404b540aSrobert if (root->nl_goto_field)
1893404b540aSrobert {
1894404b540aSrobert sf->nonlocal_goto_save_area
1895404b540aSrobert = get_frame_field (root, context, root->nl_goto_field, NULL);
1896404b540aSrobert sf->has_nonlocal_label = 1;
1897404b540aSrobert }
1898404b540aSrobert
1899404b540aSrobert /* Make sure all new local variables get inserted into the
1900404b540aSrobert proper BIND_EXPR. */
1901404b540aSrobert if (root->new_local_var_chain)
1902404b540aSrobert declare_vars (root->new_local_var_chain, DECL_SAVED_TREE (root->context),
1903404b540aSrobert false);
1904404b540aSrobert if (root->debug_var_chain)
1905404b540aSrobert declare_vars (root->debug_var_chain, DECL_SAVED_TREE (root->context),
1906404b540aSrobert true);
1907404b540aSrobert
1908404b540aSrobert /* Dump the translated tree function. */
1909404b540aSrobert dump_function (TDI_nested, root->context);
1910404b540aSrobert }
1911404b540aSrobert
1912404b540aSrobert static void
finalize_nesting_tree(struct nesting_info * root)1913404b540aSrobert finalize_nesting_tree (struct nesting_info *root)
1914404b540aSrobert {
1915404b540aSrobert do
1916404b540aSrobert {
1917404b540aSrobert if (root->inner)
1918404b540aSrobert finalize_nesting_tree (root->inner);
1919404b540aSrobert finalize_nesting_tree_1 (root);
1920404b540aSrobert root = root->next;
1921404b540aSrobert }
1922404b540aSrobert while (root);
1923404b540aSrobert }
1924404b540aSrobert
1925404b540aSrobert /* Unnest the nodes and pass them to cgraph. */
1926404b540aSrobert
1927404b540aSrobert static void
unnest_nesting_tree_1(struct nesting_info * root)1928404b540aSrobert unnest_nesting_tree_1 (struct nesting_info *root)
1929404b540aSrobert {
1930404b540aSrobert struct cgraph_node *node = cgraph_node (root->context);
1931404b540aSrobert
1932404b540aSrobert /* For nested functions update the cgraph to reflect unnesting.
1933404b540aSrobert We also delay finalizing of these functions up to this point. */
1934404b540aSrobert if (node->origin)
1935404b540aSrobert {
1936404b540aSrobert cgraph_unnest_node (cgraph_node (root->context));
1937404b540aSrobert cgraph_finalize_function (root->context, true);
1938404b540aSrobert }
1939404b540aSrobert }
1940404b540aSrobert
1941404b540aSrobert static void
unnest_nesting_tree(struct nesting_info * root)1942404b540aSrobert unnest_nesting_tree (struct nesting_info *root)
1943404b540aSrobert {
1944404b540aSrobert do
1945404b540aSrobert {
1946404b540aSrobert if (root->inner)
1947404b540aSrobert unnest_nesting_tree (root->inner);
1948404b540aSrobert unnest_nesting_tree_1 (root);
1949404b540aSrobert root = root->next;
1950404b540aSrobert }
1951404b540aSrobert while (root);
1952404b540aSrobert }
1953404b540aSrobert
1954404b540aSrobert /* Free the data structures allocated during this pass. */
1955404b540aSrobert
1956404b540aSrobert static void
free_nesting_tree(struct nesting_info * root)1957404b540aSrobert free_nesting_tree (struct nesting_info *root)
1958404b540aSrobert {
1959404b540aSrobert struct nesting_info *next;
1960404b540aSrobert do
1961404b540aSrobert {
1962404b540aSrobert if (root->inner)
1963404b540aSrobert free_nesting_tree (root->inner);
1964404b540aSrobert htab_delete (root->var_map);
1965404b540aSrobert next = root->next;
1966404b540aSrobert ggc_free (root);
1967404b540aSrobert root = next;
1968404b540aSrobert }
1969404b540aSrobert while (root);
1970404b540aSrobert }
1971404b540aSrobert
1972404b540aSrobert static GTY(()) struct nesting_info *root;
1973404b540aSrobert
1974404b540aSrobert /* Main entry point for this pass. Process FNDECL and all of its nested
1975404b540aSrobert subroutines and turn them into something less tightly bound. */
1976404b540aSrobert
1977404b540aSrobert void
lower_nested_functions(tree fndecl)1978404b540aSrobert lower_nested_functions (tree fndecl)
1979404b540aSrobert {
1980404b540aSrobert struct cgraph_node *cgn;
1981404b540aSrobert
1982404b540aSrobert /* If there are no nested functions, there's nothing to do. */
1983404b540aSrobert cgn = cgraph_node (fndecl);
1984404b540aSrobert if (!cgn->nested)
1985404b540aSrobert return;
1986404b540aSrobert
1987404b540aSrobert root = create_nesting_tree (cgn);
1988404b540aSrobert walk_all_functions (convert_nonlocal_reference, root);
1989404b540aSrobert walk_all_functions (convert_local_reference, root);
1990404b540aSrobert walk_all_functions (convert_nl_goto_reference, root);
1991404b540aSrobert walk_all_functions (convert_nl_goto_receiver, root);
1992404b540aSrobert convert_all_function_calls (root);
1993404b540aSrobert finalize_nesting_tree (root);
1994404b540aSrobert unnest_nesting_tree (root);
1995404b540aSrobert free_nesting_tree (root);
1996404b540aSrobert root = NULL;
1997404b540aSrobert }
1998404b540aSrobert
1999404b540aSrobert #include "gt-tree-nested.h"
2000