LCOV - code coverage report
Current view: top level - gcc - domwalk.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 98.3 % 120 118
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Generic dominator tree walker
       2              :    Copyright (C) 2003-2026 Free Software Foundation, Inc.
       3              :    Contributed by Diego Novillo <dnovillo@redhat.com>
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify
       8              : it 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,
      13              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15              : GNU 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              : #include "config.h"
      22              : #include "system.h"
      23              : #include "coretypes.h"
      24              : #include "backend.h"
      25              : #include "cfganal.h"
      26              : #include "domwalk.h"
      27              : #include "dumpfile.h"
      28              : 
      29              : /* This file implements a generic walker for dominator trees.
      30              : 
      31              :   To understand the dominator walker one must first have a grasp of dominators,
      32              :   immediate dominators and the dominator tree.
      33              : 
      34              :   Dominators
      35              :     A block B1 is said to dominate B2 if every path from the entry to B2 must
      36              :     pass through B1.  Given the dominance relationship, we can proceed to
      37              :     compute immediate dominators.  Note it is not important whether or not
      38              :     our definition allows a block to dominate itself.
      39              : 
      40              :   Immediate Dominators:
      41              :     Every block in the CFG has no more than one immediate dominator.  The
      42              :     immediate dominator of block BB must dominate BB and must not dominate
      43              :     any other dominator of BB and must not be BB itself.
      44              : 
      45              :   Dominator tree:
      46              :     If we then construct a tree where each node is a basic block and there
      47              :     is an edge from each block's immediate dominator to the block itself, then
      48              :     we have a dominator tree.
      49              : 
      50              : 
      51              :   [ Note this walker can also walk the post-dominator tree, which is
      52              :     defined in a similar manner.  i.e., block B1 is said to post-dominate
      53              :     block B2 if all paths from B2 to the exit block must pass through
      54              :     B1.  ]
      55              : 
      56              :   For example, given the CFG
      57              : 
      58              :                    1
      59              :                    |
      60              :                    2
      61              :                   / \
      62              :                  3   4
      63              :                     / \
      64              :        +---------->5   6
      65              :        |          / \ /
      66              :        |    +--->8   7
      67              :        |    |   /    |
      68              :        |    +--9    11
      69              :        |      /      |
      70              :        +--- 10 ---> 12
      71              : 
      72              : 
      73              :   We have a dominator tree which looks like
      74              : 
      75              :                    1
      76              :                    |
      77              :                    2
      78              :                   / \
      79              :                  /   \
      80              :                 3     4
      81              :                    / / \ \
      82              :                    | | | |
      83              :                    5 6 7 12
      84              :                    |   |
      85              :                    8   11
      86              :                    |
      87              :                    9
      88              :                    |
      89              :                   10
      90              : 
      91              : 
      92              : 
      93              :   The dominator tree is the basis for a number of analysis, transformation
      94              :   and optimization algorithms that operate on a semi-global basis.
      95              : 
      96              :   The dominator walker is a generic routine which visits blocks in the CFG
      97              :   via a depth first search of the dominator tree.  In the example above
      98              :   the dominator walker might visit blocks in the following order
      99              :   1, 2, 3, 4, 5, 8, 9, 10, 6, 7, 11, 12.
     100              : 
     101              :   The dominator walker has a number of callbacks to perform actions
     102              :   during the walk of the dominator tree.  There are two callbacks
     103              :   which walk statements, one before visiting the dominator children,
     104              :   one after visiting the dominator children.  There is a callback
     105              :   before and after each statement walk callback.  In addition, the
     106              :   dominator walker manages allocation/deallocation of data structures
     107              :   which are local to each block visited.
     108              : 
     109              :   The dominator walker is meant to provide a generic means to build a pass
     110              :   which can analyze or transform/optimize a function based on walking
     111              :   the dominator tree.  One simply fills in the dominator walker data
     112              :   structure with the appropriate callbacks and calls the walker.
     113              : 
     114              :   We currently use the dominator walker to prune the set of variables
     115              :   which might need PHI nodes (which can greatly improve compile-time
     116              :   performance in some cases).
     117              : 
     118              :   We also use the dominator walker to rewrite the function into SSA form
     119              :   which reduces code duplication since the rewriting phase is inherently
     120              :   a walk of the dominator tree.
     121              : 
     122              :   And (of course), we use the dominator walker to drive our dominator
     123              :   optimizer, which is a semi-global optimizer.
     124              : 
     125              :   TODO:
     126              : 
     127              :     Walking statements is based on the block statement iterator abstraction,
     128              :     which is currently an abstraction over walking tree statements.  Thus
     129              :     the dominator walker is currently only useful for trees.  */
     130              : 
     131              : static int
     132    155522481 : cmp_bb_postorder (const void *a, const void *b, void *data)
     133              : {
     134    155522481 :   basic_block bb1 = *(const basic_block *)(a);
     135    155522481 :   basic_block bb2 = *(const basic_block *)(b);
     136    155522481 :   int *bb_postorder = (int *)data;
     137              :   /* Place higher completion number first (pop off lower number first).  */
     138    155522481 :   return bb_postorder[bb2->index] - bb_postorder[bb1->index];
     139              : }
     140              : 
     141              : /* Permute array BBS of N basic blocks in postorder,
     142              :    i.e. by descending number in BB_POSTORDER array.  */
     143              : 
     144              : static void
     145     98753184 : sort_bbs_postorder (basic_block *bbs, int n, int *bb_postorder)
     146              : {
     147     98753184 :   if (LIKELY (n == 2))
     148              :     {
     149     74951658 :       basic_block bb0 = bbs[0], bb1 = bbs[1];
     150     74951658 :       if (bb_postorder[bb0->index] < bb_postorder[bb1->index])
     151     33109373 :         bbs[0] = bb1, bbs[1] = bb0;
     152              :     }
     153     23801526 :   else if (LIKELY (n == 3))
     154              :     {
     155     20202540 :       basic_block bb0 = bbs[0], bb1 = bbs[1], bb2 = bbs[2];
     156     20202540 :       if (bb_postorder[bb0->index] < bb_postorder[bb1->index])
     157      3483855 :         std::swap (bb0, bb1);
     158     20202540 :       if (bb_postorder[bb1->index] < bb_postorder[bb2->index])
     159              :         {
     160     13988212 :           std::swap (bb1, bb2);
     161     13988212 :           if (bb_postorder[bb0->index] < bb_postorder[bb1->index])
     162      1285762 :             std::swap (bb0, bb1);
     163              :         }
     164     20202540 :       bbs[0] = bb0, bbs[1] = bb1, bbs[2] = bb2;
     165              :     }
     166              :   else
     167      3598986 :     gcc_sort_r (bbs, n, sizeof *bbs, cmp_bb_postorder, bb_postorder);
     168     98753184 : }
     169              : 
     170              : /* Set EDGE_EXECUTABLE on every edge within FN's CFG.  */
     171              : 
     172              : void
     173      6650026 : set_all_edges_as_executable (function *fn)
     174              : {
     175      6650026 :   basic_block bb;
     176     77458032 :   FOR_ALL_BB_FN (bb, fn)
     177              :     {
     178     70808006 :       edge_iterator ei;
     179     70808006 :       edge e;
     180    158068546 :       FOR_EACH_EDGE (e, ei, bb->succs)
     181     87260540 :         e->flags |= EDGE_EXECUTABLE;
     182              :     }
     183      6650026 : }
     184              : 
     185              : /* Constructor for a dom walker.  */
     186              : 
     187     47640790 : dom_walker::dom_walker (cdi_direction direction,
     188              :                         enum reachability reachability,
     189     47640790 :                         int *bb_index_to_rpo)
     190     47640790 :   : m_dom_direction (direction),
     191     47640790 :     m_reachability (reachability),
     192     47640790 :     m_user_bb_to_rpo (bb_index_to_rpo != NULL),
     193     47640790 :     m_unreachable_dom (NULL),
     194     47640790 :     m_bb_to_rpo (bb_index_to_rpo == (int *)(uintptr_t)-1
     195     47640790 :                  ? NULL : bb_index_to_rpo)
     196              : {
     197     47640790 : }
     198              : 
     199              : /* Destructor.  */
     200              : 
     201     47640790 : dom_walker::~dom_walker ()
     202              : {
     203     47640790 :   if (! m_user_bb_to_rpo)
     204     37939456 :     free (m_bb_to_rpo);
     205     47640790 : }
     206              : 
     207              : /* Return TRUE if BB is reachable, false otherwise.  */
     208              : 
     209              : bool
     210    963326068 : dom_walker::bb_reachable (struct function *fun, basic_block bb)
     211              : {
     212              :   /* If we're not skipping unreachable blocks, then assume everything
     213              :      is reachable.  */
     214    963326068 :   if (m_reachability == ALL_BLOCKS)
     215              :     return true;
     216              : 
     217              :   /* If any of the predecessor edges that do not come from blocks dominated
     218              :      by us are still marked as possibly executable consider this block
     219              :      reachable.  */
     220     49150848 :   bool reachable = false;
     221     49150848 :   if (!m_unreachable_dom)
     222              :     {
     223     49078442 :       reachable = bb == ENTRY_BLOCK_PTR_FOR_FN (fun);
     224     49078442 :       edge_iterator ei;
     225     49078442 :       edge e;
     226    112311989 :       FOR_EACH_EDGE (e, ei, bb->preds)
     227     63233547 :         if (!dominated_by_p (CDI_DOMINATORS, e->src, bb))
     228     60452743 :           reachable |= (e->flags & EDGE_EXECUTABLE);
     229              :     }
     230              : 
     231              :   return reachable;
     232              : }
     233              : 
     234              : /* BB has been determined to be unreachable.  Propagate that property
     235              :    to incoming and outgoing edges of BB as appropriate.  */
     236              : 
     237              : void
     238        58251 : dom_walker::propagate_unreachable_to_edges (basic_block bb,
     239              :                                             FILE *dump_file,
     240              :                                             dump_flags_t dump_flags)
     241              : {
     242        58251 :   if (dump_file && (dump_flags & TDF_DETAILS))
     243           13 :     fprintf (dump_file, "Marking all outgoing edges of unreachable "
     244              :              "BB %d as not executable\n", bb->index);
     245              : 
     246        58251 :   edge_iterator ei;
     247        58251 :   edge e;
     248       101156 :   FOR_EACH_EDGE (e, ei, bb->succs)
     249        42905 :     e->flags &= ~EDGE_EXECUTABLE;
     250              : 
     251       127029 :   FOR_EACH_EDGE (e, ei, bb->preds)
     252              :     {
     253        68778 :       if (dominated_by_p (CDI_DOMINATORS, e->src, bb))
     254              :         {
     255          564 :           if (dump_file && (dump_flags & TDF_DETAILS))
     256            0 :             fprintf (dump_file, "Marking backedge from BB %d into "
     257              :                      "unreachable BB %d as not executable\n",
     258            0 :                      e->src->index, bb->index);
     259          564 :           e->flags &= ~EDGE_EXECUTABLE;
     260              :         }
     261              :     }
     262              : 
     263        58251 :   if (!m_unreachable_dom)
     264        44096 :     m_unreachable_dom = bb;
     265        58251 : }
     266              : 
     267              : const edge dom_walker::STOP = (edge)-1;
     268              : 
     269              : /* Recursively walk the dominator tree.
     270              :    BB is the basic block we are currently visiting.  */
     271              : 
     272              : void
     273     41520409 : dom_walker::walk (basic_block bb)
     274              : {
     275              :   /* Compute the basic-block index to RPO mapping lazily.  */
     276     41520409 :   if (!m_user_bb_to_rpo
     277     31819075 :       && !m_bb_to_rpo
     278     31819075 :       && m_dom_direction == CDI_DOMINATORS)
     279              :     {
     280     31819075 :       int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
     281     31819075 :       int postorder_num = pre_and_rev_post_order_compute (NULL, postorder,
     282              :                                                           true);
     283     31819075 :       m_bb_to_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun));
     284    371279861 :       for (int i = 0; i < postorder_num; ++i)
     285    339460786 :         m_bb_to_rpo[postorder[i]] = i;
     286     31819075 :       free (postorder);
     287              :     }
     288              : 
     289              :   /* Set up edge flags if need be.  */
     290     41520409 :   if (m_reachability == REACHABLE_BLOCKS)
     291      2192413 :     set_all_edges_as_executable (cfun);
     292              : 
     293     41520409 :   basic_block dest;
     294     41520409 :   basic_block *worklist = XNEWVEC (basic_block,
     295              :                                    n_basic_blocks_for_fn (cfun) * 2);
     296     41520409 :   int sp = 0;
     297              : 
     298    921805659 :   while (true)
     299              :     {
     300              :       /* Don't worry about unreachable blocks.  */
     301    481663034 :       if (EDGE_COUNT (bb->preds) > 0
     302     40155936 :           || bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)
     303    441507098 :           || bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
     304              :         {
     305    481663034 :           edge taken_edge = NULL;
     306              : 
     307              :           /* Callback for subclasses to do custom things before we have walked
     308              :              the dominator children, but before we walk statements.  */
     309    481663034 :           if (this->bb_reachable (cfun, bb))
     310              :             {
     311    481604783 :               taken_edge = before_dom_children (bb);
     312    481604783 :               if (taken_edge && taken_edge != STOP)
     313              :                 {
     314       704598 :                   edge_iterator ei;
     315       704598 :                   edge e;
     316      1572951 :                   FOR_EACH_EDGE (e, ei, bb->succs)
     317       868353 :                     if (e != taken_edge)
     318       163755 :                       e->flags &= ~EDGE_EXECUTABLE;
     319              :                 }
     320              :             }
     321              :           else
     322        58251 :             propagate_unreachable_to_edges (bb, dump_file, dump_flags);
     323              : 
     324              :           /* Mark the current BB to be popped out of the recursion stack
     325              :              once children are processed.  */
     326    481663034 :           worklist[sp++] = bb;
     327    481663034 :           worklist[sp++] = NULL;
     328              : 
     329              :           /* If the callback returned NONE then we are supposed to
     330              :              stop and not even propagate EDGE_EXECUTABLE further.  */
     331    481663034 :           if (taken_edge != STOP)
     332              :             {
     333    480498614 :               int saved_sp = sp;
     334    480498614 :               for (dest = first_dom_son (m_dom_direction, bb);
     335    920641239 :                    dest; dest = next_dom_son (m_dom_direction, dest))
     336    440142625 :                 worklist[sp++] = dest;
     337              :               /* Sort worklist after RPO order if requested.  */
     338    480498614 :               if (sp - saved_sp > 1
     339    127064730 :                   && m_dom_direction == CDI_DOMINATORS
     340    127064730 :                   && m_bb_to_rpo)
     341     98753184 :                 sort_bbs_postorder (&worklist[saved_sp], sp - saved_sp,
     342              :                                     m_bb_to_rpo);
     343              :             }
     344              :         }
     345              :       /* NULL is used to mark pop operations in the recursion stack.  */
     346    963326068 :       while (sp > 0 && !worklist[sp - 1])
     347              :         {
     348    481663034 :           --sp;
     349    481663034 :           bb = worklist[--sp];
     350              : 
     351              :           /* Callback allowing subclasses to do custom things after we have
     352              :              walked dominator children, but before we walk statements.  */
     353    481663034 :           if (bb_reachable (cfun, bb))
     354    481604783 :             after_dom_children (bb);
     355        58251 :           else if (m_unreachable_dom == bb)
     356        44096 :             m_unreachable_dom = NULL;
     357              :         }
     358    481663034 :       if (sp)
     359    440142625 :         bb = worklist[--sp];
     360              :       else
     361              :         break;
     362    440142625 :     }
     363     41520409 :   free (worklist);
     364     41520409 : }
        

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.