xref: /openbsd/gnu/gcc/gcc/tree-nested.c (revision 85ccd8df)
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