Line data Source code
1 : /* Support for thunks in symbol table.
2 : Copyright (C) 2003-2026 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 5727 : thunk_infos_t (symbol_table *table, bool ggc):
71 11454 : 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 362 : thunk_infos_t::duplicate (cgraph_node *, cgraph_node *,
83 : thunk_info *src, thunk_info *dst)
84 : {
85 362 : *dst = *src;
86 362 : }
87 :
88 : } /* anon namespace */
89 :
90 : /* Return thunk_info possibly creating new one. */
91 : thunk_info *
92 24183 : thunk_info::get_create (cgraph_node *node)
93 : {
94 24183 : if (!symtab->m_thunks)
95 : {
96 11454 : symtab->m_thunks
97 5727 : = new (ggc_alloc_no_dtor <thunk_infos_t> ())
98 5727 : thunk_infos_t (symtab, true);
99 5727 : symtab->m_thunks->disable_insertion_hook ();
100 : }
101 24183 : return symtab->m_thunks->get_create (node);
102 : }
103 :
104 : /* Stream out THIS to OB. */
105 : void
106 227 : thunk_info::stream_out (lto_simple_output_block *ob)
107 : {
108 227 : streamer_write_uhwi_stream
109 227 : (ob->main_stream,
110 227 : 1 + (this_adjusting != 0) * 2
111 383 : + (virtual_offset_p != 0) * 4);
112 227 : streamer_write_uhwi_stream (ob->main_stream, fixed_offset);
113 227 : streamer_write_uhwi_stream (ob->main_stream, virtual_value);
114 227 : streamer_write_uhwi_stream (ob->main_stream, indirect_offset);
115 227 : }
116 :
117 : /* Stream in THIS from IB. */
118 : void
119 159 : thunk_info::stream_in (class lto_input_block *ib)
120 : {
121 159 : int type = streamer_read_uhwi (ib);
122 159 : fixed_offset = streamer_read_uhwi (ib);
123 159 : virtual_value = streamer_read_uhwi (ib);
124 159 : indirect_offset = streamer_read_uhwi (ib);
125 :
126 159 : this_adjusting = (type & 2);
127 159 : virtual_offset_p = (type & 4);
128 159 : }
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 4357 : thunk_info::register_early (cgraph_node *node)
161 : {
162 4357 : unprocessed_thunk entry = {node, new (ggc_alloc <thunk_info> ()) thunk_info};
163 4357 : *entry.info = *this;
164 4357 : vec_safe_push (thunks, entry);
165 4357 : }
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 511381 : thunk_info::process_early_thunks ()
171 : {
172 511381 : unprocessed_thunk *e;
173 511381 : unsigned int i;
174 511381 : if (!thunks)
175 511381 : return;
176 :
177 5590 : FOR_EACH_VEC_ELT (*thunks, i, e)
178 : {
179 4357 : *thunk_info::get_create (e->node) = *e->info;
180 : }
181 1233 : vec_free (thunks);
182 1233 : 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 1507 : 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 1507 : gassign *stmt;
196 1507 : tree ret;
197 :
198 1507 : if (this_adjusting
199 1507 : && fixed_offset != 0)
200 : {
201 677 : stmt = gimple_build_assign
202 677 : (ptr, fold_build_pointer_plus_hwi_loc (input_location,
203 : ptr,
204 : fixed_offset));
205 677 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
206 : }
207 :
208 1507 : if (!vtable_entry_type && (virtual_offset || indirect_offset != 0))
209 : {
210 289 : tree vfunc_type = make_node (FUNCTION_TYPE);
211 289 : TREE_TYPE (vfunc_type) = integer_type_node;
212 289 : TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
213 289 : layout_type (vfunc_type);
214 :
215 289 : 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 891 : if (virtual_offset)
221 : {
222 781 : tree vtabletmp;
223 781 : tree vtabletmp2;
224 781 : tree vtabletmp3;
225 :
226 781 : vtabletmp = create_tmp_reg
227 781 : (build_pointer_type
228 : (build_pointer_type (vtable_entry_type)), "vptr");
229 :
230 : /* The vptr is always at offset zero in the object. */
231 781 : stmt = gimple_build_assign (vtabletmp,
232 781 : build1 (NOP_EXPR, TREE_TYPE (vtabletmp),
233 : ptr));
234 781 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
235 :
236 : /* Form the vtable address. */
237 781 : vtabletmp2 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp)),
238 : "vtableaddr");
239 781 : stmt = gimple_build_assign (vtabletmp2,
240 : build_simple_mem_ref (vtabletmp));
241 781 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
242 :
243 : /* Find the entry with the vcall offset. */
244 781 : stmt = gimple_build_assign (vtabletmp2,
245 : fold_build_pointer_plus_loc (input_location,
246 : vtabletmp2,
247 : virtual_offset));
248 781 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
249 :
250 : /* Get the offset itself. */
251 781 : vtabletmp3 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp2)),
252 : "vcalloffset");
253 781 : stmt = gimple_build_assign (vtabletmp3,
254 : build_simple_mem_ref (vtabletmp2));
255 781 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
256 :
257 : /* Adjust the `this' pointer. */
258 781 : ptr = fold_build_pointer_plus_loc (input_location, ptr, vtabletmp3);
259 781 : 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 1507 : 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 1507 : if (!this_adjusting
299 1507 : && 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 1507 : ret = create_tmp_reg (TREE_TYPE (ptr), "adjusted_this");
318 1507 : stmt = gimple_build_assign (ret, ptr);
319 1507 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
320 :
321 1507 : 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 24273 : expand_thunk (cgraph_node *node, bool output_asm_thunks,
331 : bool force_gimple_thunk)
332 : {
333 24273 : thunk_info *info = thunk_info::get (node);
334 24273 : bool this_adjusting = info->this_adjusting;
335 24273 : HOST_WIDE_INT fixed_offset = info->fixed_offset;
336 24273 : HOST_WIDE_INT virtual_value = info->virtual_value;
337 24273 : HOST_WIDE_INT indirect_offset = info->indirect_offset;
338 24273 : tree virtual_offset = NULL;
339 24273 : tree alias = node->callees->callee->decl;
340 24273 : tree thunk_fndecl = node->decl;
341 24273 : tree a;
342 :
343 24273 : if (!force_gimple_thunk
344 24273 : && this_adjusting
345 4908 : && indirect_offset == 0
346 4908 : && !DECL_EXTERNAL (alias)
347 4908 : && !DECL_STATIC_CHAIN (alias)
348 29181 : && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
349 : virtual_value, alias))
350 : {
351 4908 : tree fn_block;
352 4908 : tree restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
353 :
354 4908 : if (!output_asm_thunks)
355 : {
356 3147 : node->analyzed = true;
357 3147 : return false;
358 : }
359 :
360 1761 : if (in_lto_p)
361 17 : node->get_untransformed_body ();
362 1761 : a = DECL_ARGUMENTS (thunk_fndecl);
363 :
364 1761 : current_function_decl = thunk_fndecl;
365 :
366 : /* Ensure thunks are emitted in their correct sections. */
367 1761 : resolve_unique_section (thunk_fndecl, 0,
368 : flag_function_sections);
369 :
370 3522 : DECL_RESULT (thunk_fndecl)
371 1761 : = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
372 : RESULT_DECL, 0, restype);
373 1761 : 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 1761 : fn_block = make_node (BLOCK);
378 1761 : BLOCK_VARS (fn_block) = a;
379 1761 : DECL_INITIAL (thunk_fndecl) = fn_block;
380 1761 : BLOCK_SUPERCONTEXT (fn_block) = thunk_fndecl;
381 1761 : allocate_struct_function (thunk_fndecl, false);
382 1761 : init_function_start (thunk_fndecl);
383 1761 : cfun->is_thunk = 1;
384 1761 : insn_locations_init ();
385 1761 : set_curr_insn_location (DECL_SOURCE_LOCATION (thunk_fndecl));
386 1761 : prologue_location = curr_insn_location ();
387 :
388 1761 : targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
389 : fixed_offset, virtual_value, alias);
390 :
391 1761 : insn_locations_finalize ();
392 1761 : init_insn_lengths ();
393 1761 : free_after_compilation (cfun);
394 1761 : TREE_ASM_WRITTEN (thunk_fndecl) = 1;
395 1761 : node->thunk = false;
396 1761 : node->analyzed = false;
397 : }
398 19365 : 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 19365 : tree restype;
409 19365 : basic_block bb, then_bb, else_bb, return_bb;
410 19365 : gimple_stmt_iterator bsi;
411 19365 : int nargs = 0;
412 19365 : tree arg;
413 19365 : int i;
414 19365 : tree resdecl;
415 19365 : tree restmp = NULL;
416 :
417 19365 : gcall *call;
418 19365 : greturn *ret;
419 19365 : 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 19365 : 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 18357 : if (force_gimple_thunk)
429 19204 : DECL_IGNORED_P (thunk_fndecl) = 1;
430 :
431 19365 : a = DECL_ARGUMENTS (thunk_fndecl);
432 :
433 19365 : current_function_decl = thunk_fndecl;
434 :
435 : /* Ensure thunks are emitted in their correct sections. */
436 19365 : resolve_unique_section (thunk_fndecl, 0,
437 : flag_function_sections);
438 :
439 19365 : bitmap_obstack_initialize (NULL);
440 :
441 19365 : if (info->virtual_offset_p)
442 774 : virtual_offset = size_int (virtual_value);
443 :
444 : /* Build the return declaration for the function. */
445 19365 : restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
446 19365 : 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 19365 : profile_count cfg_count = node->count;
458 19365 : if (!cfg_count.initialized_p ())
459 1301 : cfg_count = profile_count::from_gcov_type
460 1301 : (BB_FREQ_MAX).guessed_local ();
461 :
462 38730 : bb = then_bb = else_bb = return_bb
463 19365 : = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
464 :
465 19365 : bsi = gsi_start_bb (bb);
466 :
467 : /* Build call to the function being thunked. */
468 19365 : if (!VOID_TYPE_P (restype)
469 19365 : && (!alias_is_noreturn
470 26 : || TREE_ADDRESSABLE (restype)
471 23 : || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
472 : {
473 7730 : 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 7711 : 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 7693 : restmp = create_tmp_reg (restype, "retval");
494 : }
495 :
496 52325 : for (arg = a; arg; arg = DECL_CHAIN (arg))
497 32960 : nargs++;
498 19365 : auto_vec<tree> vargs (nargs);
499 19365 : i = 0;
500 19365 : arg = a;
501 19365 : 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 19365 : if (nargs)
510 47760 : for (; i < nargs; i++, arg = DECL_CHAIN (arg))
511 : {
512 31827 : tree tmp = arg;
513 31827 : DECL_NOT_GIMPLE_REG_P (arg) = 0;
514 31827 : 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 31827 : vargs.quick_push (tmp);
522 : }
523 19365 : call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
524 19365 : node->callees->call_stmt = call;
525 19365 : gimple_call_set_from_thunk (call, true);
526 19365 : 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 19365 : if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
549 19365 : && (!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 19365 : if (restmp)
554 : {
555 7730 : gimple_call_set_lhs (call, restmp);
556 7730 : gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
557 : TREE_TYPE (TREE_TYPE (alias))));
558 : }
559 19365 : gsi_insert_after (&bsi, call, GSI_NEW_STMT);
560 19365 : if (!alias_is_noreturn)
561 : {
562 19053 : if (restmp && !this_adjusting
563 7564 : && (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 18892 : gimple_call_set_tail (call, true);
619 18892 : cfun->tail_call_marked = true;
620 : }
621 :
622 : /* Build return value. */
623 19053 : if (!DECL_BY_REFERENCE (resdecl))
624 19037 : ret = gimple_build_return (restmp);
625 : else
626 16 : ret = gimple_build_return (resdecl);
627 :
628 19053 : gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
629 : }
630 : else
631 : {
632 312 : gimple_call_set_ctrl_altering (call, true);
633 312 : gimple_call_set_tail (call, true);
634 312 : cfun->tail_call_marked = true;
635 312 : remove_edge (single_succ_edge (bb));
636 : }
637 :
638 19365 : cfun->gimple_df->in_ssa_p = true;
639 19365 : update_max_bb_count ();
640 19365 : profile_status_for_fn (cfun)
641 38730 : = cfg_count.initialized_p () && cfg_count.ipa_p ()
642 19365 : ? PROFILE_READ : PROFILE_GUESSED;
643 : /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
644 19365 : TREE_ASM_WRITTEN (thunk_fndecl) = false;
645 19365 : cfun->cfg->full_profile = true;
646 19365 : delete_unreachable_blocks ();
647 19365 : update_ssa (TODO_update_ssa);
648 19365 : checking_verify_flow_info ();
649 19365 : free_dominance_info (CDI_DOMINATORS);
650 :
651 : /* Since we want to emit the thunk, we explicitly mark its name as
652 : referenced. */
653 19365 : node->thunk = false;
654 19365 : node->lowered = true;
655 19365 : bitmap_obstack_release (NULL);
656 19365 : }
657 21126 : current_function_decl = NULL;
658 21126 : set_cfun (NULL);
659 21126 : return true;
660 : }
661 :
662 : void
663 256621 : symtab_thunks_cc_finalize (void)
664 : {
665 256621 : vtable_entry_type = NULL;
666 256621 : }
667 :
668 : #include "gt-symtab-thunks.h"
|