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_BIND_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 | |
768 | |