LCOV - code coverage report
Current view: top level - gcc/analyzer - supergraph-sorting.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 100.0 % 98 98
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Sorting the nodes in the supergraph.
       2              :    Copyright (C) 2025-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License 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              : #define INCLUDE_SET
      22              : #include "analyzer/common.h"
      23              : 
      24              : #include "cgraph.h"
      25              : #include "alloc-pool.h"
      26              : #include "fibonacci_heap.h"
      27              : #include "timevar.h"
      28              : 
      29              : #include "analyzer/supergraph.h"
      30              : #include "analyzer/analyzer-logging.h"
      31              : 
      32              : #if ENABLE_ANALYZER
      33              : 
      34              : namespace ana {
      35              : 
      36              : /* Update m_nodes to be ORDERING.
      37              :    Update the m_id of all nodes to reflect the new orderding.
      38              :    This assumes that all nodes are in ORDERING; does not delete
      39              :    any underlying nodes.  */
      40              : 
      41              : void
      42         3377 : supergraph::reorder_nodes_and_ids (const std::vector<supernode *> &ordering,
      43              :                                    logger *logger)
      44              : {
      45         3377 :   LOG_SCOPE (logger);
      46              : 
      47         3377 :   m_nodes.truncate (0);
      48              : 
      49       185466 :   for (size_t new_id = 0; new_id < ordering.size (); ++new_id)
      50              :     {
      51       182089 :       supernode *snode = ordering[new_id];
      52       182089 :       if (logger)
      53              :         {
      54           80 :           if ((size_t)snode->m_id == new_id)
      55           49 :             logger->log ("SN %i is unchanged", snode->m_id);
      56              :           else
      57           31 :             logger->log ("old SN %i is now SN %li", snode->m_id, new_id);
      58              :         }
      59       182089 :       m_nodes.safe_push (snode);
      60       182089 :       snode->m_id = new_id;
      61              :     }
      62              : 
      63         3377 :   m_next_snode_id = m_nodes.length ();
      64         3377 : }
      65              : 
      66              : /* std::set::contains is C++20 onwards.  */
      67              : template <typename T>
      68              : static bool
      69       658495 : set_contains_p (const std::set<T> &s, T v)
      70              : {
      71       658495 :   return s.find (v) != s.end ();
      72              : }
      73              : 
      74              : namespace {
      75              : 
      76              : class sorting_worklist
      77              : {
      78              : public:
      79        10201 :   sorting_worklist ()
      80        10201 :   : m_queue (key_t (nullptr))
      81              :   {
      82        10201 :   }
      83              : 
      84              :   void add_node (supernode *n);
      85              :   supernode *take_next (logger *logger);
      86              :   bool contains_p (supernode *n) const;
      87              : 
      88              : private:
      89              :   class key_t
      90              :   {
      91              :   public:
      92       205024 :     key_t (supernode *snode)
      93        10201 :     : m_snode (snode)
      94              :     {}
      95              : 
      96       135989 :     bool operator< (const key_t &other) const
      97              :     {
      98       135989 :       return cmp (*this, other) < 0;
      99              :     }
     100              : 
     101        33010 :     bool operator== (const key_t &other) const
     102              :     {
     103        33010 :       return cmp (*this, other) == 0;
     104              :     }
     105              : 
     106        33010 :     bool operator> (const key_t &other) const
     107              :     {
     108        33010 :       return !(*this == other || *this < other);
     109              :     }
     110              : 
     111              :   private:
     112              :     static int cmp (const key_t &ka, const key_t &kb);
     113              :     supernode *m_snode;
     114              :   };
     115              : 
     116              :   bool
     117              :   already_seen_all_predecessors_p (const supernode *n,
     118              :                                    logger *logger) const;
     119              : 
     120              :   std::set<supernode *> m_set_of_ordered_nodes;
     121              :   std::set<supernode *> m_set_of_queued_nodes;
     122              :   typedef fibonacci_heap<key_t, supernode> queue_t;
     123              :   queue_t m_queue;
     124              : };
     125              : 
     126              : void
     127       194823 : sorting_worklist::add_node (supernode *n)
     128              : {
     129       194823 :   m_queue.insert ({n}, n);
     130       194823 :   m_set_of_queued_nodes.insert (n);
     131       194823 : }
     132              : 
     133              : supernode *
     134       192290 : sorting_worklist::take_next (logger *logger)
     135              : {
     136       192290 :   if (m_queue.empty ())
     137              :     return nullptr;
     138              : 
     139       182089 :   std::vector<supernode *> rejected;
     140              : 
     141              :   /* First, try to find a node for which all predecessors
     142              :      have been ordered.  */
     143       194823 :   while (!m_queue.empty ())
     144              :     {
     145       193295 :       supernode *candidate = m_queue.extract_min ();
     146              : 
     147              :       // n shouldn't be already within the ordering
     148       193295 :       gcc_assert (!set_contains_p (m_set_of_ordered_nodes, candidate));
     149              : 
     150       193295 :       if (logger)
     151           85 :         logger->log ("consider SN %i from worklist", candidate->m_id);
     152              : 
     153       193295 :       if (already_seen_all_predecessors_p (candidate, logger))
     154              :         {
     155       180561 :           if (logger)
     156           76 :             logger->log ("all predecessors of SN %i seen; using it",
     157              :                          candidate->m_id);
     158       191291 :           for (auto r : rejected)
     159        10730 :             add_node (r);
     160       180561 :           m_set_of_ordered_nodes.insert (candidate);
     161       180561 :           m_set_of_queued_nodes.erase (candidate);
     162       180561 :           return candidate;
     163              :         }
     164              :       else
     165        12734 :         rejected.push_back (candidate);
     166              :     }
     167              : 
     168              :   /* Otherwise, simply use the first node.  */
     169         3532 :   for (auto r : rejected)
     170         2004 :     add_node (r);
     171         1528 :   supernode *n = m_queue.extract_min ();
     172         1528 :   if (logger)
     173            4 :     logger->log ("using first in queue: SN %i", n->m_id);
     174         1528 :   m_set_of_ordered_nodes.insert (n);
     175         1528 :   m_set_of_queued_nodes.erase (n);
     176         1528 :   return n;
     177       182089 : }
     178              : 
     179              : bool
     180       181929 : sorting_worklist::contains_p (supernode *n) const
     181              : {
     182       181929 :   return (m_set_of_queued_nodes.find (n) != m_set_of_queued_nodes.end ()
     183       181929 :           || m_set_of_ordered_nodes.find (n) != m_set_of_ordered_nodes.end ());
     184              : }
     185              : 
     186              : int
     187       168999 : sorting_worklist::key_t::cmp (const key_t &ka, const key_t &kb)
     188              : {
     189       168999 :   const supernode *snode_a = ka.m_snode;
     190       168999 :   const supernode *snode_b = kb.m_snode;
     191              : 
     192              :   /* Sort by BB.  */
     193       168999 :   if (int bb_cmp = snode_a->m_bb->index - snode_b->m_bb->index)
     194              :     return bb_cmp;
     195              : 
     196              :   /* Sort by existing id.  */
     197        44008 :   return snode_a->m_id - snode_b->m_id;
     198              : }
     199              : 
     200              : bool
     201       193295 : sorting_worklist::already_seen_all_predecessors_p (const supernode *n,
     202              :                                                    logger *logger) const
     203              : {
     204      1011949 :   for (auto e : n->m_preds)
     205       465200 :     if (!set_contains_p (m_set_of_ordered_nodes, e->m_src))
     206              :       {
     207        12734 :         if (logger)
     208            9 :           logger->log ("not yet ordered predecessor SN %i", e->m_src->m_id);
     209        12734 :         return false;
     210              :       }
     211              :   return true;
     212              : }
     213              : 
     214              : static std::vector<supernode *>
     215         3377 : get_node_ordering (const supergraph &sg,
     216              :                    logger *logger)
     217              : {
     218         3377 :   LOG_SCOPE (logger);
     219              : 
     220         3377 :   std::vector<supernode *> ordering_vec;
     221              : 
     222         3377 :   cgraph_node *cgnode;
     223        13578 :   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
     224              :     {
     225        10201 :       function *fun = cgnode->get_fun ();
     226              : 
     227        10201 :       sorting_worklist worklist;
     228              : 
     229        10201 :       supernode *start_node = sg.get_node_for_function_entry (*fun);
     230        10201 :       worklist.add_node (start_node);
     231              : 
     232              :       // Find the best node to add next in the ordering
     233       192290 :       while (supernode *next = worklist.take_next (logger))
     234              :         {
     235       182089 :           gcc_assert (next);
     236       182089 :           if (logger)
     237           80 :             logger->log ("next: SN: %i", next->m_id);
     238              : 
     239       182089 :           ordering_vec.push_back (next);
     240              : 
     241       706094 :           for (auto out_edge : next->m_succs)
     242              :             {
     243       181929 :               supernode *dest_node = out_edge->m_dest;
     244       181929 :               if (!worklist.contains_p (dest_node))
     245       171888 :                 worklist.add_node (dest_node);
     246              :             }
     247       182089 :         }
     248        10201 :     }
     249              : 
     250         6754 :   return ordering_vec;
     251         3377 : }
     252              : 
     253              : } // anonymous namespace
     254              : 
     255              : void
     256         3377 : supergraph::sort_nodes (logger *logger)
     257              : {
     258         3377 :   auto_timevar tv (TV_ANALYZER_SUPERGRAPH_SORTING);
     259         3377 :   LOG_SCOPE (logger);
     260              : 
     261         3377 :   const std::vector<supernode *> ordering = get_node_ordering (*this, logger);
     262         3377 :   reorder_nodes_and_ids (ordering, logger);
     263         3377 : }
     264              : 
     265              : } // namespace ana
     266              : 
     267              : #endif /* #if ENABLE_ANALYZER */
        

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.