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 5865 : thunk_infos_t (symbol_table *table, bool ggc):
71 11730 : 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 356 : thunk_infos_t::duplicate (cgraph_node *, cgraph_node *,
83 : thunk_info *src, thunk_info *dst)
84 : {
85 356 : *dst = *src;
86 356 : }
87 :
88 : } /* anon namespace */
89 :
90 : /* Return thunk_info possibly creating new one. */
91 : thunk_info *
92 25136 : thunk_info::get_create (cgraph_node *node)
93 : {
94 25136 : if (!symtab->m_thunks)
95 : {
96 11730 : symtab->m_thunks
97 5865 : = new (ggc_alloc_no_dtor <thunk_infos_t> ())
98 5865 : thunk_infos_t (symtab, true);
99 5865 : symtab->m_thunks->disable_insertion_hook ();
100 : }
101 25136 : return symtab->m_thunks->get_create (node);
102 : }
103 :
104 : /* Stream out THIS to OB. */
105 : void
106 239 : thunk_info::stream_out (lto_simple_output_block *ob)
107 : {
108 239 : streamer_write_uhwi_stream
109 239 : (ob->main_stream,
110 239 : 1 + (this_adjusting != 0) * 2
111 395 : + (virtual_offset_p != 0) * 4);
112 239 : streamer_write_uhwi_stream (ob->main_stream, fixed_offset);
113 239 : streamer_write_uhwi_stream (ob->main_stream, virtual_value);
114 239 : streamer_write_uhwi_stream (ob->main_stream, indirect_offset);
115 239 : }
116 :
117 : /* Stream in THIS from IB. */
118 : void
119 171 : thunk_info::stream_in (class lto_input_block *ib)
120 : {
121 171 : int type = streamer_read_uhwi (ib);
122 171 : fixed_offset = streamer_read_uhwi (ib);
123 171 : virtual_value = streamer_read_uhwi (ib);
124 171 : indirect_offset = streamer_read_uhwi (ib);
125 :
126 171 : this_adjusting = (type & 2);
127 171 : virtual_offset_p = (type & 4);
128 171 : }
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 4622 : thunk_info::register_early (cgraph_node *node)
161 : {
162 4622 : unprocessed_thunk entry = {node, new (ggc_alloc <thunk_info> ()) thunk_info};
163 4622 : *entry.info = *this;
164 4622 : vec_safe_push (thunks, entry);
165 4622 : }
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 527351 : thunk_info::process_early_thunks ()
171 : {
172 527351 : unprocessed_thunk *e;
173 527351 : unsigned int i;
174 527351 : if (!thunks)
175 527351 : return;
176 :
177 5892 : FOR_EACH_VEC_ELT (*thunks, i, e)
178 : {
179 4622 : *thunk_info::get_create (e->node) = *e->info;
180 : }
181 1270 : vec_free (thunks);
182 1270 : 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 1554 : 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 1554 : gassign *stmt;
196 1554 : tree ret;
197 :
198 1554 : if (this_adjusting
199 1554 : && fixed_offset != 0)
200 : {
201 664 : stmt = gimple_build_assign
202 664 : (ptr, fold_build_pointer_plus_hwi_loc (input_location,
203 : ptr,
204 : fixed_offset));
205 664 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
206 : }
207 :
208 1554 : if (!vtable_entry_type && (virtual_offset || indirect_offset != 0))
209 : {
210 307 : tree vfunc_type = make_node (FUNCTION_TYPE);
211 307 : TREE_TYPE (vfunc_type) = integer_type_node;
212 307 : TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
213 307 : layout_type (vfunc_type);
214 :
215 307 : 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 955 : if (virtual_offset)
221 : {
222 841 : tree vtabletmp;
223 841 : tree vtabletmp2;
224 841 : tree vtabletmp3;
225 :
226 841 : vtabletmp = create_tmp_reg
227 841 : (build_pointer_type
228 : (build_pointer_type (vtable_entry_type)), "vptr");
229 :
230 : /* The vptr is always at offset zero in the object. */
231 841 : stmt = gimple_build_assign (vtabletmp,
232 841 : build1 (NOP_EXPR, TREE_TYPE (vtabletmp),
233 : ptr));
234 841 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
235 :
236 : /* Form the vtable address. */
237 841 : vtabletmp2 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp)),
238 : "vtableaddr");
239 841 : stmt = gimple_build_assign (vtabletmp2,
240 : build_simple_mem_ref (vtabletmp));
241 841 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
242 :
243 : /* Find the entry with the vcall offset. */
244 841 : stmt = gimple_build_assign (vtabletmp2,
245 : fold_build_pointer_plus_loc (input_location,
246 : vtabletmp2,
247 : virtual_offset));
248 841 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
249 :
250 : /* Get the offset itself. */
251 841 : vtabletmp3 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp2)),
252 : "vcalloffset");
253 841 : stmt = gimple_build_assign (vtabletmp3,
254 : build_simple_mem_ref (vtabletmp2));
255 841 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
256 :
257 : /* Adjust the `this' pointer. */
258 841 : ptr = fold_build_pointer_plus_loc (input_location, ptr, vtabletmp3);
259 841 : 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 1554 : 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 1554 : if (!this_adjusting
299 1554 : && 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 1554 : ret = create_tmp_reg (TREE_TYPE (ptr), "adjusted_this");
318 1554 : stmt = gimple_build_assign (ret, ptr);
319 1554 : gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
320 :
321 1554 : 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 25268 : expand_thunk (cgraph_node *node, bool output_asm_thunks,
331 : bool force_gimple_thunk)
332 : {
333 25268 : thunk_info *info = thunk_info::get (node);
334 25268 : bool this_adjusting = info->this_adjusting;
335 25268 : HOST_WIDE_INT fixed_offset = info->fixed_offset;
336 25268 : HOST_WIDE_INT virtual_value = info->virtual_value;
337 25268 : HOST_WIDE_INT indirect_offset = info->indirect_offset;
338 25268 : tree virtual_offset = NULL;
339 25268 : tree alias = node->callees->callee->decl;
340 25268 : tree thunk_fndecl = node->decl;
341 25268 : tree a;
342 :
343 25268 : if (!force_gimple_thunk
344 25268 : && this_adjusting
345 5234 : && indirect_offset == 0
346 5234 : && !DECL_EXTERNAL (alias)
347 5234 : && !DECL_STATIC_CHAIN (alias)
348 30502 : && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
349 : virtual_value, alias))
350 : {
351 5234 : tree fn_block;
352 5234 : tree restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
353 :
354 5234 : if (!output_asm_thunks)
355 : {
356 3330 : node->analyzed = true;
357 3330 : return false;
358 : }
359 :
360 1904 : if (in_lto_p)
361 17 : node->get_untransformed_body ();
362 1904 : a = DECL_ARGUMENTS (thunk_fndecl);
363 :
364 1904 : current_function_decl = thunk_fndecl;
365 :
366 : /* This thunk is emitted directly and bypasses cfgexpand, so resolve
367 : its section here. */
368 1904 : resolve_unique_section (thunk_fndecl, 0,
369 : flag_function_sections);
370 :
371 3808 : DECL_RESULT (thunk_fndecl)
372 1904 : = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
373 : RESULT_DECL, 0, restype);
374 1904 : DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl;
375 :
376 : /* The back end expects DECL_INITIAL to contain a BLOCK, so we
377 : create one. */
378 1904 : fn_block = make_node (BLOCK);
379 1904 : BLOCK_VARS (fn_block) = a;
380 1904 : DECL_INITIAL (thunk_fndecl) = fn_block;
381 1904 : BLOCK_SUPERCONTEXT (fn_block) = thunk_fndecl;
382 1904 : allocate_struct_function (thunk_fndecl, false);
383 1904 : init_function_start (thunk_fndecl);
384 1904 : cfun->is_thunk = 1;
385 1904 : insn_locations_init ();
386 1904 : set_curr_insn_location (DECL_SOURCE_LOCATION (thunk_fndecl));
387 1904 : prologue_location = curr_insn_location ();
388 :
389 1904 : targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
390 : fixed_offset, virtual_value, alias);
391 :
392 1904 : insn_locations_finalize ();
393 1904 : init_insn_lengths ();
394 1904 : free_after_compilation (cfun);
395 1904 : TREE_ASM_WRITTEN (thunk_fndecl) = 1;
396 1904 : node->thunk = false;
397 1904 : node->analyzed = false;
398 : }
399 20034 : else if (stdarg_p (TREE_TYPE (thunk_fndecl)))
400 : {
401 0 : error ("generic thunk code fails for method %qD which uses %<...%>",
402 : thunk_fndecl);
403 0 : TREE_ASM_WRITTEN (thunk_fndecl) = 1;
404 0 : node->analyzed = true;
405 0 : return false;
406 : }
407 : else
408 : {
409 20034 : tree restype;
410 20034 : basic_block bb, then_bb, else_bb, return_bb;
411 20034 : gimple_stmt_iterator bsi;
412 20034 : int nargs = 0;
413 20034 : tree arg;
414 20034 : int i;
415 20034 : tree resdecl;
416 20034 : tree restmp = NULL;
417 :
418 20034 : gcall *call;
419 20034 : greturn *ret;
420 20034 : bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
421 :
422 : /* We may be called from expand_thunk that releases body except for
423 : DECL_ARGUMENTS. In this case force_gimple_thunk is true. */
424 20034 : if (in_lto_p && !force_gimple_thunk)
425 0 : node->get_untransformed_body ();
426 :
427 : /* We need to force DECL_IGNORED_P when the thunk is created
428 : after early debug was run. */
429 18970 : if (force_gimple_thunk)
430 19873 : DECL_IGNORED_P (thunk_fndecl) = 1;
431 :
432 20034 : a = DECL_ARGUMENTS (thunk_fndecl);
433 :
434 20034 : current_function_decl = thunk_fndecl;
435 :
436 20034 : bitmap_obstack_initialize (NULL);
437 :
438 20034 : if (info->virtual_offset_p)
439 834 : virtual_offset = size_int (virtual_value);
440 :
441 : /* Build the return declaration for the function. */
442 20034 : restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
443 20034 : if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
444 : {
445 1356 : resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
446 1356 : DECL_ARTIFICIAL (resdecl) = 1;
447 1356 : DECL_IGNORED_P (resdecl) = 1;
448 1356 : DECL_CONTEXT (resdecl) = thunk_fndecl;
449 1356 : DECL_RESULT (thunk_fndecl) = resdecl;
450 : }
451 : else
452 : resdecl = DECL_RESULT (thunk_fndecl);
453 :
454 20034 : profile_count cfg_count = node->count;
455 20034 : if (!cfg_count.initialized_p ())
456 1363 : cfg_count = profile_count::from_gcov_type
457 1363 : (BB_FREQ_MAX).guessed_local ();
458 :
459 40068 : bb = then_bb = else_bb = return_bb
460 20034 : = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
461 :
462 20034 : bsi = gsi_start_bb (bb);
463 :
464 : /* Build call to the function being thunked. */
465 20034 : if (!VOID_TYPE_P (restype)
466 20034 : && (!alias_is_noreturn
467 22 : || TREE_ADDRESSABLE (restype)
468 19 : || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
469 : {
470 8275 : if (DECL_BY_REFERENCE (resdecl))
471 : {
472 19 : restmp = gimple_fold_indirect_ref (resdecl);
473 19 : if (!restmp)
474 38 : restmp = build2 (MEM_REF,
475 19 : TREE_TYPE (TREE_TYPE (resdecl)),
476 : resdecl,
477 19 : build_int_cst (TREE_TYPE (resdecl), 0));
478 : }
479 8256 : else if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
480 : {
481 16 : restmp = resdecl;
482 :
483 16 : if (VAR_P (restmp))
484 : {
485 0 : add_local_decl (cfun, restmp);
486 0 : BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
487 : }
488 : }
489 : else
490 8240 : restmp = create_tmp_reg (restype, "retval");
491 : }
492 :
493 54247 : for (arg = a; arg; arg = DECL_CHAIN (arg))
494 34213 : nargs++;
495 20034 : auto_vec<tree> vargs (nargs);
496 20034 : i = 0;
497 20034 : arg = a;
498 20034 : if (this_adjusting)
499 : {
500 1195 : vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
501 : virtual_offset, indirect_offset));
502 1195 : arg = DECL_CHAIN (a);
503 1195 : i = 1;
504 : }
505 :
506 20034 : if (nargs)
507 49574 : for (; i < nargs; i++, arg = DECL_CHAIN (arg))
508 : {
509 33018 : tree tmp = arg;
510 33018 : DECL_NOT_GIMPLE_REG_P (arg) = 0;
511 33018 : if (!is_gimple_val (arg))
512 : {
513 3 : tmp = create_tmp_reg (TYPE_MAIN_VARIANT
514 : (TREE_TYPE (arg)), "arg");
515 3 : gimple *stmt = gimple_build_assign (tmp, arg);
516 3 : gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
517 : }
518 33018 : vargs.quick_push (tmp);
519 : }
520 20034 : call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
521 20034 : node->callees->call_stmt = call;
522 20034 : gimple_call_set_from_thunk (call, true);
523 20034 : if (DECL_STATIC_CHAIN (alias))
524 : {
525 0 : tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
526 0 : tree type = TREE_TYPE (p);
527 0 : tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
528 : PARM_DECL, create_tmp_var_name ("CHAIN"),
529 : type);
530 0 : DECL_ARTIFICIAL (decl) = 1;
531 0 : DECL_IGNORED_P (decl) = 1;
532 0 : TREE_USED (decl) = 1;
533 0 : DECL_CONTEXT (decl) = thunk_fndecl;
534 0 : DECL_ARG_TYPE (decl) = type;
535 0 : TREE_READONLY (decl) = 1;
536 :
537 0 : struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
538 0 : sf->static_chain_decl = decl;
539 :
540 0 : gimple_call_set_chain (call, decl);
541 : }
542 :
543 : /* Return slot optimization is always possible and in fact required to
544 : return values with DECL_BY_REFERENCE. */
545 20034 : if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
546 20034 : && (!is_gimple_reg_type (TREE_TYPE (resdecl))
547 32 : || DECL_BY_REFERENCE (resdecl)))
548 22 : gimple_call_set_return_slot_opt (call, true);
549 :
550 20034 : if (restmp)
551 : {
552 8275 : gimple_call_set_lhs (call, restmp);
553 8275 : gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
554 : TREE_TYPE (TREE_TYPE (alias))));
555 : }
556 20034 : gsi_insert_after (&bsi, call, GSI_NEW_STMT);
557 20034 : if (!alias_is_noreturn)
558 : {
559 19726 : if (restmp && !this_adjusting
560 8111 : && (fixed_offset || virtual_offset))
561 : {
562 161 : tree true_label = NULL_TREE;
563 :
564 161 : if (TREE_CODE (TREE_TYPE (restmp)) == POINTER_TYPE)
565 : {
566 122 : gimple *stmt;
567 122 : edge e;
568 : /* If the return type is a pointer, we need to
569 : protect against NULL. We know there will be an
570 : adjustment, because that's why we're emitting a
571 : thunk. */
572 122 : then_bb = create_basic_block (NULL, bb);
573 122 : then_bb->count = cfg_count - cfg_count / 16;
574 122 : return_bb = create_basic_block (NULL, then_bb);
575 122 : return_bb->count = cfg_count;
576 122 : else_bb = create_basic_block (NULL, else_bb);
577 122 : else_bb->count = cfg_count / 16;
578 122 : add_bb_to_loop (then_bb, bb->loop_father);
579 122 : add_bb_to_loop (return_bb, bb->loop_father);
580 122 : add_bb_to_loop (else_bb, bb->loop_father);
581 122 : remove_edge (single_succ_edge (bb));
582 122 : true_label = gimple_block_label (then_bb);
583 122 : stmt = gimple_build_cond (NE_EXPR, restmp,
584 122 : build_zero_cst (TREE_TYPE (restmp)),
585 : NULL_TREE, NULL_TREE);
586 122 : gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
587 122 : e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
588 122 : e->probability = profile_probability::guessed_always () / 16;
589 122 : e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
590 122 : e->probability = profile_probability::guessed_always () / 16;
591 122 : make_single_succ_edge (return_bb,
592 122 : EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
593 122 : make_single_succ_edge (then_bb, return_bb, EDGE_FALLTHRU);
594 122 : e = make_edge (else_bb, return_bb, EDGE_FALLTHRU);
595 122 : e->probability = profile_probability::always ();
596 244 : bsi = gsi_last_bb (then_bb);
597 : }
598 :
599 161 : restmp = thunk_adjust (&bsi, restmp, /*this_adjusting=*/0,
600 : fixed_offset, virtual_offset,
601 : indirect_offset);
602 161 : if (true_label)
603 : {
604 122 : gimple *stmt;
605 122 : bsi = gsi_last_bb (else_bb);
606 122 : stmt = gimple_build_assign (restmp,
607 : build_zero_cst
608 122 : (TREE_TYPE (restmp)));
609 122 : gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
610 244 : bsi = gsi_last_bb (return_bb);
611 : }
612 : }
613 : else
614 : {
615 19565 : gimple_call_set_tail (call, true);
616 19565 : cfun->tail_call_marked = true;
617 : }
618 :
619 : /* Build return value. */
620 19726 : if (!DECL_BY_REFERENCE (resdecl))
621 19710 : ret = gimple_build_return (restmp);
622 : else
623 16 : ret = gimple_build_return (resdecl);
624 :
625 19726 : gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
626 : }
627 : else
628 : {
629 308 : gimple_call_set_ctrl_altering (call, true);
630 308 : gimple_call_set_tail (call, true);
631 308 : cfun->tail_call_marked = true;
632 308 : remove_edge (single_succ_edge (bb));
633 : }
634 :
635 20034 : cfun->gimple_df->in_ssa_p = true;
636 20034 : update_max_bb_count ();
637 20034 : profile_status_for_fn (cfun)
638 19980 : = cfg_count.initialized_p () && cfg_count.ipa_p ()
639 20034 : ? PROFILE_READ : PROFILE_GUESSED;
640 : /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
641 20034 : TREE_ASM_WRITTEN (thunk_fndecl) = false;
642 20034 : cfun->cfg->full_profile = true;
643 20034 : delete_unreachable_blocks ();
644 20034 : update_ssa (TODO_update_ssa);
645 20034 : checking_verify_flow_info ();
646 20034 : free_dominance_info (CDI_DOMINATORS);
647 :
648 : /* Since we want to emit the thunk, we explicitly mark its name as
649 : referenced. */
650 20034 : node->thunk = false;
651 20034 : node->lowered = true;
652 20034 : bitmap_obstack_release (NULL);
653 20034 : }
654 21938 : current_function_decl = NULL;
655 21938 : set_cfun (NULL);
656 21938 : return true;
657 : }
658 :
659 : void
660 264460 : symtab_thunks_cc_finalize (void)
661 : {
662 264460 : vtable_entry_type = NULL;
663 264460 : }
664 :
665 : #include "gt-symtab-thunks.h"
|