1 | /* Manipulation of formal and actual parameters of functions and function |
2 | calls. |
3 | Copyright (C) 2017-2023 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 | ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params, |
220 | int always_copy_start, bool skip_return) |
221 | : m_adj_params (new_params), m_always_copy_start (always_copy_start), |
222 | 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 | /* Return if the first parameter is left intact. */ |
229 | bool first_param_intact_p (); |
230 | /* Build a function type corresponding to the modified call. */ |
231 | tree build_new_function_type (tree old_type, bool type_is_original_p); |
232 | /* Build a declaration corresponding to the target of the modified call. */ |
233 | tree adjust_decl (tree orig_decl); |
234 | /* Fill a vector marking which parameters are intact by the described |
235 | modifications. */ |
236 | void get_surviving_params (vec<bool> *surviving_params); |
237 | /* Fill a vector with new indices of surviving original parameters. */ |
238 | void get_updated_indices (vec<int> *new_indices); |
239 | /* Return the original index for the given new parameter index. Return a |
240 | negative number if not available. */ |
241 | int get_original_index (int newidx); |
242 | |
243 | void dump (FILE *f); |
244 | void debug (); |
245 | |
246 | /* How the known part of arguments should look like. */ |
247 | vec<ipa_adjusted_param, va_gc> *m_adj_params; |
248 | |
249 | /* If non-negative, copy any arguments starting at this offset without any |
250 | modifications so that functions with variable number of arguments can be |
251 | modified. This number should be equal to the number of original forma |
252 | parameters. */ |
253 | int m_always_copy_start; |
254 | /* If true, make the function not return any value. */ |
255 | bool m_skip_return; |
256 | |
257 | static bool type_attribute_allowed_p (tree); |
258 | private: |
259 | ipa_param_adjustments () {} |
260 | |
261 | void init (vec<tree> *cur_params); |
262 | int get_max_base_index (); |
263 | bool method2func_p (tree orig_type); |
264 | }; |
265 | |
266 | /* Structure used to map expressions accessing split or replaced parameters to |
267 | new PARM_DECLs. */ |
268 | |
269 | struct ipa_param_body_replacement |
270 | { |
271 | /* The old decl of the original parameter. */ |
272 | tree base; |
273 | /* The new decl it should be replaced with. */ |
274 | tree repl; |
275 | /* Users of ipa_param_body_adjustments that modify standalone functions |
276 | outside of IPA clone materialization can use the following field for their |
277 | internal purposes. */ |
278 | tree dummy; |
279 | /* The offset within BASE that REPL represents. */ |
280 | unsigned unit_offset; |
281 | }; |
282 | |
283 | struct ipa_replace_map; |
284 | |
285 | /* Class used when actually performing adjustments to formal parameters of a |
286 | function to map accesses that need to be replaced to replacements. The |
287 | class attempts to work in two very different sets of circumstances: as a |
288 | part of tree-inine.c's tree_function_versioning machinery to clone functions |
289 | (when M_ID is not NULL) and in s standalone fashion, modifying an existing |
290 | function in place (when M_ID is NULL). While a lot of stuff handled in a |
291 | unified way in both modes, there are many aspects of the processs that |
292 | requires distinct paths. */ |
293 | |
294 | class ipa_param_body_adjustments |
295 | { |
296 | public: |
297 | /* Constructor to use from within tree-inline. */ |
298 | ipa_param_body_adjustments (ipa_param_adjustments *adjustments, |
299 | tree fndecl, tree old_fndecl, |
300 | struct copy_body_data *id, tree *vars, |
301 | vec<ipa_replace_map *, va_gc> *tree_map); |
302 | /* Constructor to use for modifying a function outside of tree-inline from an |
303 | instance of ipa_param_adjustments. */ |
304 | ipa_param_body_adjustments (ipa_param_adjustments *adjustments, |
305 | tree fndecl); |
306 | /* Constructor to use for modifying a function outside of tree-inline from a |
307 | simple vector of desired parameter modification. */ |
308 | ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params, |
309 | tree fndecl); |
310 | |
311 | /* The do-it-all function for modifying a function outside of |
312 | tree-inline. */ |
313 | bool perform_cfun_body_modifications (); |
314 | |
315 | /* Change the PARM_DECLs. */ |
316 | void modify_formal_parameters (); |
317 | /* Register a REPLACEMENT for accesses to BASE at UNIT_OFFSET. */ |
318 | void register_replacement (tree base, unsigned unit_offset, tree replacement); |
319 | /* Register a replacement decl for the transformation done in APM. */ |
320 | void register_replacement (ipa_adjusted_param *apm, tree replacement); |
321 | /* Sort m_replacements and set m_sorted_replacements_p to true. Users that |
322 | call register_replacement themselves must call the method before any |
323 | lookup and thus also any statement or expression modification. */ |
324 | void sort_replacements (); |
325 | /* Lookup a replacement for a given offset within a given parameter. */ |
326 | tree lookup_replacement (tree base, unsigned unit_offset); |
327 | /* Lookup a replacement for an expression, if there is one. */ |
328 | ipa_param_body_replacement *get_expr_replacement (tree expr, |
329 | bool ignore_default_def); |
330 | /* Lookup the new base for surviving names previously belonging to a |
331 | parameter. */ |
332 | tree get_replacement_ssa_base (tree old_decl); |
333 | /* Modify a statement. */ |
334 | bool modify_gimple_stmt (gimple **stmt, gimple_seq *, |
335 | gimple *orig_stmt); |
336 | /* Return the new chain of parameters. */ |
337 | tree get_new_param_chain (); |
338 | /* Replace all occurances of SSAs in m_dead_ssa_debug_equiv in t with what |
339 | they are mapped to. */ |
340 | void remap_with_debug_expressions (tree *t); |
341 | |
342 | /* If there are any initialization statements that need to be emitted into |
343 | the basic block BB right at ther start of the new function, do so. */ |
344 | void append_init_stmts (basic_block bb); |
345 | |
346 | /* Pointers to data structures defining how the function should be |
347 | modified. */ |
348 | vec<ipa_adjusted_param, va_gc> *m_adj_params; |
349 | ipa_param_adjustments *m_adjustments; |
350 | |
351 | /* Vector of old parameter declarations that must have their debug bind |
352 | statements re-mapped and debug decls created. */ |
353 | |
354 | auto_vec<tree, 16> m_reset_debug_decls; |
355 | |
356 | /* Sets of statements and SSA_NAMEs that only manipulate data from parameters |
357 | removed because they are not necessary. */ |
358 | hash_set<gimple *> m_dead_stmts; |
359 | hash_set<tree> m_dead_ssas; |
360 | |
361 | /* Mapping from DCEd SSAs to what their potential debug_binds should be. */ |
362 | hash_map<tree, tree> m_dead_ssa_debug_equiv; |
363 | /* Mapping from DCEd statements to debug expressions that will be placed on |
364 | the RHS of debug statement that will replace this one. */ |
365 | hash_map<gimple *, tree> m_dead_stmt_debug_equiv; |
366 | |
367 | private: |
368 | void common_initialization (tree old_fndecl, tree *vars, |
369 | vec<ipa_replace_map *, va_gc> *tree_map); |
370 | tree carry_over_param (tree t); |
371 | unsigned get_base_index (ipa_adjusted_param *apm); |
372 | ipa_param_body_replacement *lookup_replacement_1 (tree base, |
373 | unsigned unit_offset); |
374 | ipa_param_body_replacement *lookup_first_base_replacement (tree base); |
375 | tree replace_removed_params_ssa_names (tree old_name, gimple *stmt); |
376 | bool modify_expression (tree *expr_p, bool convert, gimple_seq * = nullptr); |
377 | bool modify_assignment (gimple *stmt, gimple_seq *); |
378 | bool modify_call_stmt (gcall **stmt_p, gimple *orig_stmt); |
379 | bool modify_cfun_body (); |
380 | void reset_debug_stmts (); |
381 | tree get_ddef_if_exists_and_is_used (tree decl); |
382 | void mark_dead_statements (tree dead_param, vec<tree> *debugstack); |
383 | void mark_clobbers_dead (tree dead_param); |
384 | bool prepare_debug_expressions (tree dead_ssa); |
385 | |
386 | /* Declaration of the function that is being transformed. */ |
387 | |
388 | tree m_fndecl; |
389 | |
390 | /* If non-NULL, the tree-inline master data structure guiding materialization |
391 | of the current clone. */ |
392 | struct copy_body_data *m_id; |
393 | |
394 | /* Vector of old parameter declarations (before changing them). */ |
395 | |
396 | auto_vec<tree, 16> m_oparms; |
397 | |
398 | /* Vector of parameter declarations the function will have after |
399 | transformation. */ |
400 | |
401 | auto_vec<tree, 16> m_new_decls; |
402 | |
403 | /* If the function type has non-NULL TYPE_ARG_TYPES, this is the vector of |
404 | these types after transformation, otherwise an empty one. */ |
405 | |
406 | auto_vec<tree, 16> m_new_types; |
407 | |
408 | /* Vector of structures telling how to replace old parameters in the |
409 | function body. TODO: Even though there usually be only few, but should we |
410 | use a hash? */ |
411 | |
412 | auto_vec<ipa_param_body_replacement, 16> m_replacements; |
413 | |
414 | /* List of initialization assignments to be put at the beginning of the |
415 | cloned function to deal with split aggregates which however have known |
416 | constant value and so their PARM_DECL disappears. */ |
417 | |
418 | auto_vec<gimple *, 8> m_split_agg_csts_inits; |
419 | |
420 | /* Vector for remapping SSA_BASES from old parameter declarations that are |
421 | being removed as a part of the transformation. Before a new VAR_DECL is |
422 | created, it holds the old PARM_DECL, once the variable is built it is |
423 | stored here. */ |
424 | |
425 | auto_vec<tree> m_removed_decls; |
426 | |
427 | /* Hash to quickly lookup the item in m_removed_decls given the old decl. */ |
428 | |
429 | hash_map<tree, unsigned> m_removed_map; |
430 | |
431 | /* True iff the transformed function is a class method that is about to loose |
432 | its this pointer and must be converted to a normal function. */ |
433 | |
434 | bool m_method2func; |
435 | |
436 | /* True if m_replacements have ben sorted since the last insertion. */ |
437 | |
438 | bool m_sorted_replacements_p; |
439 | }; |
440 | |
441 | void push_function_arg_decls (vec<tree> *args, tree fndecl); |
442 | void push_function_arg_types (vec<tree> *types, tree fntype); |
443 | void ipa_verify_edge_has_no_modifications (cgraph_edge *cs); |
444 | void ipa_edge_modifications_finalize (); |
445 | |
446 | |
447 | #endif /* IPA_PARAM_MANIPULATION_H */ |
448 | |