]>
Commit | Line | Data |
---|---|---|
ac762bff | 1 | /* Manipulation of formal and actual parameters of functions and function |
2 | calls. | |
3 | Copyright (C) 2017 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 | #include "config.h" | |
22 | #include "system.h" | |
23 | #include "coretypes.h" | |
24 | #include "backend.h" | |
25 | #include "rtl.h" | |
26 | #include "tree.h" | |
27 | #include "gimple.h" | |
28 | #include "ssa.h" | |
29 | #include "cgraph.h" | |
30 | #include "fold-const.h" | |
31 | #include "stor-layout.h" | |
32 | #include "gimplify.h" | |
33 | #include "gimple-iterator.h" | |
34 | #include "gimplify-me.h" | |
35 | #include "tree-dfa.h" | |
36 | #include "ipa-param-manipulation.h" | |
37 | #include "print-tree.h" | |
38 | #include "gimple-pretty-print.h" | |
39 | #include "builtins.h" | |
40 | ||
41 | /* Return a heap allocated vector containing formal parameters of FNDECL. */ | |
42 | ||
43 | vec<tree> | |
44 | ipa_get_vector_of_formal_parms (tree fndecl) | |
45 | { | |
46 | vec<tree> args; | |
47 | int count; | |
48 | tree parm; | |
49 | ||
50 | gcc_assert (!flag_wpa); | |
51 | count = 0; | |
52 | for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) | |
53 | count++; | |
54 | ||
55 | args.create (count); | |
56 | for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) | |
57 | args.quick_push (parm); | |
58 | ||
59 | return args; | |
60 | } | |
61 | ||
62 | /* Return a heap allocated vector containing types of formal parameters of | |
63 | function type FNTYPE. */ | |
64 | ||
65 | vec<tree> | |
66 | ipa_get_vector_of_formal_parm_types (tree fntype) | |
67 | { | |
68 | vec<tree> types; | |
69 | int count = 0; | |
70 | tree t; | |
71 | ||
72 | for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) | |
73 | count++; | |
74 | ||
75 | types.create (count); | |
76 | for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) | |
77 | types.quick_push (TREE_VALUE (t)); | |
78 | ||
79 | return types; | |
80 | } | |
81 | ||
82 | /* Modify the function declaration FNDECL and its type according to the plan in | |
83 | ADJUSTMENTS. It also sets base fields of individual adjustments structures | |
84 | to reflect the actual parameters being modified which are determined by the | |
85 | base_index field. */ | |
86 | ||
87 | void | |
88 | ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments) | |
89 | { | |
90 | vec<tree> oparms = ipa_get_vector_of_formal_parms (fndecl); | |
91 | tree orig_type = TREE_TYPE (fndecl); | |
92 | tree old_arg_types = TYPE_ARG_TYPES (orig_type); | |
93 | ||
94 | /* The following test is an ugly hack, some functions simply don't have any | |
95 | arguments in their type. This is probably a bug but well... */ | |
96 | bool care_for_types = (old_arg_types != NULL_TREE); | |
97 | bool last_parm_void; | |
98 | vec<tree> otypes; | |
99 | if (care_for_types) | |
100 | { | |
101 | last_parm_void = (TREE_VALUE (tree_last (old_arg_types)) | |
102 | == void_type_node); | |
103 | otypes = ipa_get_vector_of_formal_parm_types (orig_type); | |
104 | if (last_parm_void) | |
105 | gcc_assert (oparms.length () + 1 == otypes.length ()); | |
106 | else | |
107 | gcc_assert (oparms.length () == otypes.length ()); | |
108 | } | |
109 | else | |
110 | { | |
111 | last_parm_void = false; | |
112 | otypes.create (0); | |
113 | } | |
114 | ||
115 | int len = adjustments.length (); | |
116 | tree *link = &DECL_ARGUMENTS (fndecl); | |
117 | tree new_arg_types = NULL; | |
118 | for (int i = 0; i < len; i++) | |
119 | { | |
120 | struct ipa_parm_adjustment *adj; | |
121 | gcc_assert (link); | |
122 | ||
123 | adj = &adjustments[i]; | |
124 | tree parm; | |
125 | if (adj->op == IPA_PARM_OP_NEW) | |
126 | parm = NULL; | |
127 | else | |
128 | parm = oparms[adj->base_index]; | |
129 | adj->base = parm; | |
130 | ||
131 | if (adj->op == IPA_PARM_OP_COPY) | |
132 | { | |
133 | if (care_for_types) | |
134 | new_arg_types = tree_cons (NULL_TREE, otypes[adj->base_index], | |
135 | new_arg_types); | |
136 | *link = parm; | |
137 | link = &DECL_CHAIN (parm); | |
138 | } | |
139 | else if (adj->op != IPA_PARM_OP_REMOVE) | |
140 | { | |
141 | tree new_parm; | |
142 | tree ptype; | |
143 | ||
144 | if (adj->by_ref) | |
145 | ptype = build_pointer_type (adj->type); | |
146 | else | |
147 | { | |
148 | ptype = adj->type; | |
149 | if (is_gimple_reg_type (ptype) | |
150 | && TYPE_MODE (ptype) != BLKmode) | |
151 | { | |
152 | unsigned malign = GET_MODE_ALIGNMENT (TYPE_MODE (ptype)); | |
153 | if (TYPE_ALIGN (ptype) != malign) | |
154 | ptype = build_aligned_type (ptype, malign); | |
155 | } | |
156 | } | |
157 | ||
158 | if (care_for_types) | |
159 | new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types); | |
160 | ||
161 | new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE, | |
162 | ptype); | |
163 | const char *prefix = adj->arg_prefix ? adj->arg_prefix : "SYNTH"; | |
164 | DECL_NAME (new_parm) = create_tmp_var_name (prefix); | |
165 | DECL_ARTIFICIAL (new_parm) = 1; | |
166 | DECL_ARG_TYPE (new_parm) = ptype; | |
167 | DECL_CONTEXT (new_parm) = fndecl; | |
168 | TREE_USED (new_parm) = 1; | |
169 | DECL_IGNORED_P (new_parm) = 1; | |
170 | layout_decl (new_parm, 0); | |
171 | ||
172 | if (adj->op == IPA_PARM_OP_NEW) | |
173 | adj->base = NULL; | |
174 | else | |
175 | adj->base = parm; | |
176 | adj->new_decl = new_parm; | |
177 | ||
178 | *link = new_parm; | |
179 | link = &DECL_CHAIN (new_parm); | |
180 | } | |
181 | } | |
182 | ||
183 | *link = NULL_TREE; | |
184 | ||
185 | tree new_reversed = NULL; | |
186 | if (care_for_types) | |
187 | { | |
188 | new_reversed = nreverse (new_arg_types); | |
189 | if (last_parm_void) | |
190 | { | |
191 | if (new_reversed) | |
192 | TREE_CHAIN (new_arg_types) = void_list_node; | |
193 | else | |
194 | new_reversed = void_list_node; | |
195 | } | |
196 | } | |
197 | ||
198 | /* Use copy_node to preserve as much as possible from original type | |
199 | (debug info, attribute lists etc.) | |
200 | Exception is METHOD_TYPEs must have THIS argument. | |
201 | When we are asked to remove it, we need to build new FUNCTION_TYPE | |
202 | instead. */ | |
203 | tree new_type = NULL; | |
204 | if (TREE_CODE (orig_type) != METHOD_TYPE | |
205 | || (adjustments[0].op == IPA_PARM_OP_COPY | |
206 | && adjustments[0].base_index == 0)) | |
207 | { | |
208 | new_type = build_distinct_type_copy (orig_type); | |
209 | TYPE_ARG_TYPES (new_type) = new_reversed; | |
210 | } | |
211 | else | |
212 | { | |
213 | new_type | |
214 | = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type), | |
215 | new_reversed)); | |
216 | TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type); | |
217 | DECL_VINDEX (fndecl) = NULL_TREE; | |
218 | } | |
219 | ||
220 | /* When signature changes, we need to clear builtin info. */ | |
221 | if (DECL_BUILT_IN (fndecl)) | |
222 | { | |
223 | DECL_BUILT_IN_CLASS (fndecl) = NOT_BUILT_IN; | |
224 | DECL_FUNCTION_CODE (fndecl) = (enum built_in_function) 0; | |
225 | } | |
226 | ||
227 | TREE_TYPE (fndecl) = new_type; | |
228 | DECL_VIRTUAL_P (fndecl) = 0; | |
229 | DECL_LANG_SPECIFIC (fndecl) = NULL; | |
230 | otypes.release (); | |
231 | oparms.release (); | |
232 | } | |
233 | ||
234 | /* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS. | |
235 | If this is a directly recursive call, CS must be NULL. Otherwise it must | |
236 | contain the corresponding call graph edge. */ | |
237 | ||
238 | void | |
239 | ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt, | |
240 | ipa_parm_adjustment_vec adjustments) | |
241 | { | |
242 | struct cgraph_node *current_node = cgraph_node::get (current_function_decl); | |
243 | vec<tree> vargs; | |
244 | vec<tree, va_gc> **debug_args = NULL; | |
245 | gcall *new_stmt; | |
246 | gimple_stmt_iterator gsi, prev_gsi; | |
247 | tree callee_decl; | |
248 | int i, len; | |
249 | ||
250 | len = adjustments.length (); | |
251 | vargs.create (len); | |
252 | callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl; | |
253 | current_node->remove_stmt_references (stmt); | |
254 | ||
255 | gsi = gsi_for_stmt (stmt); | |
256 | prev_gsi = gsi; | |
257 | gsi_prev (&prev_gsi); | |
258 | for (i = 0; i < len; i++) | |
259 | { | |
260 | struct ipa_parm_adjustment *adj; | |
261 | ||
262 | adj = &adjustments[i]; | |
263 | ||
264 | if (adj->op == IPA_PARM_OP_COPY) | |
265 | { | |
266 | tree arg = gimple_call_arg (stmt, adj->base_index); | |
267 | ||
268 | vargs.quick_push (arg); | |
269 | } | |
270 | else if (adj->op != IPA_PARM_OP_REMOVE) | |
271 | { | |
272 | tree expr, base, off; | |
273 | location_t loc; | |
274 | unsigned int deref_align = 0; | |
275 | bool deref_base = false; | |
276 | ||
277 | /* We create a new parameter out of the value of the old one, we can | |
278 | do the following kind of transformations: | |
279 | ||
280 | - A scalar passed by reference is converted to a scalar passed by | |
281 | value. (adj->by_ref is false and the type of the original | |
282 | actual argument is a pointer to a scalar). | |
283 | ||
284 | - A part of an aggregate is passed instead of the whole aggregate. | |
285 | The part can be passed either by value or by reference, this is | |
286 | determined by value of adj->by_ref. Moreover, the code below | |
287 | handles both situations when the original aggregate is passed by | |
288 | value (its type is not a pointer) and when it is passed by | |
289 | reference (it is a pointer to an aggregate). | |
290 | ||
291 | When the new argument is passed by reference (adj->by_ref is true) | |
292 | it must be a part of an aggregate and therefore we form it by | |
293 | simply taking the address of a reference inside the original | |
294 | aggregate. */ | |
295 | ||
296 | gcc_checking_assert (adj->offset % BITS_PER_UNIT == 0); | |
297 | base = gimple_call_arg (stmt, adj->base_index); | |
298 | loc = DECL_P (base) ? DECL_SOURCE_LOCATION (base) | |
299 | : EXPR_LOCATION (base); | |
300 | ||
301 | if (TREE_CODE (base) != ADDR_EXPR | |
302 | && POINTER_TYPE_P (TREE_TYPE (base))) | |
303 | off = build_int_cst (adj->alias_ptr_type, | |
304 | adj->offset / BITS_PER_UNIT); | |
305 | else | |
306 | { | |
307 | HOST_WIDE_INT base_offset; | |
308 | tree prev_base; | |
309 | bool addrof; | |
310 | ||
311 | if (TREE_CODE (base) == ADDR_EXPR) | |
312 | { | |
313 | base = TREE_OPERAND (base, 0); | |
314 | addrof = true; | |
315 | } | |
316 | else | |
317 | addrof = false; | |
318 | prev_base = base; | |
319 | base = get_addr_base_and_unit_offset (base, &base_offset); | |
320 | /* Aggregate arguments can have non-invariant addresses. */ | |
321 | if (!base) | |
322 | { | |
323 | base = build_fold_addr_expr (prev_base); | |
324 | off = build_int_cst (adj->alias_ptr_type, | |
325 | adj->offset / BITS_PER_UNIT); | |
326 | } | |
327 | else if (TREE_CODE (base) == MEM_REF) | |
328 | { | |
329 | if (!addrof) | |
330 | { | |
331 | deref_base = true; | |
332 | deref_align = TYPE_ALIGN (TREE_TYPE (base)); | |
333 | } | |
334 | off = build_int_cst (adj->alias_ptr_type, | |
335 | base_offset | |
336 | + adj->offset / BITS_PER_UNIT); | |
337 | off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), | |
338 | off); | |
339 | base = TREE_OPERAND (base, 0); | |
340 | } | |
341 | else | |
342 | { | |
343 | off = build_int_cst (adj->alias_ptr_type, | |
344 | base_offset | |
345 | + adj->offset / BITS_PER_UNIT); | |
346 | base = build_fold_addr_expr (base); | |
347 | } | |
348 | } | |
349 | ||
350 | if (!adj->by_ref) | |
351 | { | |
352 | tree type = adj->type; | |
353 | unsigned int align; | |
354 | unsigned HOST_WIDE_INT misalign; | |
355 | ||
356 | if (deref_base) | |
357 | { | |
358 | align = deref_align; | |
359 | misalign = 0; | |
360 | } | |
361 | else | |
362 | { | |
363 | get_pointer_alignment_1 (base, &align, &misalign); | |
364 | if (TYPE_ALIGN (type) > align) | |
365 | align = TYPE_ALIGN (type); | |
366 | } | |
367 | misalign += (offset_int::from (wi::to_wide (off), | |
368 | SIGNED).to_short_addr () | |
369 | * BITS_PER_UNIT); | |
370 | misalign = misalign & (align - 1); | |
371 | if (misalign != 0) | |
372 | align = least_bit_hwi (misalign); | |
373 | if (align < TYPE_ALIGN (type)) | |
374 | type = build_aligned_type (type, align); | |
375 | base = force_gimple_operand_gsi (&gsi, base, | |
376 | true, NULL, true, GSI_SAME_STMT); | |
377 | expr = fold_build2_loc (loc, MEM_REF, type, base, off); | |
378 | REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse; | |
379 | /* If expr is not a valid gimple call argument emit | |
380 | a load into a temporary. */ | |
381 | if (is_gimple_reg_type (TREE_TYPE (expr))) | |
382 | { | |
383 | gimple *tem = gimple_build_assign (NULL_TREE, expr); | |
384 | if (gimple_in_ssa_p (cfun)) | |
385 | { | |
386 | gimple_set_vuse (tem, gimple_vuse (stmt)); | |
387 | expr = make_ssa_name (TREE_TYPE (expr), tem); | |
388 | } | |
389 | else | |
390 | expr = create_tmp_reg (TREE_TYPE (expr)); | |
391 | gimple_assign_set_lhs (tem, expr); | |
392 | gsi_insert_before (&gsi, tem, GSI_SAME_STMT); | |
393 | } | |
394 | } | |
395 | else | |
396 | { | |
397 | expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off); | |
398 | REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse; | |
399 | expr = build_fold_addr_expr (expr); | |
400 | expr = force_gimple_operand_gsi (&gsi, expr, | |
401 | true, NULL, true, GSI_SAME_STMT); | |
402 | } | |
403 | vargs.quick_push (expr); | |
404 | } | |
405 | if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS) | |
406 | { | |
407 | unsigned int ix; | |
408 | tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg; | |
409 | gimple *def_temp; | |
410 | ||
411 | arg = gimple_call_arg (stmt, adj->base_index); | |
412 | if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE (arg))) | |
413 | { | |
414 | if (!fold_convertible_p (TREE_TYPE (origin), arg)) | |
415 | continue; | |
416 | arg = fold_convert_loc (gimple_location (stmt), | |
417 | TREE_TYPE (origin), arg); | |
418 | } | |
419 | if (debug_args == NULL) | |
420 | debug_args = decl_debug_args_insert (callee_decl); | |
421 | for (ix = 0; vec_safe_iterate (*debug_args, ix, &ddecl); ix += 2) | |
422 | if (ddecl == origin) | |
423 | { | |
424 | ddecl = (**debug_args)[ix + 1]; | |
425 | break; | |
426 | } | |
427 | if (ddecl == NULL) | |
428 | { | |
429 | ddecl = make_node (DEBUG_EXPR_DECL); | |
430 | DECL_ARTIFICIAL (ddecl) = 1; | |
431 | TREE_TYPE (ddecl) = TREE_TYPE (origin); | |
432 | SET_DECL_MODE (ddecl, DECL_MODE (origin)); | |
433 | ||
434 | vec_safe_push (*debug_args, origin); | |
435 | vec_safe_push (*debug_args, ddecl); | |
436 | } | |
437 | def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg), stmt); | |
438 | gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT); | |
439 | } | |
440 | } | |
441 | ||
442 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
443 | { | |
444 | fprintf (dump_file, "replacing stmt:"); | |
445 | print_gimple_stmt (dump_file, gsi_stmt (gsi), 0); | |
446 | } | |
447 | ||
448 | new_stmt = gimple_build_call_vec (callee_decl, vargs); | |
449 | vargs.release (); | |
450 | if (gimple_call_lhs (stmt)) | |
451 | gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); | |
452 | ||
453 | gimple_set_block (new_stmt, gimple_block (stmt)); | |
454 | if (gimple_has_location (stmt)) | |
455 | gimple_set_location (new_stmt, gimple_location (stmt)); | |
456 | gimple_call_set_chain (new_stmt, gimple_call_chain (stmt)); | |
457 | gimple_call_copy_flags (new_stmt, stmt); | |
458 | if (gimple_in_ssa_p (cfun)) | |
459 | { | |
460 | gimple_set_vuse (new_stmt, gimple_vuse (stmt)); | |
461 | if (gimple_vdef (stmt)) | |
462 | { | |
463 | gimple_set_vdef (new_stmt, gimple_vdef (stmt)); | |
464 | SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; | |
465 | } | |
466 | } | |
467 | ||
468 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
469 | { | |
470 | fprintf (dump_file, "with stmt:"); | |
471 | print_gimple_stmt (dump_file, new_stmt, 0); | |
472 | fprintf (dump_file, "\n"); | |
473 | } | |
474 | gsi_replace (&gsi, new_stmt, true); | |
475 | if (cs) | |
476 | cs->set_call_stmt (new_stmt); | |
477 | do | |
478 | { | |
479 | current_node->record_stmt_references (gsi_stmt (gsi)); | |
480 | gsi_prev (&gsi); | |
481 | } | |
482 | while (gsi_stmt (gsi) != gsi_stmt (prev_gsi)); | |
483 | } | |
484 | ||
485 | /* Return true iff BASE_INDEX is in ADJUSTMENTS more than once. */ | |
486 | ||
487 | static bool | |
488 | index_in_adjustments_multiple_times_p (int base_index, | |
489 | ipa_parm_adjustment_vec adjustments) | |
490 | { | |
491 | int i, len = adjustments.length (); | |
492 | bool one = false; | |
493 | ||
494 | for (i = 0; i < len; i++) | |
495 | { | |
496 | struct ipa_parm_adjustment *adj; | |
497 | adj = &adjustments[i]; | |
498 | ||
499 | if (adj->base_index == base_index) | |
500 | { | |
501 | if (one) | |
502 | return true; | |
503 | else | |
504 | one = true; | |
505 | } | |
506 | } | |
507 | return false; | |
508 | } | |
509 | ||
510 | /* Return adjustments that should have the same effect on function parameters | |
511 | and call arguments as if they were first changed according to adjustments in | |
512 | INNER and then by adjustments in OUTER. */ | |
513 | ||
514 | ipa_parm_adjustment_vec | |
515 | ipa_combine_adjustments (ipa_parm_adjustment_vec inner, | |
516 | ipa_parm_adjustment_vec outer) | |
517 | { | |
518 | int i, outlen = outer.length (); | |
519 | int inlen = inner.length (); | |
520 | int removals = 0; | |
521 | ipa_parm_adjustment_vec adjustments, tmp; | |
522 | ||
523 | tmp.create (inlen); | |
524 | for (i = 0; i < inlen; i++) | |
525 | { | |
526 | struct ipa_parm_adjustment *n; | |
527 | n = &inner[i]; | |
528 | ||
529 | if (n->op == IPA_PARM_OP_REMOVE) | |
530 | removals++; | |
531 | else | |
532 | { | |
533 | /* FIXME: Handling of new arguments are not implemented yet. */ | |
534 | gcc_assert (n->op != IPA_PARM_OP_NEW); | |
535 | tmp.quick_push (*n); | |
536 | } | |
537 | } | |
538 | ||
539 | adjustments.create (outlen + removals); | |
540 | for (i = 0; i < outlen; i++) | |
541 | { | |
542 | struct ipa_parm_adjustment r; | |
543 | struct ipa_parm_adjustment *out = &outer[i]; | |
544 | struct ipa_parm_adjustment *in = &tmp[out->base_index]; | |
545 | ||
546 | memset (&r, 0, sizeof (r)); | |
547 | gcc_assert (in->op != IPA_PARM_OP_REMOVE); | |
548 | if (out->op == IPA_PARM_OP_REMOVE) | |
549 | { | |
550 | if (!index_in_adjustments_multiple_times_p (in->base_index, tmp)) | |
551 | { | |
552 | r.op = IPA_PARM_OP_REMOVE; | |
553 | adjustments.quick_push (r); | |
554 | } | |
555 | continue; | |
556 | } | |
557 | else | |
558 | { | |
559 | /* FIXME: Handling of new arguments are not implemented yet. */ | |
560 | gcc_assert (out->op != IPA_PARM_OP_NEW); | |
561 | } | |
562 | ||
563 | r.base_index = in->base_index; | |
564 | r.type = out->type; | |
565 | ||
566 | /* FIXME: Create nonlocal value too. */ | |
567 | ||
568 | if (in->op == IPA_PARM_OP_COPY && out->op == IPA_PARM_OP_COPY) | |
569 | r.op = IPA_PARM_OP_COPY; | |
570 | else if (in->op == IPA_PARM_OP_COPY) | |
571 | r.offset = out->offset; | |
572 | else if (out->op == IPA_PARM_OP_COPY) | |
573 | r.offset = in->offset; | |
574 | else | |
575 | r.offset = in->offset + out->offset; | |
576 | adjustments.quick_push (r); | |
577 | } | |
578 | ||
579 | for (i = 0; i < inlen; i++) | |
580 | { | |
581 | struct ipa_parm_adjustment *n = &inner[i]; | |
582 | ||
583 | if (n->op == IPA_PARM_OP_REMOVE) | |
584 | adjustments.quick_push (*n); | |
585 | } | |
586 | ||
587 | tmp.release (); | |
588 | return adjustments; | |
589 | } | |
590 | ||
591 | /* If T is an SSA_NAME, return NULL if it is not a default def or | |
592 | return its base variable if it is. If IGNORE_DEFAULT_DEF is true, | |
593 | the base variable is always returned, regardless if it is a default | |
594 | def. Return T if it is not an SSA_NAME. */ | |
595 | ||
596 | static tree | |
597 | get_ssa_base_param (tree t, bool ignore_default_def) | |
598 | { | |
599 | if (TREE_CODE (t) == SSA_NAME) | |
600 | { | |
601 | if (ignore_default_def || SSA_NAME_IS_DEFAULT_DEF (t)) | |
602 | return SSA_NAME_VAR (t); | |
603 | else | |
604 | return NULL_TREE; | |
605 | } | |
606 | return t; | |
607 | } | |
608 | ||
609 | /* Given an expression, return an adjustment entry specifying the | |
610 | transformation to be done on EXPR. If no suitable adjustment entry | |
611 | was found, returns NULL. | |
612 | ||
613 | If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a | |
614 | default def, otherwise bail on them. | |
615 | ||
616 | If CONVERT is non-NULL, this function will set *CONVERT if the | |
617 | expression provided is a component reference. ADJUSTMENTS is the | |
618 | adjustments vector. */ | |
619 | ||
620 | ipa_parm_adjustment * | |
621 | ipa_get_adjustment_candidate (tree **expr, bool *convert, | |
622 | ipa_parm_adjustment_vec adjustments, | |
623 | bool ignore_default_def) | |
624 | { | |
625 | if (TREE_CODE (**expr) == BIT_FIELD_REF | |
626 | || TREE_CODE (**expr) == IMAGPART_EXPR | |
627 | || TREE_CODE (**expr) == REALPART_EXPR) | |
628 | { | |
629 | *expr = &TREE_OPERAND (**expr, 0); | |
630 | if (convert) | |
631 | *convert = true; | |
632 | } | |
633 | ||
634 | HOST_WIDE_INT offset, size, max_size; | |
635 | bool reverse; | |
636 | tree base | |
637 | = get_ref_base_and_extent (**expr, &offset, &size, &max_size, &reverse); | |
638 | if (!base || size == -1 || max_size == -1) | |
639 | return NULL; | |
640 | ||
641 | if (TREE_CODE (base) == MEM_REF) | |
642 | { | |
643 | offset += mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT; | |
644 | base = TREE_OPERAND (base, 0); | |
645 | } | |
646 | ||
647 | base = get_ssa_base_param (base, ignore_default_def); | |
648 | if (!base || TREE_CODE (base) != PARM_DECL) | |
649 | return NULL; | |
650 | ||
651 | struct ipa_parm_adjustment *cand = NULL; | |
652 | unsigned int len = adjustments.length (); | |
653 | for (unsigned i = 0; i < len; i++) | |
654 | { | |
655 | struct ipa_parm_adjustment *adj = &adjustments[i]; | |
656 | ||
657 | if (adj->base == base | |
658 | && (adj->offset == offset || adj->op == IPA_PARM_OP_REMOVE)) | |
659 | { | |
660 | cand = adj; | |
661 | break; | |
662 | } | |
663 | } | |
664 | ||
665 | if (!cand || cand->op == IPA_PARM_OP_COPY || cand->op == IPA_PARM_OP_REMOVE) | |
666 | return NULL; | |
667 | return cand; | |
668 | } | |
669 | ||
670 | /* If the expression *EXPR should be replaced by a reduction of a parameter, do | |
671 | so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT | |
672 | specifies whether the function should care about type incompatibility the | |
673 | current and new expressions. If it is false, the function will leave | |
674 | incompatibility issues to the caller. Return true iff the expression | |
675 | was modified. */ | |
676 | ||
677 | bool | |
678 | ipa_modify_expr (tree *expr, bool convert, | |
679 | ipa_parm_adjustment_vec adjustments) | |
680 | { | |
681 | struct ipa_parm_adjustment *cand | |
682 | = ipa_get_adjustment_candidate (&expr, &convert, adjustments, false); | |
683 | if (!cand) | |
684 | return false; | |
685 | ||
686 | tree src; | |
687 | if (cand->by_ref) | |
688 | { | |
689 | src = build_simple_mem_ref (cand->new_decl); | |
690 | REF_REVERSE_STORAGE_ORDER (src) = cand->reverse; | |
691 | } | |
692 | else | |
693 | src = cand->new_decl; | |
694 | ||
695 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
696 | { | |
697 | fprintf (dump_file, "About to replace expr "); | |
698 | print_generic_expr (dump_file, *expr); | |
699 | fprintf (dump_file, " with "); | |
700 | print_generic_expr (dump_file, src); | |
701 | fprintf (dump_file, "\n"); | |
702 | } | |
703 | ||
704 | if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type)) | |
705 | { | |
706 | tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src); | |
707 | *expr = vce; | |
708 | } | |
709 | else | |
710 | *expr = src; | |
711 | return true; | |
712 | } | |
713 | ||
714 | /* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human | |
715 | friendly way, assuming they are meant to be applied to FNDECL. */ | |
716 | ||
717 | void | |
718 | ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments, | |
719 | tree fndecl) | |
720 | { | |
721 | int i, len = adjustments.length (); | |
722 | bool first = true; | |
723 | vec<tree> parms = ipa_get_vector_of_formal_parms (fndecl); | |
724 | ||
725 | fprintf (file, "IPA param adjustments: "); | |
726 | for (i = 0; i < len; i++) | |
727 | { | |
728 | struct ipa_parm_adjustment *adj; | |
729 | adj = &adjustments[i]; | |
730 | ||
731 | if (!first) | |
732 | fprintf (file, " "); | |
733 | else | |
734 | first = false; | |
735 | ||
736 | fprintf (file, "%i. base_index: %i - ", i, adj->base_index); | |
737 | print_generic_expr (file, parms[adj->base_index]); | |
738 | if (adj->base) | |
739 | { | |
740 | fprintf (file, ", base: "); | |
741 | print_generic_expr (file, adj->base); | |
742 | } | |
743 | if (adj->new_decl) | |
744 | { | |
745 | fprintf (file, ", new_decl: "); | |
746 | print_generic_expr (file, adj->new_decl); | |
747 | } | |
748 | if (adj->new_ssa_base) | |
749 | { | |
750 | fprintf (file, ", new_ssa_base: "); | |
751 | print_generic_expr (file, adj->new_ssa_base); | |
752 | } | |
753 | ||
754 | if (adj->op == IPA_PARM_OP_COPY) | |
755 | fprintf (file, ", copy_param"); | |
756 | else if (adj->op == IPA_PARM_OP_REMOVE) | |
757 | fprintf (file, ", remove_param"); | |
758 | else | |
759 | fprintf (file, ", offset %li", (long) adj->offset); | |
760 | if (adj->by_ref) | |
761 | fprintf (file, ", by_ref"); | |
762 | print_node_brief (file, ", type: ", adj->type, 0); | |
763 | fprintf (file, "\n"); | |
764 | } | |
765 | parms.release (); | |
766 | } | |
767 |