LCOV - code coverage report
Current view: top level - gcc - gimple-range-edge.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.9 % 97 93
Test Date: 2026-02-28 14:20:25 Functions: 77.8 % 9 7
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Gimple range edge functionality.
       2              :    Copyright (C) 2020-2026 Free Software Foundation, Inc.
       3              :    Contributed by Andrew MacLeod <amacleod@redhat.com>
       4              :    and Aldy Hernandez <aldyh@redhat.com>.
       5              : 
       6              : This file is part of GCC.
       7              : 
       8              : GCC is free software; you can redistribute it and/or modify
       9              : it under the terms of the GNU General Public License as published by
      10              : the Free Software Foundation; either version 3, or (at your option)
      11              : any later version.
      12              : 
      13              : GCC is distributed in the hope that it will be useful,
      14              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16              : GNU General Public License for more details.
      17              : 
      18              : You should have received a copy of the GNU General Public License
      19              : along with GCC; see the file COPYING3.  If not see
      20              : <http://www.gnu.org/licenses/>.  */
      21              : 
      22              : 
      23              : #include "config.h"
      24              : #include "system.h"
      25              : #include "coretypes.h"
      26              : #include "backend.h"
      27              : #include "tree.h"
      28              : #include "gimple.h"
      29              : #include "ssa.h"
      30              : #include "gimple-pretty-print.h"
      31              : #include "gimple-iterator.h"
      32              : #include "tree-cfg.h"
      33              : #include "gimple-range.h"
      34              : #include "value-range-storage.h"
      35              : #include "rtl.h"
      36              : 
      37              : // If there is a range control statement at the end of block BB, return it.
      38              : // Otherwise return NULL.
      39              : 
      40              : gimple *
      41    273649479 : gimple_outgoing_range_stmt_p (basic_block bb)
      42              : {
      43    273649479 :   if (bb->flags & BB_RTL)
      44              :     return NULL;
      45    272177338 :   gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
      46    272177338 :   if (!gsi_end_p (gsi))
      47              :     {
      48    245768423 :       gimple *s = gsi_stmt (gsi);
      49    245768423 :       if (is_a<gcond *> (s) && gimple_range_op_handler::supported_p (s))
      50              :         return gsi_stmt (gsi);
      51     37837833 :       if (is_a <gswitch *> (s))
      52              :         return gsi_stmt (gsi);
      53              :     }
      54              :   return NULL;
      55              : }
      56              : 
      57              : // Return a TRUE or FALSE range representing the edge value of a GCOND.
      58              : 
      59              : void
      60    244905357 : gcond_edge_range (irange &r, edge e)
      61              : {
      62    244905357 :   gcc_checking_assert (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE));
      63    244905357 :   if (e->flags & EDGE_TRUE_VALUE)
      64    121264689 :     r = range_true ();
      65              :   else
      66    123640668 :     r = range_false ();
      67    244905357 : }
      68              : 
      69              : // Construct a gimple_outgoing_range object.  No memory is allocated.
      70              : 
      71     28165641 : gimple_outgoing_range::gimple_outgoing_range (int max_sw_edges)
      72              : {
      73     28165641 :   m_edge_table = NULL;
      74     28165641 :   m_range_allocator = NULL;
      75     28165641 :   m_max_edges = max_sw_edges;
      76     28165641 : }
      77              : 
      78              : // Destruct an edge object, disposing of any memory allocated.
      79              : 
      80     28165640 : gimple_outgoing_range::~gimple_outgoing_range ()
      81              : {
      82     28165640 :   if (m_edge_table)
      83        58078 :     delete m_edge_table;
      84     28165640 :   if (m_range_allocator)
      85        58078 :     delete m_range_allocator;
      86     28165640 : }
      87              : 
      88              : // Set a new switch limit.
      89              : 
      90              : void
      91            0 : gimple_outgoing_range::set_switch_limit (int max_sw_edges)
      92              : {
      93            0 :   m_max_edges = max_sw_edges;
      94            0 : }
      95              : 
      96              : // Get a range for a switch edge E from statement S and return it in R.
      97              : // Use a cached value if it exists, or calculate it if not.
      98              : 
      99              : bool
     100       482417 : gimple_outgoing_range::switch_edge_range (irange &r, gswitch *sw, edge e)
     101              : {
     102              :   // ADA currently has cases where the index is 64 bits and the case
     103              :   // arguments are 32 bit, causing a trap when we create a case_range.
     104              :   // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798)
     105              :   // punt on switches where the labels don't match the argument.
     106       482417 :   if (gimple_switch_num_labels (sw) > 1 &&
     107       482417 :       TYPE_PRECISION (TREE_TYPE (CASE_LOW (gimple_switch_label (sw, 1)))) !=
     108       482417 :       TYPE_PRECISION (TREE_TYPE (gimple_switch_index (sw))))
     109              :     return false;
     110              : 
     111       482398 :   if (!m_edge_table)
     112        58078 :     m_edge_table = new hash_map<edge, vrange_storage *> (n_edges_for_fn (cfun));
     113       482398 :   if (!m_range_allocator)
     114        58078 :     m_range_allocator = new vrange_allocator;
     115              : 
     116       482398 :    vrange_storage **val = m_edge_table->get (e);
     117       482398 :    if (!val)
     118              :      {
     119        73863 :        calc_switch_ranges (sw);
     120        73863 :        val = m_edge_table->get (e);
     121        73863 :        gcc_checking_assert (val);
     122              :      }
     123       482398 :    (*val)->get_vrange (r, TREE_TYPE (gimple_switch_index (sw)));
     124       482398 :   return true;
     125              : }
     126              : 
     127              : 
     128              : // Calculate all switch edges from SW and cache them in the hash table.
     129              : 
     130              : void
     131        73863 : gimple_outgoing_range::calc_switch_ranges (gswitch *sw)
     132              : {
     133        73863 :   bool existed;
     134        73863 :   unsigned x, lim;
     135        73863 :   lim = gimple_switch_num_labels (sw);
     136        73863 :   tree type = TREE_TYPE (gimple_switch_index (sw));
     137        73863 :   edge default_edge = gimple_switch_default_edge (cfun, sw);
     138              : 
     139              :   // This should be the first call into this switch.
     140              :   //
     141              :   // Allocate an int_range_max for the default range case, start with
     142              :   // varying and intersect each other case from it.
     143        73863 :   int_range_max default_range (type);
     144              : 
     145       509299 :   for (x = 1; x < lim; x++)
     146              :     {
     147       435436 :       edge e = gimple_switch_edge (cfun, sw, x);
     148              : 
     149              :       // If this edge is the same as the default edge, do nothing else.
     150       435436 :       if (e == default_edge)
     151          143 :         continue;
     152              : 
     153       435311 :       wide_int low = wi::to_wide (CASE_LOW (gimple_switch_label (sw, x)));
     154       435311 :       wide_int high;
     155       435311 :       tree tree_high = CASE_HIGH (gimple_switch_label (sw, x));
     156       435311 :       if (tree_high)
     157        38282 :         high = wi::to_wide (tree_high);
     158              :       else
     159       397029 :         high = low;
     160              : 
     161              :       // Remove the case range from the default case.
     162       435311 :       int_range_max def_range (type, low, high);
     163       435311 :       range_cast (def_range, type);
     164              :       // If all possible values are taken, set default_range to UNDEFINED.
     165       435311 :       if (def_range.varying_p ())
     166            1 :         default_range.set_undefined ();
     167              :       else
     168              :         {
     169       435310 :           def_range.invert ();
     170       435310 :           default_range.intersect (def_range);
     171              :         }
     172              : 
     173              :       // Create/union this case with anything on else on the edge.
     174       435311 :       int_range_max case_range (type, low, high);
     175       435311 :       range_cast (case_range, type);
     176       435311 :       vrange_storage *&slot = m_edge_table->get_or_insert (e, &existed);
     177       435311 :       if (existed)
     178              :         {
     179              :           // If this doesn't change the value, move on.
     180        80963 :           int_range_max tmp;
     181        80963 :           slot->get_vrange (tmp, type);
     182        80963 :           if (!case_range.union_ (tmp))
     183            0 :            continue;
     184        80963 :           if (slot->fits_p (case_range))
     185              :             {
     186           18 :               slot->set_vrange (case_range);
     187           18 :               continue;
     188              :             }
     189        80963 :         }
     190              :       // If there was an existing range and it doesn't fit, we lose the memory.
     191              :       // It'll get reclaimed when the obstack is freed.  This seems less
     192              :       // intrusive than allocating max ranges for each case.
     193       435293 :       slot = m_range_allocator->clone (case_range);
     194       435311 :     }
     195              : 
     196        73863 :   if (default_edge == NULL)
     197              :     {
     198              :       /* During expansion the default edge could have been removed
     199              :          if the default is unreachable.  */
     200         1326 :       gcc_assert (currently_expanding_to_rtl);
     201         1326 :       return;
     202              :     }
     203              : 
     204        72537 :   vrange_storage *&slot = m_edge_table->get_or_insert (default_edge, &existed);
     205              :   // This should be the first call into this switch.
     206        72537 :   gcc_checking_assert (!existed);
     207        72537 :   slot = m_range_allocator->clone (default_range);
     208        73863 : }
     209              : 
     210              : 
     211              : // Calculate the range forced on on edge E by control flow, return it
     212              : // in R.  Return the statement which defines the range, otherwise
     213              : // return NULL
     214              : 
     215              : gimple *
     216    161834627 : gimple_outgoing_range::edge_range_p (irange &r, edge e)
     217              : {
     218    161834627 :   if (single_succ_p (e->src))
     219              :     return NULL;
     220              : 
     221              :   // Determine if there is an outgoing edge.
     222    110909216 :   gimple *s = gimple_outgoing_range_stmt_p (e->src);
     223    110909216 :   if (!s)
     224              :     return NULL;
     225              : 
     226    109903732 :   if (is_a<gcond *> (s))
     227              :     {
     228    109420938 :       gcond_edge_range (r, e);
     229    109420938 :       return s;
     230              :     }
     231              : 
     232              :   // Only process switches if it within the size limit.
     233       482794 :   if (m_max_edges == 0 || (EDGE_COUNT (e->src->succs) > (unsigned)m_max_edges))
     234              :     return NULL;
     235              : 
     236       482417 :   gcc_checking_assert (is_a<gswitch *> (s));
     237       482417 :   gswitch *sw = as_a<gswitch *> (s);
     238              : 
     239              :   // Switches can only be integers.
     240       482417 :   if (switch_edge_range (as_a <irange> (r), sw, e))
     241              :     return s;
     242              : 
     243              :   return NULL;
     244              : }
        

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.