]>
Commit | Line | Data |
---|---|---|
ac762bff | 1 | /* Manipulation of formal and actual parameters of functions and function |
2 | calls. | |
fbd26352 | 3 | Copyright (C) 2017-2019 Free Software Foundation, Inc. |
ac762bff | 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. */ | |
a0e9bfbb | 221 | if (fndecl_built_in_p (fndecl)) |
ac762bff | 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 | ||
3bed7476 | 296 | poly_int64 byte_offset = exact_div (adj->offset, BITS_PER_UNIT); |
ac762bff | 297 | base = gimple_call_arg (stmt, adj->base_index); |
ccdd6f5c | 298 | loc = gimple_location (stmt); |
ac762bff | 299 | |
300 | if (TREE_CODE (base) != ADDR_EXPR | |
301 | && POINTER_TYPE_P (TREE_TYPE (base))) | |
3bed7476 | 302 | off = build_int_cst (adj->alias_ptr_type, byte_offset); |
ac762bff | 303 | else |
304 | { | |
773078cb | 305 | poly_int64 base_offset; |
ac762bff | 306 | tree prev_base; |
307 | bool addrof; | |
308 | ||
309 | if (TREE_CODE (base) == ADDR_EXPR) | |
310 | { | |
311 | base = TREE_OPERAND (base, 0); | |
312 | addrof = true; | |
313 | } | |
314 | else | |
315 | addrof = false; | |
316 | prev_base = base; | |
317 | base = get_addr_base_and_unit_offset (base, &base_offset); | |
318 | /* Aggregate arguments can have non-invariant addresses. */ | |
319 | if (!base) | |
320 | { | |
321 | base = build_fold_addr_expr (prev_base); | |
3bed7476 | 322 | off = build_int_cst (adj->alias_ptr_type, byte_offset); |
ac762bff | 323 | } |
324 | else if (TREE_CODE (base) == MEM_REF) | |
325 | { | |
326 | if (!addrof) | |
327 | { | |
328 | deref_base = true; | |
329 | deref_align = TYPE_ALIGN (TREE_TYPE (base)); | |
330 | } | |
331 | off = build_int_cst (adj->alias_ptr_type, | |
3bed7476 | 332 | base_offset + byte_offset); |
ac762bff | 333 | off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), |
334 | off); | |
335 | base = TREE_OPERAND (base, 0); | |
336 | } | |
337 | else | |
338 | { | |
339 | off = build_int_cst (adj->alias_ptr_type, | |
3bed7476 | 340 | base_offset + byte_offset); |
ac762bff | 341 | base = build_fold_addr_expr (base); |
342 | } | |
343 | } | |
344 | ||
345 | if (!adj->by_ref) | |
346 | { | |
347 | tree type = adj->type; | |
348 | unsigned int align; | |
349 | unsigned HOST_WIDE_INT misalign; | |
350 | ||
351 | if (deref_base) | |
352 | { | |
353 | align = deref_align; | |
354 | misalign = 0; | |
355 | } | |
356 | else | |
357 | { | |
358 | get_pointer_alignment_1 (base, &align, &misalign); | |
359 | if (TYPE_ALIGN (type) > align) | |
360 | align = TYPE_ALIGN (type); | |
361 | } | |
362 | misalign += (offset_int::from (wi::to_wide (off), | |
363 | SIGNED).to_short_addr () | |
364 | * BITS_PER_UNIT); | |
365 | misalign = misalign & (align - 1); | |
366 | if (misalign != 0) | |
367 | align = least_bit_hwi (misalign); | |
368 | if (align < TYPE_ALIGN (type)) | |
369 | type = build_aligned_type (type, align); | |
370 | base = force_gimple_operand_gsi (&gsi, base, | |
371 | true, NULL, true, GSI_SAME_STMT); | |
372 | expr = fold_build2_loc (loc, MEM_REF, type, base, off); | |
373 | REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse; | |
374 | /* If expr is not a valid gimple call argument emit | |
375 | a load into a temporary. */ | |
376 | if (is_gimple_reg_type (TREE_TYPE (expr))) | |
377 | { | |
378 | gimple *tem = gimple_build_assign (NULL_TREE, expr); | |
379 | if (gimple_in_ssa_p (cfun)) | |
380 | { | |
381 | gimple_set_vuse (tem, gimple_vuse (stmt)); | |
382 | expr = make_ssa_name (TREE_TYPE (expr), tem); | |
383 | } | |
384 | else | |
385 | expr = create_tmp_reg (TREE_TYPE (expr)); | |
386 | gimple_assign_set_lhs (tem, expr); | |
ccdd6f5c | 387 | gimple_set_location (tem, loc); |
ac762bff | 388 | gsi_insert_before (&gsi, tem, GSI_SAME_STMT); |
389 | } | |
390 | } | |
391 | else | |
392 | { | |
393 | expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off); | |
394 | REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse; | |
395 | expr = build_fold_addr_expr (expr); | |
396 | expr = force_gimple_operand_gsi (&gsi, expr, | |
397 | true, NULL, true, GSI_SAME_STMT); | |
398 | } | |
399 | vargs.quick_push (expr); | |
400 | } | |
c64f38bf | 401 | if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS) |
ac762bff | 402 | { |
403 | unsigned int ix; | |
404 | tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg; | |
405 | gimple *def_temp; | |
406 | ||
407 | arg = gimple_call_arg (stmt, adj->base_index); | |
408 | if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE (arg))) | |
409 | { | |
410 | if (!fold_convertible_p (TREE_TYPE (origin), arg)) | |
411 | continue; | |
412 | arg = fold_convert_loc (gimple_location (stmt), | |
413 | TREE_TYPE (origin), arg); | |
414 | } | |
415 | if (debug_args == NULL) | |
416 | debug_args = decl_debug_args_insert (callee_decl); | |
417 | for (ix = 0; vec_safe_iterate (*debug_args, ix, &ddecl); ix += 2) | |
418 | if (ddecl == origin) | |
419 | { | |
420 | ddecl = (**debug_args)[ix + 1]; | |
421 | break; | |
422 | } | |
423 | if (ddecl == NULL) | |
424 | { | |
425 | ddecl = make_node (DEBUG_EXPR_DECL); | |
426 | DECL_ARTIFICIAL (ddecl) = 1; | |
427 | TREE_TYPE (ddecl) = TREE_TYPE (origin); | |
428 | SET_DECL_MODE (ddecl, DECL_MODE (origin)); | |
429 | ||
430 | vec_safe_push (*debug_args, origin); | |
431 | vec_safe_push (*debug_args, ddecl); | |
432 | } | |
433 | def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg), stmt); | |
434 | gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT); | |
435 | } | |
436 | } | |
437 | ||
438 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
439 | { | |
440 | fprintf (dump_file, "replacing stmt:"); | |
441 | print_gimple_stmt (dump_file, gsi_stmt (gsi), 0); | |
442 | } | |
443 | ||
444 | new_stmt = gimple_build_call_vec (callee_decl, vargs); | |
445 | vargs.release (); | |
446 | if (gimple_call_lhs (stmt)) | |
447 | gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); | |
448 | ||
449 | gimple_set_block (new_stmt, gimple_block (stmt)); | |
450 | if (gimple_has_location (stmt)) | |
451 | gimple_set_location (new_stmt, gimple_location (stmt)); | |
452 | gimple_call_set_chain (new_stmt, gimple_call_chain (stmt)); | |
453 | gimple_call_copy_flags (new_stmt, stmt); | |
454 | if (gimple_in_ssa_p (cfun)) | |
455 | { | |
456 | gimple_set_vuse (new_stmt, gimple_vuse (stmt)); | |
457 | if (gimple_vdef (stmt)) | |
458 | { | |
459 | gimple_set_vdef (new_stmt, gimple_vdef (stmt)); | |
460 | SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; | |
461 | } | |
462 | } | |
463 | ||
464 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
465 | { | |
466 | fprintf (dump_file, "with stmt:"); | |
467 | print_gimple_stmt (dump_file, new_stmt, 0); | |
468 | fprintf (dump_file, "\n"); | |
469 | } | |
470 | gsi_replace (&gsi, new_stmt, true); | |
471 | if (cs) | |
472 | cs->set_call_stmt (new_stmt); | |
473 | do | |
474 | { | |
475 | current_node->record_stmt_references (gsi_stmt (gsi)); | |
476 | gsi_prev (&gsi); | |
477 | } | |
478 | while (gsi_stmt (gsi) != gsi_stmt (prev_gsi)); | |
479 | } | |
480 | ||
481 | /* Return true iff BASE_INDEX is in ADJUSTMENTS more than once. */ | |
482 | ||
483 | static bool | |
484 | index_in_adjustments_multiple_times_p (int base_index, | |
485 | ipa_parm_adjustment_vec adjustments) | |
486 | { | |
487 | int i, len = adjustments.length (); | |
488 | bool one = false; | |
489 | ||
490 | for (i = 0; i < len; i++) | |
491 | { | |
492 | struct ipa_parm_adjustment *adj; | |
493 | adj = &adjustments[i]; | |
494 | ||
495 | if (adj->base_index == base_index) | |
496 | { | |
497 | if (one) | |
498 | return true; | |
499 | else | |
500 | one = true; | |
501 | } | |
502 | } | |
503 | return false; | |
504 | } | |
505 | ||
506 | /* Return adjustments that should have the same effect on function parameters | |
507 | and call arguments as if they were first changed according to adjustments in | |
508 | INNER and then by adjustments in OUTER. */ | |
509 | ||
510 | ipa_parm_adjustment_vec | |
511 | ipa_combine_adjustments (ipa_parm_adjustment_vec inner, | |
512 | ipa_parm_adjustment_vec outer) | |
513 | { | |
514 | int i, outlen = outer.length (); | |
515 | int inlen = inner.length (); | |
516 | int removals = 0; | |
517 | ipa_parm_adjustment_vec adjustments, tmp; | |
518 | ||
519 | tmp.create (inlen); | |
520 | for (i = 0; i < inlen; i++) | |
521 | { | |
522 | struct ipa_parm_adjustment *n; | |
523 | n = &inner[i]; | |
524 | ||
525 | if (n->op == IPA_PARM_OP_REMOVE) | |
526 | removals++; | |
527 | else | |
528 | { | |
529 | /* FIXME: Handling of new arguments are not implemented yet. */ | |
530 | gcc_assert (n->op != IPA_PARM_OP_NEW); | |
531 | tmp.quick_push (*n); | |
532 | } | |
533 | } | |
534 | ||
535 | adjustments.create (outlen + removals); | |
536 | for (i = 0; i < outlen; i++) | |
537 | { | |
538 | struct ipa_parm_adjustment r; | |
539 | struct ipa_parm_adjustment *out = &outer[i]; | |
540 | struct ipa_parm_adjustment *in = &tmp[out->base_index]; | |
541 | ||
542 | memset (&r, 0, sizeof (r)); | |
543 | gcc_assert (in->op != IPA_PARM_OP_REMOVE); | |
544 | if (out->op == IPA_PARM_OP_REMOVE) | |
545 | { | |
546 | if (!index_in_adjustments_multiple_times_p (in->base_index, tmp)) | |
547 | { | |
548 | r.op = IPA_PARM_OP_REMOVE; | |
549 | adjustments.quick_push (r); | |
550 | } | |
551 | continue; | |
552 | } | |
553 | else | |
554 | { | |
555 | /* FIXME: Handling of new arguments are not implemented yet. */ | |
556 | gcc_assert (out->op != IPA_PARM_OP_NEW); | |
557 | } | |
558 | ||
559 | r.base_index = in->base_index; | |
560 | r.type = out->type; | |
561 | ||
562 | /* FIXME: Create nonlocal value too. */ | |
563 | ||
564 | if (in->op == IPA_PARM_OP_COPY && out->op == IPA_PARM_OP_COPY) | |
565 | r.op = IPA_PARM_OP_COPY; | |
566 | else if (in->op == IPA_PARM_OP_COPY) | |
567 | r.offset = out->offset; | |
568 | else if (out->op == IPA_PARM_OP_COPY) | |
569 | r.offset = in->offset; | |
570 | else | |
571 | r.offset = in->offset + out->offset; | |
572 | adjustments.quick_push (r); | |
573 | } | |
574 | ||
575 | for (i = 0; i < inlen; i++) | |
576 | { | |
577 | struct ipa_parm_adjustment *n = &inner[i]; | |
578 | ||
579 | if (n->op == IPA_PARM_OP_REMOVE) | |
580 | adjustments.quick_push (*n); | |
581 | } | |
582 | ||
583 | tmp.release (); | |
584 | return adjustments; | |
585 | } | |
586 | ||
587 | /* If T is an SSA_NAME, return NULL if it is not a default def or | |
588 | return its base variable if it is. If IGNORE_DEFAULT_DEF is true, | |
589 | the base variable is always returned, regardless if it is a default | |
590 | def. Return T if it is not an SSA_NAME. */ | |
591 | ||
592 | static tree | |
593 | get_ssa_base_param (tree t, bool ignore_default_def) | |
594 | { | |
595 | if (TREE_CODE (t) == SSA_NAME) | |
596 | { | |
597 | if (ignore_default_def || SSA_NAME_IS_DEFAULT_DEF (t)) | |
598 | return SSA_NAME_VAR (t); | |
599 | else | |
600 | return NULL_TREE; | |
601 | } | |
602 | return t; | |
603 | } | |
604 | ||
605 | /* Given an expression, return an adjustment entry specifying the | |
606 | transformation to be done on EXPR. If no suitable adjustment entry | |
607 | was found, returns NULL. | |
608 | ||
609 | If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a | |
610 | default def, otherwise bail on them. | |
611 | ||
612 | If CONVERT is non-NULL, this function will set *CONVERT if the | |
613 | expression provided is a component reference. ADJUSTMENTS is the | |
614 | adjustments vector. */ | |
615 | ||
616 | ipa_parm_adjustment * | |
617 | ipa_get_adjustment_candidate (tree **expr, bool *convert, | |
618 | ipa_parm_adjustment_vec adjustments, | |
619 | bool ignore_default_def) | |
620 | { | |
621 | if (TREE_CODE (**expr) == BIT_FIELD_REF | |
622 | || TREE_CODE (**expr) == IMAGPART_EXPR | |
623 | || TREE_CODE (**expr) == REALPART_EXPR) | |
624 | { | |
625 | *expr = &TREE_OPERAND (**expr, 0); | |
626 | if (convert) | |
627 | *convert = true; | |
628 | } | |
629 | ||
f3c2a387 | 630 | poly_int64 offset, size, max_size; |
ac762bff | 631 | bool reverse; |
632 | tree base | |
633 | = get_ref_base_and_extent (**expr, &offset, &size, &max_size, &reverse); | |
f3c2a387 | 634 | if (!base || !known_size_p (size) || !known_size_p (max_size)) |
ac762bff | 635 | return NULL; |
636 | ||
637 | if (TREE_CODE (base) == MEM_REF) | |
638 | { | |
90ca1268 | 639 | offset += mem_ref_offset (base).force_shwi () * BITS_PER_UNIT; |
ac762bff | 640 | base = TREE_OPERAND (base, 0); |
641 | } | |
642 | ||
643 | base = get_ssa_base_param (base, ignore_default_def); | |
644 | if (!base || TREE_CODE (base) != PARM_DECL) | |
645 | return NULL; | |
646 | ||
647 | struct ipa_parm_adjustment *cand = NULL; | |
648 | unsigned int len = adjustments.length (); | |
649 | for (unsigned i = 0; i < len; i++) | |
650 | { | |
651 | struct ipa_parm_adjustment *adj = &adjustments[i]; | |
652 | ||
653 | if (adj->base == base | |
3bed7476 | 654 | && (known_eq (adj->offset, offset) || adj->op == IPA_PARM_OP_REMOVE)) |
ac762bff | 655 | { |
656 | cand = adj; | |
657 | break; | |
658 | } | |
659 | } | |
660 | ||
661 | if (!cand || cand->op == IPA_PARM_OP_COPY || cand->op == IPA_PARM_OP_REMOVE) | |
662 | return NULL; | |
663 | return cand; | |
664 | } | |
665 | ||
666 | /* If the expression *EXPR should be replaced by a reduction of a parameter, do | |
667 | so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT | |
668 | specifies whether the function should care about type incompatibility the | |
669 | current and new expressions. If it is false, the function will leave | |
670 | incompatibility issues to the caller. Return true iff the expression | |
671 | was modified. */ | |
672 | ||
673 | bool | |
674 | ipa_modify_expr (tree *expr, bool convert, | |
675 | ipa_parm_adjustment_vec adjustments) | |
676 | { | |
677 | struct ipa_parm_adjustment *cand | |
678 | = ipa_get_adjustment_candidate (&expr, &convert, adjustments, false); | |
679 | if (!cand) | |
680 | return false; | |
681 | ||
682 | tree src; | |
683 | if (cand->by_ref) | |
684 | { | |
685 | src = build_simple_mem_ref (cand->new_decl); | |
686 | REF_REVERSE_STORAGE_ORDER (src) = cand->reverse; | |
687 | } | |
688 | else | |
689 | src = cand->new_decl; | |
690 | ||
691 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
692 | { | |
693 | fprintf (dump_file, "About to replace expr "); | |
694 | print_generic_expr (dump_file, *expr); | |
695 | fprintf (dump_file, " with "); | |
696 | print_generic_expr (dump_file, src); | |
697 | fprintf (dump_file, "\n"); | |
698 | } | |
699 | ||
700 | if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type)) | |
701 | { | |
702 | tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src); | |
703 | *expr = vce; | |
704 | } | |
705 | else | |
706 | *expr = src; | |
707 | return true; | |
708 | } | |
709 | ||
710 | /* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human | |
711 | friendly way, assuming they are meant to be applied to FNDECL. */ | |
712 | ||
713 | void | |
714 | ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments, | |
715 | tree fndecl) | |
716 | { | |
717 | int i, len = adjustments.length (); | |
718 | bool first = true; | |
719 | vec<tree> parms = ipa_get_vector_of_formal_parms (fndecl); | |
720 | ||
721 | fprintf (file, "IPA param adjustments: "); | |
722 | for (i = 0; i < len; i++) | |
723 | { | |
724 | struct ipa_parm_adjustment *adj; | |
725 | adj = &adjustments[i]; | |
726 | ||
727 | if (!first) | |
728 | fprintf (file, " "); | |
729 | else | |
730 | first = false; | |
731 | ||
732 | fprintf (file, "%i. base_index: %i - ", i, adj->base_index); | |
733 | print_generic_expr (file, parms[adj->base_index]); | |
734 | if (adj->base) | |
735 | { | |
736 | fprintf (file, ", base: "); | |
737 | print_generic_expr (file, adj->base); | |
738 | } | |
739 | if (adj->new_decl) | |
740 | { | |
741 | fprintf (file, ", new_decl: "); | |
742 | print_generic_expr (file, adj->new_decl); | |
743 | } | |
744 | if (adj->new_ssa_base) | |
745 | { | |
746 | fprintf (file, ", new_ssa_base: "); | |
747 | print_generic_expr (file, adj->new_ssa_base); | |
748 | } | |
749 | ||
750 | if (adj->op == IPA_PARM_OP_COPY) | |
751 | fprintf (file, ", copy_param"); | |
752 | else if (adj->op == IPA_PARM_OP_REMOVE) | |
753 | fprintf (file, ", remove_param"); | |
754 | else | |
3bed7476 | 755 | { |
756 | fprintf (file, ", offset "); | |
757 | print_dec (adj->offset, file); | |
758 | } | |
ac762bff | 759 | if (adj->by_ref) |
760 | fprintf (file, ", by_ref"); | |
761 | print_node_brief (file, ", type: ", adj->type, 0); | |
762 | fprintf (file, "\n"); | |
763 | } | |
764 | parms.release (); | |
765 | } | |
766 |