Branch data Line data Source code
1 : : /* Manipulation of formal and actual parameters of functions and function
2 : : calls.
3 : : Copyright (C) 2017-2025 Free Software Foundation, Inc.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>.
20 : :
21 : :
22 : :
23 : : This file defines classes and other data structures that are used to manipulate
24 : : the prototype of a function, especially to create, remove or split its formal
25 : : parameters, but also to remove its return value, and also its call statements
26 : : correspondingly.
27 : :
28 : : The most basic one is a vector of structures ipa_adjusted_param. It is simply
29 : : a description how the new parameters should look like after the transformation
30 : : in what way they relate to the previous ones (if in any). Such relation to an
31 : : old parameter can be an outright copy or an IPA-SRA replacement. If an old
32 : : parameter is not listed or otherwise mentioned, it is removed as unused or at
33 : : least unnecessary. Note that this most basic structure does not work for
34 : : modifying calls of functions with variable number of arguments.
35 : :
36 : : Class ipa_param_adjustments is only a little more than a thin encapsulation of
37 : : a vector of ipa_param_adjustments. Along with this vector it contains an index
38 : : of the first potential vararg argument and a boolean flag whether the return
39 : : value should be removed or not. Moreover, the class contains method
40 : : modify_call which can transform a call statement so that it correctly calls a
41 : : modified function. These two data structures were designed to have a small
42 : : memory footprint because they are allocated for each clone of a call graph node
43 : : that has its prototype changed and live until the end of IPA clone
44 : : materialization and call redirection phase.
45 : :
46 : : On the other hand, class ipa_param_body_adjustments can afford to allocate more
47 : : data because its life span is much smaller, it is allocated and destroyed in
48 : : the course of materialization of each single clone that needs it or only when a
49 : : particular pass needs to change a function it is operating on. This class has
50 : : various methods required to change function declaration and the body of the
51 : : function according to instructions given either by class ipa_param_adjustments
52 : : or only a vector of ipa_adjusted_params.
53 : :
54 : : When these classes are used in the context of call graph clone materialization
55 : : and subsequent call statement redirection - which is the point at which we
56 : : modify arguments in call statements - they need to cooperate with each other in
57 : : order to handle what we refer to as pass-through (IPA-SRA) splits. These are
58 : : situations when a formal parameter of one function is split into several
59 : : smaller ones and some of them are then passed on in a call to another function
60 : : because the formal parameter of this callee has also been split.
61 : :
62 : : Consider a simple example:
63 : :
64 : : struct S {int a, b, c;};
65 : : struct Z {int x; S s;};
66 : :
67 : : foo (S s)
68 : : {
69 : : use (s.b);
70 : : }
71 : :
72 : : bar (Z z)
73 : : {
74 : : use (z.s.a);
75 : : foo (z.s);
76 : : }
77 : :
78 : : baz ()
79 : : {
80 : : bar (*global);
81 : : }
82 : :
83 : : Both bar and foo would have their parameter split. Foo would receive one
84 : : replacement representing s.b. Function bar would see its parameter split into
85 : : one replacement representing z.s.a and another representing z.s.b which would
86 : : be passed on to foo. It would be a so called pass-through split IPA-SRA
87 : : replacement, one which is passed in a call as an actual argument to another
88 : : IPA-SRA replacement in another function.
89 : :
90 : : Note that the call chain the example can be arbitrarily long and recursive and
91 : : that any function in it can be cloned by another IPA pass and any number of
92 : : adjacent functions in the call chain can be inlined into each other. Call
93 : : redirection takes place only after bodies of the function have been modified by
94 : : all of the above.
95 : :
96 : : Call redirection has to be able to find the right decl or SSA_NAME that
97 : : corresponds to the transitive split in the caller. The SSA names are assigned
98 : : right after clone materialization/ modification and cannot be "added" to call
99 : : arguments at any later point. Moreover, if the caller has been inlined the
100 : : SSA_NAMEs in question no longer belong to PARM_DECLs but to VAR_DECLs,
101 : : indistinguishable from any others.
102 : :
103 : : Therefore, when clone materialization finds a call statement which it knows is
104 : : a part of a transitive split, it will simply add as arguments all new "split"
105 : : replacements (that have grater or equal offset than the original call
106 : : argument):
107 : :
108 : : foo (repl_for_a, repl_for_b, <rest of original arguments>);
109 : :
110 : : It will also store into ipa_edge_modification_info (which is internal to
111 : : ipa-param-modification.c) information about which replacement is which and
112 : : where original arguments are. Call redirection will then invoke
113 : : ipa_param_adjustments::modify_call which will access this information and
114 : : eliminate all replacements which the callee does not expect (repl_for_a in our
115 : : example above). In between these two steps, however, a call statement might
116 : : have extraneous arguments. */
117 : :
118 : : #ifndef IPA_PARAM_MANIPULATION_H
119 : : #define IPA_PARAM_MANIPULATION_H
120 : :
121 : : /* Indices into ipa_param_prefixes to identify a human-readable prefix for newly
122 : : synthesized parameters. Keep in sync with the array. */
123 : : enum ipa_param_name_prefix_indices
124 : : {
125 : : IPA_PARAM_PREFIX_SYNTH,
126 : : IPA_PARAM_PREFIX_ISRA,
127 : : IPA_PARAM_PREFIX_SIMD,
128 : : IPA_PARAM_PREFIX_MASK,
129 : : IPA_PARAM_PREFIX_COUNT
130 : : };
131 : :
132 : : /* We do not support manipulating functions with more than
133 : : 1<<IPA_PARAM_MAX_INDEX_BITS parameters. */
134 : : #define IPA_PARAM_MAX_INDEX_BITS 16
135 : :
136 : : /* Operation to be performed for the parameter in ipa_parm_adjustment
137 : : below. */
138 : :
139 : : enum ipa_parm_op
140 : : {
141 : : /* Do not use or you will trigger an assert. */
142 : : IPA_PARAM_OP_UNDEFINED,
143 : :
144 : : /* This new parameter is an unmodified parameter at index base_index. */
145 : : IPA_PARAM_OP_COPY,
146 : :
147 : : /* This describes a brand new parameter. If it somehow relates to any
148 : : original parameters, the user needs to manage the transition itself. */
149 : : IPA_PARAM_OP_NEW,
150 : :
151 : : /* Split parameter as indicated by fields base_index, offset and type. */
152 : : IPA_PARAM_OP_SPLIT
153 : : };
154 : :
155 : : /* Structure that describes one parameter of a function after transformation.
156 : : Omitted parameters will be removed. */
157 : :
158 : : struct GTY(()) ipa_adjusted_param
159 : : {
160 : : /* Type of the new parameter. Required for all operations except
161 : : IPA_PARM_OP_COPY when the original type will be preserved. */
162 : : tree type;
163 : :
164 : : /* Alias reference type to be used in MEM_REFs when adjusting caller
165 : : arguments. Required for IPA_PARM_OP_SPLIT operation. */
166 : : tree alias_ptr_type;
167 : :
168 : : /* Offset into the original parameter (for the cases when the new parameter
169 : : is a component of an original one). Required for IPA_PARM_OP_SPLIT
170 : : operation. */
171 : : unsigned unit_offset;
172 : :
173 : : /* Zero based index of the original parameter this one is based on. Required
174 : : for IPA_PARAM_OP_COPY and IPA_PARAM_OP_SPLIT, users of IPA_PARAM_OP_NEW
175 : : only need to specify it if they use replacement lookup provided by
176 : : ipa_param_body_adjustments. */
177 : : unsigned base_index : IPA_PARAM_MAX_INDEX_BITS;
178 : :
179 : : /* Zero based index of the parameter this one is based on in the previous
180 : : clone. If there is no previous clone, it must be equal to base_index. */
181 : : unsigned prev_clone_index : IPA_PARAM_MAX_INDEX_BITS;
182 : :
183 : : /* Specify the operation, if any, to be performed on the parameter. */
184 : : enum ipa_parm_op op : 2;
185 : :
186 : : /* If set, this structure describes a parameter copied over from a previous
187 : : IPA clone, any transformations are thus not to be re-done. */
188 : : unsigned prev_clone_adjustment : 1;
189 : :
190 : : /* Index into ipa_param_prefixes specifying a prefix to be used with
191 : : DECL_NAMEs of newly synthesized parameters. */
192 : : unsigned param_prefix_index : 2;
193 : :
194 : : /* Storage order of the original parameter (for the cases when the new
195 : : parameter is a component of an original one). */
196 : : unsigned reverse : 1;
197 : :
198 : : /* A bit free for the user. */
199 : : unsigned user_flag : 1;
200 : : };
201 : :
202 : : void ipa_dump_adjusted_parameters (FILE *f,
203 : : vec<ipa_adjusted_param, va_gc> *adj_params);
204 : :
205 : : /* Class used to record planned modifications to parameters of a function and
206 : : also to perform necessary modifications at the caller side at the gimple
207 : : level. Used to describe all cgraph node clones that have their parameters
208 : : changed, therefore the class should only have a small memory footprint. */
209 : :
210 : : class GTY(()) ipa_param_adjustments
211 : : {
212 : : public:
213 : : /* Constructor from NEW_PARAMS showing how new parameters should look like
214 : : plus copying any pre-existing actual arguments starting from argument
215 : : with index ALWAYS_COPY_START (if non-negative, negative means do not copy
216 : : anything beyond what is described in NEW_PARAMS), and SKIP_RETURN, which
217 : : indicates that the function should return void after transformation. */
218 : :
219 : 153981 : ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params,
220 : : int always_copy_start, bool skip_return)
221 : 153981 : : m_adj_params (new_params), m_always_copy_start (always_copy_start),
222 : 153981 : m_skip_return (skip_return)
223 : : {}
224 : :
225 : : /* Modify a call statement arguments (and possibly remove the return value)
226 : : as described in the data fields of this class. */
227 : : gcall *modify_call (cgraph_edge *cs, bool update_references,
228 : : hash_set <tree> *killed_ssas);
229 : : /* Return if the first parameter is left intact. */
230 : : bool first_param_intact_p ();
231 : : /* Build a function type corresponding to the modified call. */
232 : : tree build_new_function_type (tree old_type, bool type_is_original_p,
233 : : bool *args_modified = NULL);
234 : : /* Build a declaration corresponding to the target of the modified call. */
235 : : tree adjust_decl (tree orig_decl);
236 : : /* Fill a vector marking which parameters are intact by the described
237 : : modifications. */
238 : : void get_surviving_params (vec<bool> *surviving_params);
239 : : /* Fill a vector with new indices of surviving original parameters. */
240 : : void get_updated_indices (vec<int> *new_indices);
241 : : /* Return the original index for the given new parameter index. Return a
242 : : negative number if not available. */
243 : : int get_original_index (int newidx);
244 : :
245 : : void dump (FILE *f);
246 : : void debug ();
247 : :
248 : : /* How the known part of arguments should look like. */
249 : : vec<ipa_adjusted_param, va_gc> *m_adj_params;
250 : :
251 : : /* If non-negative, copy any arguments starting at this offset without any
252 : : modifications so that functions with variable number of arguments can be
253 : : modified. This number should be equal to the number of original forma
254 : : parameters. */
255 : : int m_always_copy_start;
256 : : /* If true, make the function not return any value. */
257 : : bool m_skip_return;
258 : :
259 : : static bool type_attribute_allowed_p (tree);
260 : : private:
261 : : ipa_param_adjustments () {}
262 : :
263 : : void init (vec<tree> *cur_params);
264 : : int get_max_base_index ();
265 : : bool method2func_p (tree orig_type);
266 : : };
267 : :
268 : : /* Structure used to map expressions accessing split or replaced parameters to
269 : : new PARM_DECLs. */
270 : :
271 : : struct ipa_param_body_replacement
272 : : {
273 : : /* The old decl of the original parameter. */
274 : : tree base;
275 : : /* The new decl it should be replaced with. */
276 : : tree repl;
277 : : /* Users of ipa_param_body_adjustments that modify standalone functions
278 : : outside of IPA clone materialization can use the following field for their
279 : : internal purposes. */
280 : : tree dummy;
281 : : /* The offset within BASE that REPL represents. */
282 : : unsigned unit_offset;
283 : : };
284 : :
285 : : struct ipa_replace_map;
286 : :
287 : : /* Class used when actually performing adjustments to formal parameters of a
288 : : function to map accesses that need to be replaced to replacements. The
289 : : class attempts to work in two very different sets of circumstances: as a
290 : : part of tree-inine.c's tree_function_versioning machinery to clone functions
291 : : (when M_ID is not NULL) and in s standalone fashion, modifying an existing
292 : : function in place (when M_ID is NULL). While a lot of stuff handled in a
293 : : unified way in both modes, there are many aspects of the processs that
294 : : requires distinct paths. */
295 : :
296 : : class ipa_param_body_adjustments
297 : : {
298 : : public:
299 : : /* Constructor to use from within tree-inline. */
300 : : ipa_param_body_adjustments (ipa_param_adjustments *adjustments,
301 : : tree fndecl, tree old_fndecl,
302 : : struct copy_body_data *id, tree *vars,
303 : : vec<ipa_replace_map *, va_gc> *tree_map);
304 : : /* Constructor to use for modifying a function outside of tree-inline from an
305 : : instance of ipa_param_adjustments. */
306 : : ipa_param_body_adjustments (ipa_param_adjustments *adjustments,
307 : : tree fndecl);
308 : : /* Constructor to use for modifying a function outside of tree-inline from a
309 : : simple vector of desired parameter modification. */
310 : : ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params,
311 : : tree fndecl);
312 : :
313 : : /* The do-it-all function for modifying a function outside of
314 : : tree-inline. */
315 : : bool perform_cfun_body_modifications ();
316 : :
317 : : /* Change the PARM_DECLs. */
318 : : void modify_formal_parameters ();
319 : : /* Register a REPLACEMENT for accesses to BASE at UNIT_OFFSET. */
320 : : void register_replacement (tree base, unsigned unit_offset, tree replacement);
321 : : /* Register a replacement decl for the transformation done in APM. */
322 : : void register_replacement (ipa_adjusted_param *apm, tree replacement);
323 : : /* Sort m_replacements and set m_sorted_replacements_p to true. Users that
324 : : call register_replacement themselves must call the method before any
325 : : lookup and thus also any statement or expression modification. */
326 : : void sort_replacements ();
327 : : /* Lookup a replacement for a given offset within a given parameter. */
328 : : tree lookup_replacement (tree base, unsigned unit_offset);
329 : : /* Lookup a replacement for an expression, if there is one. */
330 : : ipa_param_body_replacement *get_expr_replacement (tree expr,
331 : : bool ignore_default_def);
332 : : /* Lookup the new base for surviving names previously belonging to a
333 : : parameter. */
334 : : tree get_replacement_ssa_base (tree old_decl);
335 : : /* Modify a statement. */
336 : : bool modify_gimple_stmt (gimple **stmt, gimple_seq *extra_stmts,
337 : : gimple *orig_stmt);
338 : : /* Return the new chain of parameters. */
339 : : tree get_new_param_chain ();
340 : : /* Replace all occurances of SSAs in m_dead_ssa_debug_equiv in t with what
341 : : they are mapped to. */
342 : : void remap_with_debug_expressions (tree *t);
343 : :
344 : : /* If there are any initialization statements that need to be emitted into
345 : : the basic block BB right at ther start of the new function, do so. */
346 : : void append_init_stmts (basic_block bb);
347 : :
348 : : /* Pointers to data structures defining how the function should be
349 : : modified. */
350 : : vec<ipa_adjusted_param, va_gc> *m_adj_params;
351 : : ipa_param_adjustments *m_adjustments;
352 : :
353 : : /* Vector of old parameter declarations that must have their debug bind
354 : : statements re-mapped and debug decls created. */
355 : :
356 : : auto_vec<tree, 16> m_reset_debug_decls;
357 : :
358 : : /* Sets of statements and SSA_NAMEs that only manipulate data from parameters
359 : : removed because they are not necessary. */
360 : : hash_set<gimple *> m_dead_stmts;
361 : : hash_set<tree> m_dead_ssas;
362 : :
363 : : /* Mapping from DCEd SSAs to what their potential debug_binds should be. */
364 : : hash_map<tree, tree> m_dead_ssa_debug_equiv;
365 : : /* Mapping from DCEd statements to debug expressions that will be placed on
366 : : the RHS of debug statement that will replace this one. */
367 : : hash_map<gimple *, tree> m_dead_stmt_debug_equiv;
368 : :
369 : : private:
370 : : void common_initialization (tree old_fndecl, tree *vars,
371 : : vec<ipa_replace_map *, va_gc> *tree_map);
372 : : tree carry_over_param (tree t);
373 : : unsigned get_base_index (ipa_adjusted_param *apm);
374 : : ipa_param_body_replacement *lookup_replacement_1 (tree base,
375 : : unsigned unit_offset);
376 : : ipa_param_body_replacement *lookup_first_base_replacement (tree base);
377 : : tree replace_removed_params_ssa_names (tree old_name, gimple *stmt);
378 : : bool modify_expression (tree *expr_p, bool convert, gimple_seq * = nullptr);
379 : : bool modify_assignment (gimple *stmt, gimple_seq *extra_stmts);
380 : : bool modify_call_stmt (gcall **stmt_p, gimple *orig_stmt);
381 : : bool modify_cfun_body ();
382 : : void reset_debug_stmts ();
383 : : tree get_ddef_if_exists_and_is_used (tree decl);
384 : : void mark_dead_statements (tree dead_param, vec<tree> *debugstack);
385 : : void mark_clobbers_dead (tree dead_param);
386 : : bool prepare_debug_expressions (tree dead_ssa);
387 : :
388 : : /* Declaration of the function that is being transformed. */
389 : :
390 : : tree m_fndecl;
391 : :
392 : : /* If non-NULL, the tree-inline master data structure guiding materialization
393 : : of the current clone. */
394 : : struct copy_body_data *m_id;
395 : :
396 : : /* Vector of old parameter declarations (before changing them). */
397 : :
398 : : auto_vec<tree, 16> m_oparms;
399 : :
400 : : /* Vector of parameter declarations the function will have after
401 : : transformation. */
402 : :
403 : : auto_vec<tree, 16> m_new_decls;
404 : :
405 : : /* If the function type has non-NULL TYPE_ARG_TYPES, this is the vector of
406 : : these types after transformation, otherwise an empty one. */
407 : :
408 : : auto_vec<tree, 16> m_new_types;
409 : :
410 : : /* Vector of structures telling how to replace old parameters in the
411 : : function body. TODO: Even though there usually be only few, but should we
412 : : use a hash? */
413 : :
414 : : auto_vec<ipa_param_body_replacement, 16> m_replacements;
415 : :
416 : : /* List of initialization assignments to be put at the beginning of the
417 : : cloned function to deal with split aggregates which however have known
418 : : constant value and so their PARM_DECL disappears. */
419 : :
420 : : auto_vec<gimple *, 8> m_split_agg_csts_inits;
421 : :
422 : : /* Vector for remapping SSA_BASES from old parameter declarations that are
423 : : being removed as a part of the transformation. Before a new VAR_DECL is
424 : : created, it holds the old PARM_DECL, once the variable is built it is
425 : : stored here. */
426 : :
427 : : auto_vec<tree> m_removed_decls;
428 : :
429 : : /* Hash to quickly lookup the item in m_removed_decls given the old decl. */
430 : :
431 : : hash_map<tree, unsigned> m_removed_map;
432 : :
433 : : /* True iff the transformed function is a class method that is about to loose
434 : : its this pointer and must be converted to a normal function. */
435 : :
436 : : bool m_method2func;
437 : :
438 : : /* True if m_replacements have ben sorted since the last insertion. */
439 : :
440 : : bool m_sorted_replacements_p;
441 : : };
442 : :
443 : : void push_function_arg_decls (vec<tree> *args, tree fndecl);
444 : : void push_function_arg_types (vec<tree> *types, tree fntype);
445 : : void ipa_verify_edge_has_no_modifications (cgraph_edge *cs);
446 : : void ipa_edge_modifications_finalize ();
447 : : void ipa_release_ssas_in_hash (hash_set <tree> *killed_ssas);
448 : :
449 : : #endif /* IPA_PARAM_MANIPULATION_H */
|