Branch data Line data Source code
1 : : /* Support for thunks in symbol table.
2 : : Copyright (C) 2003-2025 Free Software Foundation, Inc.
3 : : Contributed by Jan Hubicka
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 "tree.h"
26 : : #include "gimple.h"
27 : : #include "predict.h"
28 : : #include "target.h"
29 : : #include "rtl.h"
30 : : #include "alloc-pool.h"
31 : : #include "cgraph.h"
32 : : #include "symbol-summary.h"
33 : : #include "symtab-thunks.h"
34 : : #include "lto-streamer.h"
35 : : #include "fold-const.h"
36 : : #include "gimple-iterator.h"
37 : : #include "stor-layout.h"
38 : : #include "gimplify-me.h"
39 : : #include "varasm.h"
40 : : #include "output.h"
41 : : #include "cfg.h"
42 : : #include "cfghooks.h"
43 : : #include "gimple-ssa.h"
44 : : #include "gimple-fold.h"
45 : : #include "cfgloop.h"
46 : : #include "tree-into-ssa.h"
47 : : #include "tree-cfg.h"
48 : : #include "cfgcleanup.h"
49 : : #include "tree-pass.h"
50 : : #include "data-streamer.h"
51 : : #include "langhooks.h"
52 : :
53 : : /* Used for vtable lookup in thunk adjusting. */
54 : : static GTY (()) tree vtable_entry_type;
55 : : struct GTY (()) unprocessed_thunk
56 : : {
57 : : cgraph_node *node;
58 : : thunk_info *info;
59 : : };
60 : : /* To be PCH safe we store thunks into a vector before end of compilation
61 : : unit. */
62 : : static GTY (()) vec<unprocessed_thunk, va_gc> *thunks;
63 : :
64 : : namespace {
65 : :
66 : : /* Function summary for thunk_infos. */
67 : : class GTY((user)) thunk_infos_t: public function_summary <thunk_info *>
68 : : {
69 : : public:
70 : 5641 : thunk_infos_t (symbol_table *table, bool ggc):
71 : 11282 : function_summary<thunk_info *> (table, ggc) { }
72 : :
73 : : /* Hook that is called by summary when a node is duplicated. */
74 : : void duplicate (cgraph_node *node,
75 : : cgraph_node *node2,
76 : : thunk_info *data,
77 : : thunk_info *data2) final override;
78 : : };
79 : :
80 : : /* Duplication hook. */
81 : : void
82 : 329 : thunk_infos_t::duplicate (cgraph_node *, cgraph_node *,
83 : : thunk_info *src, thunk_info *dst)
84 : : {
85 : 329 : *dst = *src;
86 : 329 : }
87 : :
88 : : } /* anon namespace */
89 : :
90 : : /* Return thunk_info possibly creating new one. */
91 : : thunk_info *
92 : 22945 : thunk_info::get_create (cgraph_node *node)
93 : : {
94 : 22945 : if (!symtab->m_thunks)
95 : : {
96 : 11282 : symtab->m_thunks
97 : 5641 : = new (ggc_alloc_no_dtor <thunk_infos_t> ())
98 : 5641 : thunk_infos_t (symtab, true);
99 : 5641 : symtab->m_thunks->disable_insertion_hook ();
100 : : }
101 : 22945 : return symtab->m_thunks->get_create (node);
102 : : }
103 : :
104 : : /* Stream out THIS to OB. */
105 : : void
106 : 221 : thunk_info::stream_out (lto_simple_output_block *ob)
107 : : {
108 : 221 : streamer_write_uhwi_stream
109 : 221 : (ob->main_stream,
110 : 221 : 1 + (this_adjusting != 0) * 2
111 : 375 : + (virtual_offset_p != 0) * 4);
112 : 221 : streamer_write_uhwi_stream (ob->main_stream, fixed_offset);
113 : 221 : streamer_write_uhwi_stream (ob->main_stream, virtual_value);
114 : 221 : streamer_write_uhwi_stream (ob->main_stream, indirect_offset);
115 : 221 : }
116 : :
117 : : /* Stream in THIS from IB. */
118 : : void
119 : 152 : thunk_info::stream_in (class lto_input_block *ib)
120 : : {
121 : 152 : int type = streamer_read_uhwi (ib);
122 : 152 : fixed_offset = streamer_read_uhwi (ib);
123 : 152 : virtual_value = streamer_read_uhwi (ib);
124 : 152 : indirect_offset = streamer_read_uhwi (ib);
125 : :
126 : 152 : this_adjusting = (type & 2);
127 : 152 : virtual_offset_p = (type & 4);
128 : 152 : }
129 : :
130 : : /* Dump THIS to F. */
131 : : void
132 : 70 : thunk_info::dump (FILE *f)
133 : : {
134 : 70 : if (alias)
135 : 0 : fprintf (f, " of %s (asm:%s)",
136 : 0 : lang_hooks.decl_printable_name (alias, 2),
137 : 0 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (alias)));
138 : 70 : fprintf (f, " fixed offset %i virtual value %i indirect_offset %i "
139 : : "has virtual offset %i\n",
140 : 70 : (int)fixed_offset,
141 : 70 : (int)virtual_value,
142 : 70 : (int)indirect_offset,
143 : 70 : (int)virtual_offset_p);
144 : 70 : }
145 : :
146 : : /* Hash THIS. */
147 : : hashval_t
148 : 0 : thunk_info::hash ()
149 : : {
150 : 0 : inchash::hash hstate;
151 : 0 : hstate.add_hwi (fixed_offset);
152 : 0 : hstate.add_hwi (virtual_value);
153 : 0 : hstate.add_flag (this_adjusting);
154 : 0 : hstate.add_flag (virtual_offset_p);
155 : 0 : return hstate.end ();
156 : : }
157 : :
158 : : /* Add unprocessed thunk. */
159 : : void
160 : 4349 : thunk_info::register_early (cgraph_node *node)
161 : : {
162 : 4349 : unprocessed_thunk entry = {node, new (ggc_alloc <thunk_info> ()) thunk_info};
163 : 4349 : *entry.info = *this;
164 : 4349 : vec_safe_push (thunks, entry);
165 : 4349 : }
166 : :
167 : : /* Attach recorded thunks to cgraph_nodes.
168 : : All this is done only to avoid need to stream summaries to PCH. */
169 : : void
170 : 505386 : thunk_info::process_early_thunks ()
171 : : {
172 : 505386 : unprocessed_thunk *e;
173 : 505386 : unsigned int i;
174 : 505386 : if (!thunks)
175 : 505386 : return;
176 : :
177 : 5579 : FOR_EACH_VEC_ELT (*thunks, i, e)
178 : : {
179 : 4349 : *thunk_info::get_create (e->node) = *e->info;
180 : : }
181 : 1230 : vec_free (thunks);
182 : 1230 : thunks = NULL;
183 : : }
184 : :
185 : : /* Adjust PTR by the constant FIXED_OFFSET, by the vtable offset indicated by
186 : : VIRTUAL_OFFSET, and by the indirect offset indicated by INDIRECT_OFFSET, if
187 : : it is non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and zero
188 : : for a result adjusting thunk. */
189 : : tree
190 : 1497 : thunk_adjust (gimple_stmt_iterator * bsi,
191 : : tree ptr, bool this_adjusting,
192 : : HOST_WIDE_INT fixed_offset, tree virtual_offset,
193 : : HOST_WIDE_INT indirect_offset)
194 : : {
195 : 1497 : gassign *stmt;
196 : 1497 : tree ret;
197 : :
198 : 1497 : if (this_adjusting
199 : 1497 : && fixed_offset != 0)
200 : : {
201 : 657 : stmt = gimple_build_assign
202 : 657 : (ptr, fold_build_pointer_plus_hwi_loc (input_location,
203 : : ptr,
204 : : fixed_offset));
205 : 657 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
206 : : }
207 : :
208 : 1497 : if (!vtable_entry_type && (virtual_offset || indirect_offset != 0))
209 : : {
210 : 292 : tree vfunc_type = make_node (FUNCTION_TYPE);
211 : 292 : TREE_TYPE (vfunc_type) = integer_type_node;
212 : 292 : TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
213 : 292 : layout_type (vfunc_type);
214 : :
215 : 292 : vtable_entry_type = build_pointer_type (vfunc_type);
216 : : }
217 : :
218 : : /* If there's a virtual offset, look up that value in the vtable and
219 : : adjust the pointer again. */
220 : 900 : if (virtual_offset)
221 : : {
222 : 791 : tree vtabletmp;
223 : 791 : tree vtabletmp2;
224 : 791 : tree vtabletmp3;
225 : :
226 : 791 : vtabletmp = create_tmp_reg
227 : 791 : (build_pointer_type
228 : : (build_pointer_type (vtable_entry_type)), "vptr");
229 : :
230 : : /* The vptr is always at offset zero in the object. */
231 : 791 : stmt = gimple_build_assign (vtabletmp,
232 : 791 : build1 (NOP_EXPR, TREE_TYPE (vtabletmp),
233 : : ptr));
234 : 791 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
235 : :
236 : : /* Form the vtable address. */
237 : 791 : vtabletmp2 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp)),
238 : : "vtableaddr");
239 : 791 : stmt = gimple_build_assign (vtabletmp2,
240 : : build_simple_mem_ref (vtabletmp));
241 : 791 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
242 : :
243 : : /* Find the entry with the vcall offset. */
244 : 791 : stmt = gimple_build_assign (vtabletmp2,
245 : : fold_build_pointer_plus_loc (input_location,
246 : : vtabletmp2,
247 : : virtual_offset));
248 : 791 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
249 : :
250 : : /* Get the offset itself. */
251 : 791 : vtabletmp3 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp2)),
252 : : "vcalloffset");
253 : 791 : stmt = gimple_build_assign (vtabletmp3,
254 : : build_simple_mem_ref (vtabletmp2));
255 : 791 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
256 : :
257 : : /* Adjust the `this' pointer. */
258 : 791 : ptr = fold_build_pointer_plus_loc (input_location, ptr, vtabletmp3);
259 : 791 : ptr = force_gimple_operand_gsi (bsi, ptr, true, NULL_TREE, false,
260 : : GSI_CONTINUE_LINKING);
261 : : }
262 : :
263 : : /* Likewise for an offset that is stored in the object that contains the
264 : : vtable. */
265 : 1497 : if (indirect_offset != 0)
266 : : {
267 : 0 : tree offset_ptr, offset_tree;
268 : :
269 : : /* Get the address of the offset. */
270 : 0 : offset_ptr
271 : 0 : = create_tmp_reg (build_pointer_type
272 : : (build_pointer_type (vtable_entry_type)),
273 : : "offset_ptr");
274 : 0 : stmt = gimple_build_assign (offset_ptr,
275 : 0 : build1 (NOP_EXPR, TREE_TYPE (offset_ptr),
276 : : ptr));
277 : 0 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
278 : :
279 : 0 : stmt = gimple_build_assign
280 : 0 : (offset_ptr,
281 : : fold_build_pointer_plus_hwi_loc (input_location, offset_ptr,
282 : : indirect_offset));
283 : 0 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
284 : :
285 : : /* Get the offset itself. */
286 : 0 : offset_tree = create_tmp_reg (TREE_TYPE (TREE_TYPE (offset_ptr)),
287 : : "offset");
288 : 0 : stmt = gimple_build_assign (offset_tree,
289 : : build_simple_mem_ref (offset_ptr));
290 : 0 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
291 : :
292 : : /* Adjust the `this' pointer. */
293 : 0 : ptr = fold_build_pointer_plus_loc (input_location, ptr, offset_tree);
294 : 0 : ptr = force_gimple_operand_gsi (bsi, ptr, true, NULL_TREE, false,
295 : : GSI_CONTINUE_LINKING);
296 : : }
297 : :
298 : 1497 : if (!this_adjusting
299 : 1497 : && fixed_offset != 0)
300 : : /* Adjust the pointer by the constant. */
301 : : {
302 : 73 : tree ptrtmp;
303 : :
304 : 73 : if (VAR_P (ptr))
305 : : ptrtmp = ptr;
306 : : else
307 : : {
308 : 18 : ptrtmp = create_tmp_reg (TREE_TYPE (ptr), "ptr");
309 : 18 : stmt = gimple_build_assign (ptrtmp, ptr);
310 : 18 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
311 : : }
312 : 73 : ptr = fold_build_pointer_plus_hwi_loc (input_location,
313 : : ptrtmp, fixed_offset);
314 : : }
315 : :
316 : : /* Emit the statement and gimplify the adjustment expression. */
317 : 1497 : ret = create_tmp_reg (TREE_TYPE (ptr), "adjusted_this");
318 : 1497 : stmt = gimple_build_assign (ret, ptr);
319 : 1497 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
320 : :
321 : 1497 : return ret;
322 : : }
323 : :
324 : : /* Expand thunk NODE to gimple if possible.
325 : : When FORCE_GIMPLE_THUNK is true, gimple thunk is created and
326 : : no assembler is produced.
327 : : When OUTPUT_ASM_THUNK is true, also produce assembler for
328 : : thunks that are not lowered. */
329 : : bool
330 : 23038 : expand_thunk (cgraph_node *node, bool output_asm_thunks,
331 : : bool force_gimple_thunk)
332 : : {
333 : 23038 : thunk_info *info = thunk_info::get (node);
334 : 23038 : bool this_adjusting = info->this_adjusting;
335 : 23038 : HOST_WIDE_INT fixed_offset = info->fixed_offset;
336 : 23038 : HOST_WIDE_INT virtual_value = info->virtual_value;
337 : 23038 : HOST_WIDE_INT indirect_offset = info->indirect_offset;
338 : 23038 : tree virtual_offset = NULL;
339 : 23038 : tree alias = node->callees->callee->decl;
340 : 23038 : tree thunk_fndecl = node->decl;
341 : 23038 : tree a;
342 : :
343 : 23038 : if (!force_gimple_thunk
344 : 23038 : && this_adjusting
345 : 4893 : && indirect_offset == 0
346 : 4893 : && !DECL_EXTERNAL (alias)
347 : 4893 : && !DECL_STATIC_CHAIN (alias)
348 : 27931 : && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
349 : : virtual_value, alias))
350 : : {
351 : 4893 : tree fn_block;
352 : 4893 : tree restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
353 : :
354 : 4893 : if (!output_asm_thunks)
355 : : {
356 : 3141 : node->analyzed = true;
357 : 3141 : return false;
358 : : }
359 : :
360 : 1752 : if (in_lto_p)
361 : 17 : node->get_untransformed_body ();
362 : 1752 : a = DECL_ARGUMENTS (thunk_fndecl);
363 : :
364 : 1752 : current_function_decl = thunk_fndecl;
365 : :
366 : : /* Ensure thunks are emitted in their correct sections. */
367 : 1752 : resolve_unique_section (thunk_fndecl, 0,
368 : : flag_function_sections);
369 : :
370 : 3504 : DECL_RESULT (thunk_fndecl)
371 : 1752 : = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
372 : : RESULT_DECL, 0, restype);
373 : 1752 : DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl;
374 : :
375 : : /* The back end expects DECL_INITIAL to contain a BLOCK, so we
376 : : create one. */
377 : 1752 : fn_block = make_node (BLOCK);
378 : 1752 : BLOCK_VARS (fn_block) = a;
379 : 1752 : DECL_INITIAL (thunk_fndecl) = fn_block;
380 : 1752 : BLOCK_SUPERCONTEXT (fn_block) = thunk_fndecl;
381 : 1752 : allocate_struct_function (thunk_fndecl, false);
382 : 1752 : init_function_start (thunk_fndecl);
383 : 1752 : cfun->is_thunk = 1;
384 : 1752 : insn_locations_init ();
385 : 1752 : set_curr_insn_location (DECL_SOURCE_LOCATION (thunk_fndecl));
386 : 1752 : prologue_location = curr_insn_location ();
387 : :
388 : 1752 : targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
389 : : fixed_offset, virtual_value, alias);
390 : :
391 : 1752 : insn_locations_finalize ();
392 : 1752 : init_insn_lengths ();
393 : 1752 : free_after_compilation (cfun);
394 : 1752 : TREE_ASM_WRITTEN (thunk_fndecl) = 1;
395 : 1752 : node->thunk = false;
396 : 1752 : node->analyzed = false;
397 : : }
398 : 18145 : else if (stdarg_p (TREE_TYPE (thunk_fndecl)))
399 : : {
400 : 0 : error ("generic thunk code fails for method %qD which uses %<...%>",
401 : : thunk_fndecl);
402 : 0 : TREE_ASM_WRITTEN (thunk_fndecl) = 1;
403 : 0 : node->analyzed = true;
404 : 0 : return false;
405 : : }
406 : : else
407 : : {
408 : 18145 : tree restype;
409 : 18145 : basic_block bb, then_bb, else_bb, return_bb;
410 : 18145 : gimple_stmt_iterator bsi;
411 : 18145 : int nargs = 0;
412 : 18145 : tree arg;
413 : 18145 : int i;
414 : 18145 : tree resdecl;
415 : 18145 : tree restmp = NULL;
416 : :
417 : 18145 : gcall *call;
418 : 18145 : greturn *ret;
419 : 18145 : bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
420 : :
421 : : /* We may be called from expand_thunk that releases body except for
422 : : DECL_ARGUMENTS. In this case force_gimple_thunk is true. */
423 : 18145 : if (in_lto_p && !force_gimple_thunk)
424 : 0 : node->get_untransformed_body ();
425 : :
426 : : /* We need to force DECL_IGNORED_P when the thunk is created
427 : : after early debug was run. */
428 : 17196 : if (force_gimple_thunk)
429 : 17984 : DECL_IGNORED_P (thunk_fndecl) = 1;
430 : :
431 : 18145 : a = DECL_ARGUMENTS (thunk_fndecl);
432 : :
433 : 18145 : current_function_decl = thunk_fndecl;
434 : :
435 : : /* Ensure thunks are emitted in their correct sections. */
436 : 18145 : resolve_unique_section (thunk_fndecl, 0,
437 : : flag_function_sections);
438 : :
439 : 18145 : bitmap_obstack_initialize (NULL);
440 : :
441 : 18145 : if (info->virtual_offset_p)
442 : 784 : virtual_offset = size_int (virtual_value);
443 : :
444 : : /* Build the return declaration for the function. */
445 : 18145 : restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
446 : 18145 : if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
447 : : {
448 : 1294 : resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
449 : 1294 : DECL_ARTIFICIAL (resdecl) = 1;
450 : 1294 : DECL_IGNORED_P (resdecl) = 1;
451 : 1294 : DECL_CONTEXT (resdecl) = thunk_fndecl;
452 : 1294 : DECL_RESULT (thunk_fndecl) = resdecl;
453 : : }
454 : : else
455 : : resdecl = DECL_RESULT (thunk_fndecl);
456 : :
457 : 18145 : profile_count cfg_count = node->count;
458 : 18145 : if (!cfg_count.initialized_p ())
459 : 1301 : cfg_count = profile_count::from_gcov_type
460 : 1301 : (BB_FREQ_MAX).guessed_local ();
461 : :
462 : 36290 : bb = then_bb = else_bb = return_bb
463 : 18145 : = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
464 : :
465 : 18145 : bsi = gsi_start_bb (bb);
466 : :
467 : : /* Build call to the function being thunked. */
468 : 18145 : if (!VOID_TYPE_P (restype)
469 : 18145 : && (!alias_is_noreturn
470 : 26 : || TREE_ADDRESSABLE (restype)
471 : 23 : || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
472 : : {
473 : 6757 : if (DECL_BY_REFERENCE (resdecl))
474 : : {
475 : 19 : restmp = gimple_fold_indirect_ref (resdecl);
476 : 19 : if (!restmp)
477 : 38 : restmp = build2 (MEM_REF,
478 : 19 : TREE_TYPE (TREE_TYPE (resdecl)),
479 : : resdecl,
480 : 19 : build_int_cst (TREE_TYPE (resdecl), 0));
481 : : }
482 : 6738 : else if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
483 : : {
484 : 18 : restmp = resdecl;
485 : :
486 : 18 : if (VAR_P (restmp))
487 : : {
488 : 0 : add_local_decl (cfun, restmp);
489 : 0 : BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
490 : : }
491 : : }
492 : : else
493 : 6720 : restmp = create_tmp_reg (restype, "retval");
494 : : }
495 : :
496 : 47748 : for (arg = a; arg; arg = DECL_CHAIN (arg))
497 : 29603 : nargs++;
498 : 18145 : auto_vec<tree> vargs (nargs);
499 : 18145 : i = 0;
500 : 18145 : arg = a;
501 : 18145 : if (this_adjusting)
502 : : {
503 : 1133 : vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
504 : : virtual_offset, indirect_offset));
505 : 1133 : arg = DECL_CHAIN (a);
506 : 1133 : i = 1;
507 : : }
508 : :
509 : 18145 : if (nargs)
510 : 43244 : for (; i < nargs; i++, arg = DECL_CHAIN (arg))
511 : : {
512 : 28470 : tree tmp = arg;
513 : 28470 : DECL_NOT_GIMPLE_REG_P (arg) = 0;
514 : 28470 : if (!is_gimple_val (arg))
515 : : {
516 : 3 : tmp = create_tmp_reg (TYPE_MAIN_VARIANT
517 : : (TREE_TYPE (arg)), "arg");
518 : 3 : gimple *stmt = gimple_build_assign (tmp, arg);
519 : 3 : gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
520 : : }
521 : 28470 : vargs.quick_push (tmp);
522 : : }
523 : 18145 : call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
524 : 18145 : node->callees->call_stmt = call;
525 : 18145 : gimple_call_set_from_thunk (call, true);
526 : 18145 : if (DECL_STATIC_CHAIN (alias))
527 : : {
528 : 0 : tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
529 : 0 : tree type = TREE_TYPE (p);
530 : 0 : tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
531 : : PARM_DECL, create_tmp_var_name ("CHAIN"),
532 : : type);
533 : 0 : DECL_ARTIFICIAL (decl) = 1;
534 : 0 : DECL_IGNORED_P (decl) = 1;
535 : 0 : TREE_USED (decl) = 1;
536 : 0 : DECL_CONTEXT (decl) = thunk_fndecl;
537 : 0 : DECL_ARG_TYPE (decl) = type;
538 : 0 : TREE_READONLY (decl) = 1;
539 : :
540 : 0 : struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
541 : 0 : sf->static_chain_decl = decl;
542 : :
543 : 0 : gimple_call_set_chain (call, decl);
544 : : }
545 : :
546 : : /* Return slot optimization is always possible and in fact required to
547 : : return values with DECL_BY_REFERENCE. */
548 : 18145 : if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
549 : 18145 : && (!is_gimple_reg_type (TREE_TYPE (resdecl))
550 : 32 : || DECL_BY_REFERENCE (resdecl)))
551 : 24 : gimple_call_set_return_slot_opt (call, true);
552 : :
553 : 18145 : if (restmp)
554 : : {
555 : 6757 : gimple_call_set_lhs (call, restmp);
556 : 6757 : gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
557 : : TREE_TYPE (TREE_TYPE (alias))));
558 : : }
559 : 18145 : gsi_insert_after (&bsi, call, GSI_NEW_STMT);
560 : 18145 : if (!alias_is_noreturn)
561 : : {
562 : 17836 : if (restmp && !this_adjusting
563 : 6599 : && (fixed_offset || virtual_offset))
564 : : {
565 : 161 : tree true_label = NULL_TREE;
566 : :
567 : 161 : if (TREE_CODE (TREE_TYPE (restmp)) == POINTER_TYPE)
568 : : {
569 : 122 : gimple *stmt;
570 : 122 : edge e;
571 : : /* If the return type is a pointer, we need to
572 : : protect against NULL. We know there will be an
573 : : adjustment, because that's why we're emitting a
574 : : thunk. */
575 : 122 : then_bb = create_basic_block (NULL, bb);
576 : 122 : then_bb->count = cfg_count - cfg_count / 16;
577 : 122 : return_bb = create_basic_block (NULL, then_bb);
578 : 122 : return_bb->count = cfg_count;
579 : 122 : else_bb = create_basic_block (NULL, else_bb);
580 : 122 : else_bb->count = cfg_count / 16;
581 : 122 : add_bb_to_loop (then_bb, bb->loop_father);
582 : 122 : add_bb_to_loop (return_bb, bb->loop_father);
583 : 122 : add_bb_to_loop (else_bb, bb->loop_father);
584 : 122 : remove_edge (single_succ_edge (bb));
585 : 122 : true_label = gimple_block_label (then_bb);
586 : 122 : stmt = gimple_build_cond (NE_EXPR, restmp,
587 : 122 : build_zero_cst (TREE_TYPE (restmp)),
588 : : NULL_TREE, NULL_TREE);
589 : 122 : gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
590 : 122 : e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
591 : 122 : e->probability = profile_probability::guessed_always () / 16;
592 : 122 : e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
593 : 122 : e->probability = profile_probability::guessed_always () / 16;
594 : 122 : make_single_succ_edge (return_bb,
595 : 122 : EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
596 : 122 : make_single_succ_edge (then_bb, return_bb, EDGE_FALLTHRU);
597 : 122 : e = make_edge (else_bb, return_bb, EDGE_FALLTHRU);
598 : 122 : e->probability = profile_probability::always ();
599 : 244 : bsi = gsi_last_bb (then_bb);
600 : : }
601 : :
602 : 161 : restmp = thunk_adjust (&bsi, restmp, /*this_adjusting=*/0,
603 : : fixed_offset, virtual_offset,
604 : : indirect_offset);
605 : 161 : if (true_label)
606 : : {
607 : 122 : gimple *stmt;
608 : 122 : bsi = gsi_last_bb (else_bb);
609 : 122 : stmt = gimple_build_assign (restmp,
610 : : build_zero_cst
611 : 122 : (TREE_TYPE (restmp)));
612 : 122 : gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
613 : 244 : bsi = gsi_last_bb (return_bb);
614 : : }
615 : : }
616 : : else
617 : : {
618 : 17675 : gimple_call_set_tail (call, true);
619 : 17675 : cfun->tail_call_marked = true;
620 : : }
621 : :
622 : : /* Build return value. */
623 : 17836 : if (!DECL_BY_REFERENCE (resdecl))
624 : 17820 : ret = gimple_build_return (restmp);
625 : : else
626 : 16 : ret = gimple_build_return (resdecl);
627 : :
628 : 17836 : gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
629 : : }
630 : : else
631 : : {
632 : 309 : gimple_call_set_ctrl_altering (call, true);
633 : 309 : gimple_call_set_tail (call, true);
634 : 309 : cfun->tail_call_marked = true;
635 : 309 : remove_edge (single_succ_edge (bb));
636 : : }
637 : :
638 : 18145 : cfun->gimple_df->in_ssa_p = true;
639 : 18145 : update_max_bb_count ();
640 : 18145 : profile_status_for_fn (cfun)
641 : 36290 : = cfg_count.initialized_p () && cfg_count.ipa_p ()
642 : 18145 : ? PROFILE_READ : PROFILE_GUESSED;
643 : : /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
644 : 18145 : TREE_ASM_WRITTEN (thunk_fndecl) = false;
645 : 18145 : cfun->cfg->full_profile = true;
646 : 18145 : delete_unreachable_blocks ();
647 : 18145 : update_ssa (TODO_update_ssa);
648 : 18145 : checking_verify_flow_info ();
649 : 18145 : free_dominance_info (CDI_DOMINATORS);
650 : :
651 : : /* Since we want to emit the thunk, we explicitly mark its name as
652 : : referenced. */
653 : 18145 : node->thunk = false;
654 : 18145 : node->lowered = true;
655 : 18145 : bitmap_obstack_release (NULL);
656 : 18145 : }
657 : 19897 : current_function_decl = NULL;
658 : 19897 : set_cfun (NULL);
659 : 19897 : return true;
660 : : }
661 : :
662 : : void
663 : 254814 : symtab_thunks_cc_finalize (void)
664 : : {
665 : 254814 : vtable_entry_type = NULL;
666 : 254814 : }
667 : :
668 : : #include "gt-symtab-thunks.h"
|