LCOV - code coverage report
Current view: top level - gcc - asm-toplevel.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.8 % 97 92
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Toplevel assembly.
       2              :    Copyright (C) 2025 Free Software Foundation, Inc.
       3              :    Contributed by Michal Jires <mjires@suse.cz>
       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 "tree-pass.h"
      27              : #include "cgraph.h"
      28              : 
      29              : /* This symbol must be available and cannot be renamed.
      30              :    Marks the symbol and symbols that reference it.  */
      31              : static void
      32           49 : mark_fragile_ref_by_asm (symtab_node* node, bool maybe_local = false)
      33              : {
      34           49 :   node->ref_by_asm = true;
      35              :   /* Local symbols must remain in the same partition with their callers.  */
      36           49 :   if (!TREE_PUBLIC (node->decl) || maybe_local)
      37              :     {
      38           35 :       unsigned j;
      39           35 :       ipa_ref *ref;
      40           35 :       node->must_remain_in_tu_name = true;
      41           62 :       for (j = 0; node->iterate_referring (j, ref); j++)
      42           27 :         ref->referring->must_remain_in_tu_body = true;
      43              : 
      44           51 :       if (cgraph_node* cnode = dyn_cast <cgraph_node *> (node))
      45           31 :         for (cgraph_edge *e = cnode->callers; e ; e = e->next_caller)
      46           15 :           e->caller->must_remain_in_tu_body = true;
      47              :     }
      48           49 : }
      49              : 
      50              : /* Helper struct for walk_through_constraints.  */
      51              : struct constraint_data {
      52              :   asm_node *node;
      53              :   unsigned asm_definition : 1;
      54              : };
      55              : 
      56              : /* Mark symbols in constraints.  */
      57              : static tree
      58         1475 : walk_through_constraints (tree* t, int*, void* dat)
      59              : {
      60         1475 :   constraint_data* data = (constraint_data*) dat;
      61         1475 :   asm_node* anode = data->node;
      62              : 
      63         1475 :   if (VAR_OR_FUNCTION_DECL_P (*t))
      64              :     {
      65          389 :       symtab_node* node;
      66          389 :       if (!flag_wpa && !flag_ltrans)
      67              :         {
      68          369 :           node = symtab_node::get_create (*t);
      69          369 :           node->ref_by_asm = true;
      70              : 
      71              :           /* Disable implicit definition on static variables defined in asm.  */
      72          167 :           if (data->asm_definition && is_a<varpool_node*> (node)
      73          490 :               && !TREE_PUBLIC (node->decl))
      74           10 :             DECL_EXTERNAL (node->decl) = true;
      75              : 
      76          369 :           if (data->asm_definition && !TREE_PUBLIC (node->decl) && flag_lto)
      77           14 :             node->must_remain_in_tu_name = true;
      78              :         }
      79              :       else
      80              :         {
      81           20 :           node = symtab_node::get (*t);
      82           20 :           gcc_assert (node);
      83              : 
      84              :           /* Local symbols defined in asm cannot be renamed.
      85              :              LGEN pass is too early to use node->callers.
      86              :              So we do it in WPA.  */
      87           20 :           if (data->asm_definition && flag_wpa)
      88           19 :             mark_fragile_ref_by_asm (node);
      89              :         }
      90          389 :       anode->symbols_referenced.safe_push (node);
      91              :     }
      92         1475 :   return NULL;
      93              : }
      94              : 
      95              : /* Analyze constraints of toplevel extended assembly.  */
      96              : void
      97       267899 : analyze_toplevel_extended_asm ()
      98              : {
      99       267899 :   asm_node *anode;
     100       280847 :   for (anode = symtab->first_asm_symbol (); anode;
     101        12948 :        anode = safe_as_a<asm_node*> (anode->next))
     102              :     {
     103        12948 :       if (TREE_CODE (anode->asm_str) != ASM_EXPR)
     104        12777 :         continue;
     105          171 :       struct constraint_data data {anode, false};
     106              : 
     107          398 :       for (tree l = ASM_INPUTS (anode->asm_str); l; l = TREE_CHAIN (l))
     108              :         {
     109          227 :           tree constraint = TREE_VALUE (TREE_PURPOSE (l));
     110          227 :           const char* c = TREE_STRING_POINTER (constraint);
     111          227 :           data.asm_definition = c[0] == ':' && c[1] == 0;
     112          227 :           walk_tree (&l, walk_through_constraints, (void*) &data, NULL);
     113              :         }
     114          171 :       data.asm_definition = false;
     115          219 :       for (tree l = ASM_OUTPUTS (anode->asm_str); l; l = TREE_CHAIN (l))
     116           48 :         walk_tree (&l, walk_through_constraints, (void*) &data, NULL);
     117              :     }
     118       267899 : }
     119              : 
     120              : 
     121              : /* Checks all toplevel assembly contents and compares them with known symbols.
     122              :    Marks those symbols with relevant flags.
     123              :    Heuristics: Detects anything in assembly that looks like an identifer.
     124              : 
     125              :    This pass must be in WPA, otherwise we will not see all possibly referenced
     126              :    symbols - if a symbol is only declared, it will not be in the callgraph if
     127              :    it is only referenced from toplevel assembly.
     128              :    However in WPA there may be multiple symbols with the same identifier.
     129              :    The chosen solution is to handle local symbols in LGEN pass first.  */
     130              : 
     131              : void
     132           18 : ipa_asm_heuristics ()
     133              : {
     134           18 :   hash_map<nofree_string_hash, symtab_node *> map;
     135           18 :   asm_node *anode = symtab->first_asm_symbol ();
     136           18 :   if (!anode)
     137            3 :     return;
     138              : 
     139           15 :   symtab_node* snode;
     140           15 :   if (flag_wpa)
     141              :     {
     142           39 :       FOR_EACH_SYMBOL (snode)
     143           33 :         if (TREE_PUBLIC (snode->decl))
     144           30 :             map.put (snode->asm_name (), snode);
     145              :     }
     146              :   else
     147              :     {
     148           39 :       FOR_EACH_SYMBOL (snode)
     149           30 :         map.put (snode->asm_name (), snode);
     150              :     }
     151              : 
     152           15 :   auto_vec<char> ident;
     153              : 
     154           51 :   for (; anode; anode = safe_as_a<asm_node*> (anode->next))
     155              :     {
     156           36 :       if (TREE_CODE (anode->asm_str) != STRING_CST)
     157            0 :         continue;
     158              : 
     159           36 :       const char *asm_str = TREE_STRING_POINTER (anode->asm_str);
     160           36 :       int asm_len = TREE_STRING_LENGTH (anode->asm_str);
     161              : 
     162           36 :       if (dump_file)
     163            0 :         fprintf (dump_file, "Searching for symbols in toplevel asm:\n%s\n---\n",
     164              :                  asm_str);
     165              : 
     166          864 :       for (int i = 0; i < asm_len + 1; ++i)
     167              :         {
     168          828 :           char c = 0;
     169          828 :           if (i < asm_len)
     170          792 :             c = asm_str[i];
     171              : 
     172          828 :           if ('0' <= c && c <= '9')
     173              :             {
     174            0 :               if (ident.length ())
     175            0 :                 ident.safe_push (c);
     176              :             }
     177              :           else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_')
     178          660 :             ident.safe_push (c);
     179          906 :           else if (ident.length ())
     180              :             {
     181           78 :               ident.safe_push ('\0');
     182          156 :               symtab_node **n_ = map.get (ident.begin ());
     183              : 
     184           78 :               if (n_)
     185              :                 {
     186           30 :                   bool is_label = c == ':';
     187              : 
     188           30 :                   if (dump_file)
     189            0 :                     fprintf (dump_file, "Found symbol '%s' (is_label: %d)\n",
     190              :                              ident.begin (), is_label);
     191              : 
     192           30 :                   mark_fragile_ref_by_asm (*n_, is_label);
     193              :                 }
     194              : 
     195           78 :               ident.truncate (0);
     196              :             }
     197              :         }
     198              :     }
     199           18 : }
     200              : 
     201              : namespace {
     202              : 
     203              : const pass_data pass_data_ipa_asm =
     204              : {
     205              :   IPA_PASS, /* type */
     206              :   "ipa-asm", /* name */
     207              :   OPTGROUP_NONE, /* optinfo_flags */
     208              :   TV_IPA_LTO_ASM, /* tv_id */
     209              :   0, /* properties_required */
     210              :   0, /* properties_provided */
     211              :   0, /* properties_destroyed */
     212              :   0, /* todo_flags_start */
     213              :   0, /* todo_flags_finish */
     214              : };
     215              : 
     216              : class pass_ipa_asm : public ipa_opt_pass_d
     217              : {
     218              : public:
     219       571444 :   pass_ipa_asm (gcc::context *ctxt)
     220              :     : ipa_opt_pass_d (pass_data_ipa_asm, ctxt,
     221              :                       NULL, /* generate_summary */
     222              :                       NULL, /* write_summary */
     223              :                       NULL, /* read_summary */
     224              :                       NULL, /* write_optimization_summary */
     225              :                       NULL, /* read_optimization_summary */
     226              :                       NULL, /* stmt_fixup */
     227              :                       0, /* function_transform_todo_flags_start */
     228              :                       NULL, /* function_transform */
     229       571444 :                       NULL) /* variable_transform */
     230       571444 :   {}
     231              : 
     232              :   /* opt_pass methods: */
     233              : 
     234       793679 :   bool gate (function *) final override
     235              :     {
     236       793679 :       return (flag_lto || flag_wpa) && flag_toplevel_asm_heuristics;
     237              :     }
     238              : 
     239           18 :   unsigned int execute (function *) final override
     240              :     {
     241           18 :       ipa_asm_heuristics ();
     242           18 :       return 0;
     243              :     }
     244              : 
     245              : };
     246              : 
     247              : } // anon namespace
     248              : 
     249              : ipa_opt_pass_d *
     250       285722 : make_pass_ipa_asm_lgen (gcc::context *ctxt)
     251              : {
     252       285722 :   return new pass_ipa_asm (ctxt);
     253              : }
     254              : 
     255              : ipa_opt_pass_d *
     256       285722 : make_pass_ipa_asm_wpa (gcc::context *ctxt)
     257              : {
     258       285722 :   return new pass_ipa_asm (ctxt);
     259              : }
        

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.