LCOV - code coverage report
Current view: top level - gcc - symtab-thunks.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.1 % 334 291
Test Date: 2026-09-19 16:22:48 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         5832 :   thunk_infos_t (symbol_table *table, bool ggc):
      71        11664 :     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        24975 : thunk_info::get_create (cgraph_node *node)
      93              : {
      94        24975 :   if (!symtab->m_thunks)
      95              :     {
      96        11664 :       symtab->m_thunks
      97         5832 :          = new (ggc_alloc_no_dtor <thunk_infos_t> ())
      98         5832 :              thunk_infos_t (symtab, true);
      99         5832 :       symtab->m_thunks->disable_insertion_hook ();
     100              :     }
     101        24975 :   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         4582 : thunk_info::register_early (cgraph_node *node)
     161              : {
     162         4582 :   unprocessed_thunk entry = {node, new (ggc_alloc <thunk_info> ()) thunk_info};
     163         4582 :   *entry.info = *this;
     164         4582 :   vec_safe_push (thunks, entry);
     165         4582 : }
     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       527133 : thunk_info::process_early_thunks ()
     171              : {
     172       527133 :   unprocessed_thunk *e;
     173       527133 :   unsigned int i;
     174       527133 :   if (!thunks)
     175       527133 :     return;
     176              : 
     177         5842 :   FOR_EACH_VEC_ELT (*thunks, i, e)
     178              :     {
     179         4582 :       *thunk_info::get_create (e->node) = *e->info;
     180              :     }
     181         1260 :   vec_free (thunks);
     182         1260 :   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         1518 : 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         1518 :   gassign *stmt;
     196         1518 :   tree ret;
     197              : 
     198         1518 :   if (this_adjusting
     199         1518 :       && 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         1518 :   if (!vtable_entry_type && (virtual_offset || indirect_offset != 0))
     209              :     {
     210          298 :       tree vfunc_type = make_node (FUNCTION_TYPE);
     211          298 :       TREE_TYPE (vfunc_type) = integer_type_node;
     212          298 :       TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
     213          298 :       layout_type (vfunc_type);
     214              : 
     215          298 :       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          919 :   if (virtual_offset)
     221              :     {
     222          805 :       tree vtabletmp;
     223          805 :       tree vtabletmp2;
     224          805 :       tree vtabletmp3;
     225              : 
     226          805 :       vtabletmp = create_tmp_reg
     227          805 :                     (build_pointer_type
     228              :                           (build_pointer_type (vtable_entry_type)), "vptr");
     229              : 
     230              :       /* The vptr is always at offset zero in the object.  */
     231          805 :       stmt = gimple_build_assign (vtabletmp,
     232          805 :                                   build1 (NOP_EXPR, TREE_TYPE (vtabletmp),
     233              :                                           ptr));
     234          805 :       gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
     235              : 
     236              :       /* Form the vtable address.  */
     237          805 :       vtabletmp2 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp)),
     238              :                                      "vtableaddr");
     239          805 :       stmt = gimple_build_assign (vtabletmp2,
     240              :                                   build_simple_mem_ref (vtabletmp));
     241          805 :       gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
     242              : 
     243              :       /* Find the entry with the vcall offset.  */
     244          805 :       stmt = gimple_build_assign (vtabletmp2,
     245              :                                   fold_build_pointer_plus_loc (input_location,
     246              :                                                                vtabletmp2,
     247              :                                                                virtual_offset));
     248          805 :       gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
     249              : 
     250              :       /* Get the offset itself.  */
     251          805 :       vtabletmp3 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp2)),
     252              :                                      "vcalloffset");
     253          805 :       stmt = gimple_build_assign (vtabletmp3,
     254              :                                   build_simple_mem_ref (vtabletmp2));
     255          805 :       gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
     256              : 
     257              :       /* Adjust the `this' pointer.  */
     258          805 :       ptr = fold_build_pointer_plus_loc (input_location, ptr, vtabletmp3);
     259          805 :       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         1518 :   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         1518 :   if (!this_adjusting
     299         1518 :       && 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         1518 :   ret = create_tmp_reg (TREE_TYPE (ptr), "adjusted_this");
     318         1518 :   stmt = gimple_build_assign (ret, ptr);
     319         1518 :   gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
     320              : 
     321         1518 :   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        25111 : expand_thunk (cgraph_node *node, bool output_asm_thunks,
     331              :               bool force_gimple_thunk)
     332              : {
     333        25111 :   thunk_info *info = thunk_info::get (node);
     334        25111 :   bool this_adjusting = info->this_adjusting;
     335        25111 :   HOST_WIDE_INT fixed_offset = info->fixed_offset;
     336        25111 :   HOST_WIDE_INT virtual_value = info->virtual_value;
     337        25111 :   HOST_WIDE_INT indirect_offset = info->indirect_offset;
     338        25111 :   tree virtual_offset = NULL;
     339        25111 :   tree alias = node->callees->callee->decl;
     340        25111 :   tree thunk_fndecl = node->decl;
     341        25111 :   tree a;
     342              : 
     343        25111 :   if (!force_gimple_thunk
     344        25111 :       && this_adjusting
     345         5186 :       && indirect_offset == 0
     346         5186 :       && !DECL_EXTERNAL (alias)
     347         5186 :       && !DECL_STATIC_CHAIN (alias)
     348        30297 :       && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
     349              :                                               virtual_value, alias))
     350              :     {
     351         5186 :       tree fn_block;
     352         5186 :       tree restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
     353              : 
     354         5186 :       if (!output_asm_thunks)
     355              :         {
     356         3290 :           node->analyzed = true;
     357         3290 :           return false;
     358              :         }
     359              : 
     360         1896 :       if (in_lto_p)
     361           17 :         node->get_untransformed_body ();
     362         1896 :       a = DECL_ARGUMENTS (thunk_fndecl);
     363              : 
     364         1896 :       current_function_decl = thunk_fndecl;
     365              : 
     366              :       /* This thunk is emitted directly and bypasses cfgexpand, so resolve
     367              :          its section here.  */
     368         1896 :       resolve_unique_section (thunk_fndecl, 0,
     369              :                               flag_function_sections);
     370              : 
     371         3792 :       DECL_RESULT (thunk_fndecl)
     372         1896 :         = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
     373              :                       RESULT_DECL, 0, restype);
     374         1896 :       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         1896 :       fn_block = make_node (BLOCK);
     379         1896 :       BLOCK_VARS (fn_block) = a;
     380         1896 :       DECL_INITIAL (thunk_fndecl) = fn_block;
     381         1896 :       BLOCK_SUPERCONTEXT (fn_block) = thunk_fndecl;
     382         1896 :       allocate_struct_function (thunk_fndecl, false);
     383         1896 :       init_function_start (thunk_fndecl);
     384         1896 :       cfun->is_thunk = 1;
     385         1896 :       insn_locations_init ();
     386         1896 :       set_curr_insn_location (DECL_SOURCE_LOCATION (thunk_fndecl));
     387         1896 :       prologue_location = curr_insn_location ();
     388              : 
     389         1896 :       targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
     390              :                                        fixed_offset, virtual_value, alias);
     391              : 
     392         1896 :       insn_locations_finalize ();
     393         1896 :       init_insn_lengths ();
     394         1896 :       free_after_compilation (cfun);
     395         1896 :       TREE_ASM_WRITTEN (thunk_fndecl) = 1;
     396         1896 :       node->thunk = false;
     397         1896 :       node->analyzed = false;
     398              :     }
     399        19925 :   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        19925 :       tree restype;
     410        19925 :       basic_block bb, then_bb, else_bb, return_bb;
     411        19925 :       gimple_stmt_iterator bsi;
     412        19925 :       int nargs = 0;
     413        19925 :       tree arg;
     414        19925 :       int i;
     415        19925 :       tree resdecl;
     416        19925 :       tree restmp = NULL;
     417              : 
     418        19925 :       gcall *call;
     419        19925 :       greturn *ret;
     420        19925 :       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        19925 :       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        18869 :       if (force_gimple_thunk)
     430        19764 :         DECL_IGNORED_P (thunk_fndecl) = 1;
     431              : 
     432        19925 :       a = DECL_ARGUMENTS (thunk_fndecl);
     433              : 
     434        19925 :       current_function_decl = thunk_fndecl;
     435              : 
     436        19925 :       bitmap_obstack_initialize (NULL);
     437              : 
     438        19925 :       if (info->virtual_offset_p)
     439          798 :         virtual_offset = size_int (virtual_value);
     440              : 
     441              :       /* Build the return declaration for the function.  */
     442        19925 :       restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
     443        19925 :       if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
     444              :         {
     445         1320 :           resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
     446         1320 :           DECL_ARTIFICIAL (resdecl) = 1;
     447         1320 :           DECL_IGNORED_P (resdecl) = 1;
     448         1320 :           DECL_CONTEXT (resdecl) = thunk_fndecl;
     449         1320 :           DECL_RESULT (thunk_fndecl) = resdecl;
     450              :         }
     451              :       else
     452              :         resdecl = DECL_RESULT (thunk_fndecl);
     453              : 
     454        19925 :       profile_count cfg_count = node->count;
     455        19925 :       if (!cfg_count.initialized_p ())
     456         1327 :         cfg_count = profile_count::from_gcov_type
     457         1327 :                          (BB_FREQ_MAX).guessed_local ();
     458              : 
     459        39850 :       bb = then_bb = else_bb = return_bb
     460        19925 :         = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
     461              : 
     462        19925 :       bsi = gsi_start_bb (bb);
     463              : 
     464              :       /* Build call to the function being thunked.  */
     465        19925 :       if (!VOID_TYPE_P (restype)
     466        19925 :           && (!alias_is_noreturn
     467           22 :               || TREE_ADDRESSABLE (restype)
     468           19 :               || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
     469              :         {
     470         8234 :           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         8215 :           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         8199 :             restmp = create_tmp_reg (restype, "retval");
     491              :         }
     492              : 
     493        53909 :       for (arg = a; arg; arg = DECL_CHAIN (arg))
     494        33984 :         nargs++;
     495        19925 :       auto_vec<tree> vargs (nargs);
     496        19925 :       i = 0;
     497        19925 :       arg = a;
     498        19925 :       if (this_adjusting)
     499              :         {
     500         1159 :           vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
     501              :                                           virtual_offset, indirect_offset));
     502         1159 :           arg = DECL_CHAIN (a);
     503         1159 :           i = 1;
     504              :         }
     505              : 
     506        19925 :       if (nargs)
     507        49275 :         for (; i < nargs; i++, arg = DECL_CHAIN (arg))
     508              :           {
     509        32825 :             tree tmp = arg;
     510        32825 :             DECL_NOT_GIMPLE_REG_P (arg) = 0;
     511        32825 :             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        32825 :             vargs.quick_push (tmp);
     519              :           }
     520        19925 :       call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
     521        19925 :       node->callees->call_stmt = call;
     522        19925 :       gimple_call_set_from_thunk (call, true);
     523        19925 :       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        19925 :       if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
     546        19925 :           && (!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        19925 :       if (restmp)
     551              :         {
     552         8234 :           gimple_call_set_lhs (call, restmp);
     553         8234 :           gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
     554              :                                                  TREE_TYPE (TREE_TYPE (alias))));
     555              :         }
     556        19925 :       gsi_insert_after (&bsi, call, GSI_NEW_STMT);
     557        19925 :       if (!alias_is_noreturn)
     558              :         {
     559        19617 :           if (restmp && !this_adjusting
     560         8070 :               && (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        19456 :               gimple_call_set_tail (call, true);
     616        19456 :               cfun->tail_call_marked = true;
     617              :             }
     618              : 
     619              :           /* Build return value.  */
     620        19617 :           if (!DECL_BY_REFERENCE (resdecl))
     621        19601 :             ret = gimple_build_return (restmp);
     622              :           else
     623           16 :             ret = gimple_build_return (resdecl);
     624              : 
     625        19617 :           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        19925 :       cfun->gimple_df->in_ssa_p = true;
     636        19925 :       update_max_bb_count ();
     637        19925 :       profile_status_for_fn (cfun)
     638        19871 :         = cfg_count.initialized_p () && cfg_count.ipa_p ()
     639        19925 :           ? PROFILE_READ : PROFILE_GUESSED;
     640              :       /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks.  */
     641        19925 :       TREE_ASM_WRITTEN (thunk_fndecl) = false;
     642        19925 :       cfun->cfg->full_profile = true;
     643        19925 :       delete_unreachable_blocks ();
     644        19925 :       update_ssa (TODO_update_ssa);
     645        19925 :       checking_verify_flow_info ();
     646        19925 :       free_dominance_info (CDI_DOMINATORS);
     647              : 
     648              :       /* Since we want to emit the thunk, we explicitly mark its name as
     649              :          referenced.  */
     650        19925 :       node->thunk = false;
     651        19925 :       node->lowered = true;
     652        19925 :       bitmap_obstack_release (NULL);
     653        19925 :     }
     654        21821 :   current_function_decl = NULL;
     655        21821 :   set_cfun (NULL);
     656        21821 :   return true;
     657              : }
     658              : 
     659              : void
     660       264541 : symtab_thunks_cc_finalize (void)
     661              : {
     662       264541 :   vtable_entry_type = NULL;
     663       264541 : }
     664              : 
     665              : #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.