LCOV - code coverage report
Current view: top level - gcc - symtab-thunks.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.2 % 335 292
Test Date: 2026-02-28 14:20:25 Functions: 90.9 % 11 10
Legend: Lines:     hit not hit

            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"
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.