LCOV - code coverage report
Current view: top level - gcc - gimple-ssa-isolate-paths.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 96.2 % 372 358
Test Date: 2026-08-22 16:33:35 Functions: 94.7 % 19 18
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Detect paths through the CFG which can never be executed in a conforming
       2              :    program and isolate them.
       3              : 
       4              :    Copyright (C) 2013-2026 Free Software Foundation, Inc.
       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              : #include "config.h"
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "backend.h"
      26              : #include "tree.h"
      27              : #include "gimple.h"
      28              : #include "cfghooks.h"
      29              : #include "tree-pass.h"
      30              : #include "ssa.h"
      31              : #include "diagnostic-core.h"
      32              : #include "fold-const.h"
      33              : #include "gimple-iterator.h"
      34              : #include "gimple-walk.h"
      35              : #include "tree-ssa.h"
      36              : #include "cfgloop.h"
      37              : #include "tree-cfg.h"
      38              : #include "cfganal.h"
      39              : #include "intl.h"
      40              : 
      41              : 
      42              : static bool cfg_altered;
      43              : 
      44              : /* Callback for walk_stmt_load_store_ops.
      45              : 
      46              :    Return TRUE if OP will dereference the tree stored in DATA, FALSE
      47              :    otherwise.
      48              : 
      49              :    This routine only makes a superficial check for a dereference.  Thus,
      50              :    it must only be used if it is safe to return a false negative.  */
      51              : static bool
      52         3101 : check_loadstore (gimple *stmt, tree op, tree, void *data)
      53              : {
      54         6202 :   if ((TREE_CODE (op) == MEM_REF
      55           47 :        || (TREE_CODE (op) == TARGET_MEM_REF
      56            0 :            && !TMR_INDEX2 (op)
      57            0 :            && (!TMR_INDEX (op)
      58            0 :                || (TMR_STEP (op)
      59            0 :                    && expr_not_equal_to (TMR_STEP (op),
      60         3101 :                                          wi::one (TYPE_PRECISION (TREE_TYPE
      61              :                                                         (TMR_STEP (op)))),
      62              :                                          stmt)))))
      63         3101 :       && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
      64              :     {
      65         2989 :       TREE_THIS_VOLATILE (op) = 1;
      66         2989 :       TREE_SIDE_EFFECTS (op) = 1;
      67         2989 :       gimple_set_has_volatile_ops (stmt, true);
      68              :       return true;
      69              :     }
      70              :   return false;
      71              : }
      72              : 
      73              : static vec<gimple *> *bb_split_points;
      74              : 
      75              : /* Insert a trap after SI and split the block after the trap.  */
      76              : 
      77              : static void
      78         2493 : insert_trap (gimple_stmt_iterator *si_p, tree op)
      79              : {
      80              :   /* We want the NULL pointer dereference to actually occur so that
      81              :      code that wishes to catch the signal can do so.
      82              : 
      83              :      If the dereference is a load, then there's nothing to do as the
      84              :      LHS will be a throw-away SSA_NAME and the RHS is the NULL dereference.
      85              : 
      86              :      If the dereference is a store and we can easily transform the RHS,
      87              :      then simplify the RHS to enable more DCE.   Note that we require the
      88              :      statement to be a GIMPLE_ASSIGN which filters out calls on the RHS.  */
      89         2493 :   gimple *stmt = gsi_stmt (*si_p);
      90         2493 :   if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
      91          802 :       && is_gimple_assign (stmt)
      92         3292 :       && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
      93              :     {
      94              :       /* We just need to turn the RHS into zero converted to the proper
      95              :          type.  */
      96          515 :       tree type = TREE_TYPE (gimple_assign_lhs (stmt));
      97          515 :       gimple_assign_set_rhs_code (stmt, INTEGER_CST);
      98          515 :       gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
      99          515 :       update_stmt (stmt);
     100              :     }
     101              : 
     102         2493 :   gcall *new_stmt
     103         2493 :     = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
     104         2493 :   gimple_seq seq = NULL;
     105         2493 :   gimple_seq_add_stmt (&seq, new_stmt);
     106              : 
     107              :   /* If we had a NULL pointer dereference, then we want to insert the
     108              :      __builtin_trap after the statement, for the other cases we want
     109              :      to insert before the statement.  */
     110         2493 :   if (walk_stmt_load_store_ops (stmt, (void *)op,
     111              :                                 check_loadstore,
     112              :                                 check_loadstore))
     113              :     {
     114         2187 :       gsi_insert_after (si_p, seq, GSI_NEW_STMT);
     115         2187 :       if (stmt_ends_bb_p (stmt))
     116              :         {
     117            1 :           if (dom_info_available_p (CDI_POST_DOMINATORS))
     118            0 :             bb_split_points->safe_push (stmt);
     119              :           else
     120            1 :             split_block (gimple_bb (stmt), stmt);
     121            1 :           return;
     122              :         }
     123              :     }
     124              :   else
     125          306 :     gsi_insert_before (si_p, seq, GSI_NEW_STMT);
     126              : 
     127         2492 :   if (dom_info_available_p (CDI_POST_DOMINATORS))
     128            1 :     bb_split_points->safe_push (new_stmt);
     129              :   else
     130         2491 :     split_block (gimple_bb (new_stmt), new_stmt);
     131         2492 :   *si_p = gsi_for_stmt (stmt);
     132              : }
     133              : 
     134              : /* BB when reached via incoming edge E will exhibit undefined behavior
     135              :    at STMT.  Isolate and optimize the path which exhibits undefined
     136              :    behavior.
     137              : 
     138              :    Isolation is simple.  Duplicate BB and redirect E to BB'.
     139              : 
     140              :    Optimization is simple as well.  Replace STMT in BB' with an
     141              :    unconditional trap and remove all outgoing edges from BB'.
     142              : 
     143              :    If RET_ZERO, do not trap, only return NULL.
     144              : 
     145              :    DUPLICATE is a pre-existing duplicate, use it as BB' if it exists.
     146              : 
     147              :    Return BB' (which may be equal to DUPLICATE).  */
     148              : 
     149              : ATTRIBUTE_RETURNS_NONNULL basic_block
     150         1483 : isolate_path (basic_block bb, basic_block duplicate,
     151              :               edge e, gimple *stmt, tree op, bool ret_zero)
     152              : {
     153         1483 :   gimple_stmt_iterator si, si2;
     154         1483 :   edge_iterator ei;
     155         1483 :   edge e2;
     156         1483 :   bool impossible = true;
     157         1483 :   profile_count count = e->count ();
     158              : 
     159        22824 :   for (si = gsi_start_bb (bb); gsi_stmt (si) != stmt; gsi_next (&si))
     160        20077 :     if (stmt_can_terminate_bb_p (gsi_stmt (si)))
     161              :       {
     162              :         impossible = false;
     163              :         break;
     164              :       }
     165         1483 :   force_edge_cold (e, impossible);
     166              : 
     167              :   /* First duplicate BB if we have not done so already and remove all
     168              :      the duplicate's outgoing edges as duplicate is going to unconditionally
     169              :      trap.  Removing the outgoing edges is both an optimization and ensures
     170              :      we don't need to do any PHI node updates.  */
     171         1483 :   if (!duplicate)
     172              :     {
     173          899 :       duplicate = duplicate_block (bb, NULL, NULL);
     174          899 :       duplicate->count = profile_count::zero ();
     175          899 :       if (!ret_zero)
     176         2166 :         for (ei = ei_start (duplicate->succs); (e2 = ei_safe_edge (ei)); )
     177         1331 :           remove_edge (e2);
     178              :     }
     179         1483 :   bb->count -= count;
     180              : 
     181              :   /* Complete the isolation step by redirecting E to reach DUPLICATE.  */
     182         1483 :   e2 = redirect_edge_and_branch (e, duplicate);
     183         1483 :   if (e2)
     184              :     {
     185         1045 :       flush_pending_stmts (e2);
     186              : 
     187              :       /* Update profile only when redirection is really processed.  */
     188         1045 :       bb->count += e->count ();
     189              :     }
     190              : 
     191              :   /* There may be more than one statement in DUPLICATE which exhibits
     192              :      undefined behavior.  Ultimately we want the first such statement in
     193              :      DUPLCIATE so that we're able to delete as much code as possible.
     194              : 
     195              :      So each time we discover undefined behavior in DUPLICATE, search for
     196              :      the statement which triggers undefined behavior.  If found, then
     197              :      transform the statement into a trap and delete everything after the
     198              :      statement.  If not found, then this particular instance was subsumed by
     199              :      an earlier instance of undefined behavior and there's nothing to do.
     200              : 
     201              :      This is made more complicated by the fact that we have STMT, which is in
     202              :      BB rather than in DUPLICATE.  So we set up two iterators, one for each
     203              :      block and walk forward looking for STMT in BB, advancing each iterator at
     204              :      each step.
     205              : 
     206              :      When we find STMT the second iterator should point to STMT's equivalent in
     207              :      duplicate.  If DUPLICATE ends before STMT is found in BB, then there's
     208              :      nothing to do.
     209              : 
     210              :      Ignore labels and debug statements.  */
     211         1483 :   si = gsi_start_nondebug_after_labels_bb (bb);
     212         1483 :   si2 = gsi_start_nondebug_after_labels_bb (duplicate);
     213         7626 :   while (!gsi_end_p (si) && !gsi_end_p (si2) && gsi_stmt (si) != stmt)
     214              :     {
     215         6143 :       gsi_next_nondebug (&si);
     216         6143 :       gsi_next_nondebug (&si2);
     217              :     }
     218              : 
     219              :   /* This would be an indicator that we never found STMT in BB, which should
     220              :      never happen.  */
     221         1483 :   gcc_assert (!gsi_end_p (si));
     222              : 
     223              :   /* If we did not run to the end of DUPLICATE, then SI points to STMT and
     224              :      SI2 points to the duplicate of STMT in DUPLICATE.  Insert a trap
     225              :      before SI2 and remove SI2 and all trailing statements.  */
     226         1483 :   if (!gsi_end_p (si2))
     227              :     {
     228         1401 :       if (ret_zero)
     229              :         {
     230          109 :           greturn *ret = as_a <greturn *> (gsi_stmt (si2));
     231          109 :           tree zero = build_zero_cst (TREE_TYPE (gimple_return_retval (ret)));
     232          109 :           gimple_return_set_retval (ret, zero);
     233          109 :           update_stmt (ret);
     234              :         }
     235              :       else
     236         1292 :         insert_trap (&si2, op);
     237              :     }
     238              : 
     239         1483 :   return duplicate;
     240              : }
     241              : 
     242              : /* Return TRUE if STMT is a div/mod operation using DIVISOR as the divisor.
     243              :    FALSE otherwise.  */
     244              : 
     245              : static bool
     246     68515611 : is_divmod_with_given_divisor (gimple *stmt, tree divisor)
     247              : {
     248              :   /* Only assignments matter.  */
     249     68515611 :   if (!is_gimple_assign (stmt))
     250              :     return false;
     251              : 
     252              :   /* Check for every DIV/MOD expression.  */
     253     15192705 :   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
     254     15192705 :   if (rhs_code == TRUNC_DIV_EXPR
     255     15192705 :       || rhs_code == FLOOR_DIV_EXPR
     256     15142948 :       || rhs_code == CEIL_DIV_EXPR
     257     15142948 :       || rhs_code == EXACT_DIV_EXPR
     258              :       || rhs_code == ROUND_DIV_EXPR
     259     15091188 :       || rhs_code == TRUNC_MOD_EXPR
     260              :       || rhs_code == FLOOR_MOD_EXPR
     261     15046458 :       || rhs_code == CEIL_MOD_EXPR
     262     15046015 :       || rhs_code == ROUND_MOD_EXPR)
     263              :     {
     264              :       /* Pointer equality is fine when DIVISOR is an SSA_NAME, but
     265              :          not sufficient for constants which may have different types.  */
     266       146708 :       if (operand_equal_p (gimple_assign_rhs2 (stmt), divisor, 0))
     267              :         return true;
     268              :     }
     269              :   return false;
     270              : }
     271              : 
     272              : /* NAME is an SSA_NAME that we have already determined has the value 0 or NULL.
     273              : 
     274              :    Return TRUE if USE_STMT uses NAME in a way where a 0 or NULL value results
     275              :    in undefined behavior, FALSE otherwise
     276              : 
     277              :    LOC is used for issuing diagnostics.  This case represents potential
     278              :    undefined behavior exposed by path splitting and that's reflected in
     279              :    the diagnostic.  */
     280              : 
     281              : bool
     282       747573 : stmt_uses_name_in_undefined_way (gimple *use_stmt, tree name, location_t loc)
     283              : {
     284              :   /* If we are working with a non pointer type, then see
     285              :      if this use is a DIV/MOD operation using NAME as the
     286              :      divisor.  */
     287       747573 :   if (!POINTER_TYPE_P (TREE_TYPE (name)))
     288              :     {
     289       629144 :       if (!cfun->can_throw_non_call_exceptions)
     290       419718 :         return is_divmod_with_given_divisor (use_stmt, name);
     291              :       return false;
     292              :     }
     293              : 
     294              :   /* NAME is a pointer, so see if it's used in a context where it must
     295              :      be non-NULL.  */
     296       118429 :   bool by_dereference
     297       118429 :     = infer_nonnull_range_by_dereference (use_stmt, name);
     298              : 
     299       118429 :   if (by_dereference
     300       118429 :       || infer_nonnull_range_by_attribute (use_stmt, name))
     301              :     {
     302              : 
     303         1510 :       if (by_dereference)
     304              :         {
     305         1335 :           warning_at (loc, OPT_Wnull_dereference,
     306              :                       "potential null pointer dereference");
     307         1335 :           if (!flag_isolate_erroneous_paths_dereference)
     308              :             return false;
     309              :         }
     310              :       else
     311              :         {
     312          175 :           if (!flag_isolate_erroneous_paths_attribute)
     313              :             return false;
     314              :         }
     315         1337 :       return true;
     316              :     }
     317              :   return false;
     318              : }
     319              : 
     320              : /* Return TRUE if USE_STMT uses 0 or NULL in a context which results in
     321              :    undefined behavior, FALSE otherwise.
     322              : 
     323              :    These cases are explicit in the IL.  */
     324              : 
     325              : bool
     326     79070461 : stmt_uses_0_or_null_in_undefined_way (gimple *stmt)
     327              : {
     328     79070461 :   if (!cfun->can_throw_non_call_exceptions
     329     79070461 :       && is_divmod_with_given_divisor (stmt, integer_zero_node))
     330              :     return true;
     331              : 
     332              :   /* By passing null_pointer_node, we can use the
     333              :      infer_nonnull_range functions to detect explicit NULL
     334              :      pointer dereferences and other uses where a non-NULL
     335              :      value is required.  */
     336              : 
     337     79070207 :   bool by_dereference
     338     79070207 :     = infer_nonnull_range_by_dereference (stmt, null_pointer_node);
     339     79070207 :   if (by_dereference
     340     79070207 :       || infer_nonnull_range_by_attribute (stmt, null_pointer_node))
     341              :     {
     342         1263 :       if (by_dereference)
     343              :         {
     344          946 :           location_t loc = gimple_location (stmt);
     345          946 :           warning_at (loc, OPT_Wnull_dereference,
     346              :                       "null pointer dereference");
     347          946 :           if (!flag_isolate_erroneous_paths_dereference)
     348              :             return false;
     349              :         }
     350              :       else
     351              :         {
     352          317 :           if (!flag_isolate_erroneous_paths_attribute)
     353              :             return false;
     354              :         }
     355          947 :       return true;
     356              :     }
     357              :   return false;
     358              : }
     359              : 
     360              : /* Describes the property of a return statement that may return
     361              :    the address of one or more local variables.  The type must
     362              :    be safely assignable and copyable so that it can be stored in
     363              :    a hash_map.  */
     364              : class args_loc_t
     365              : {
     366              :  public:
     367              : 
     368        47374 :   args_loc_t (): nargs (), locvec (), ptr (&ptr)
     369              :   {
     370        47374 :     locvec.create (4);
     371        47374 :   }
     372              : 
     373            0 :   args_loc_t (const args_loc_t &rhs)
     374            0 :     : nargs (rhs.nargs), locvec (rhs.locvec.copy ()), ptr (&ptr) { }
     375              : 
     376              :   args_loc_t& operator= (const args_loc_t &rhs)
     377              :   {
     378              :     nargs = rhs.nargs;
     379              :     locvec.release ();
     380              :     locvec = rhs.locvec.copy ();
     381              :     return *this;
     382              :   }
     383              : 
     384        47374 :   ~args_loc_t ()
     385              :   {
     386        47374 :     locvec.release ();
     387        47374 :     gcc_assert (ptr == &ptr);
     388        47374 :   }
     389              : 
     390              :   /* For a PHI in a return statement its number of arguments.  When greater
     391              :      than LOCVEC.LENGTH () implies that an address of one of the locals in
     392              :      LOCVEC may but need not be returned by the statement.  Otherwise,
     393              :      unless both are zero, it implies it definitely is returned.  */
     394              :   unsigned nargs;
     395              :   /* The locations of local variables/alloca calls returned by the return
     396              :      statement.  Avoid using auto_vec here since it's not safe to copy due
     397              :      to pr90904.  */
     398              :   vec <location_t> locvec;
     399              :   void *ptr;
     400              : };
     401              : 
     402              : /* A mapping from a return statement to the locations of local variables
     403              :    whose addresses it may return.  */
     404              : typedef hash_map <gimple *, args_loc_t> locmap_t;
     405              : 
     406              : /* Given the LOCMAP mapping, issue diagnostics about returning addresses
     407              :    of local variables.  When MAYBE is set, all diagnostics will be of
     408              :    the "may return" kind.  Otherwise each will be determined based on
     409              :    the equality of the corresponding NARGS and LOCVEC.LENGTH () values.  */
     410              : 
     411              : static void
     412       981719 : diag_returned_locals (bool maybe, const locmap_t &locmap)
     413              : {
     414       982038 :   for (locmap_t::iterator it = locmap.begin (); it != locmap.end (); ++it)
     415              :     {
     416          319 :       gimple *stmt = (*it).first;
     417          319 :       const args_loc_t &argsloc = (*it).second;
     418          319 :       location_t stmtloc = gimple_location (stmt);
     419          319 :       if (stmtloc == UNKNOWN_LOCATION)
     420              :         /* When multiple return statements are merged into one it
     421              :            may not have an associated location.  Use the location
     422              :            of the closing brace instead.  */
     423           18 :         stmtloc = cfun->function_end_locus;
     424              : 
     425          319 :       auto_diagnostic_group d;
     426          319 :       unsigned nargs = argsloc.locvec.length ();
     427          638 :       if (warning_at (stmtloc, OPT_Wreturn_local_addr,
     428          151 :                       (maybe || argsloc.nargs > nargs
     429              :                        ? G_("function may return address of local variable")
     430              :                        : G_("function returns address of local variable"))))
     431              :         {
     432          578 :           for (unsigned i = 0; i != nargs; ++i)
     433          322 :             inform (argsloc.locvec[i], "declared here");
     434              :         }
     435          319 :     }
     436       981719 : }
     437              : 
     438              : /* Return true if EXPR is an expression of pointer type that refers
     439              :    to the address of one or more variables with automatic storage
     440              :    duration.  If so, add an entry to *PLOCMAP and insert into
     441              :    PLOCMAP->LOCVEC the locations of the corresponding local variables
     442              :    whose address is returned by the RETURN_STMT (which may be set to
     443              :    (gimple*)-1 as a placeholder for such a statement).  VISITED is
     444              :    a bitmap of PHI nodes already visited by recursive calls.  When
     445              :    null, PHI expressions are not considered.  */
     446              : 
     447              : static bool
     448      8706214 : is_addr_local (gimple *return_stmt, tree exp, locmap_t *plocmap,
     449              :                hash_set<gphi *> *visited)
     450              : {
     451      8706214 :   if (TREE_CODE (exp) == ADDR_EXPR)
     452              :     {
     453       109287 :       tree baseaddr = get_base_address (TREE_OPERAND (exp, 0));
     454       109287 :       if (TREE_CODE (baseaddr) == MEM_REF)
     455        24742 :         return is_addr_local (return_stmt, TREE_OPERAND (baseaddr, 0),
     456        24742 :                               plocmap, visited);
     457              : 
     458        84545 :       if ((!VAR_P (baseaddr)
     459        60899 :            || is_global_var (baseaddr))
     460       110667 :           && TREE_CODE (baseaddr) != PARM_DECL)
     461              :         return false;
     462              : 
     463        34975 :       args_loc_t &argsloc = plocmap->get_or_insert (return_stmt);
     464        34975 :       argsloc.locvec.safe_push (DECL_SOURCE_LOCATION (baseaddr));
     465        34975 :       return true;
     466              :     }
     467              : 
     468      8596927 :   if (!POINTER_TYPE_P (TREE_TYPE (exp)))
     469              :     return false;
     470              : 
     471      1535394 :   if (TREE_CODE (exp) == SSA_NAME)
     472              :     {
     473      1430023 :       gimple *def_stmt = SSA_NAME_DEF_STMT (exp);
     474      1430023 :       enum gimple_code code = gimple_code (def_stmt);
     475              : 
     476      1430023 :       if (is_gimple_assign (def_stmt))
     477              :         {
     478       705147 :           tree type = TREE_TYPE (gimple_assign_lhs (def_stmt));
     479       705147 :           if (POINTER_TYPE_P (type))
     480              :             {
     481       705147 :               tree_code code = gimple_assign_rhs_code (def_stmt);
     482       705147 :               tree ptr1 = NULL_TREE, ptr2 = NULL_TREE;
     483              : 
     484              :               /* Set to the number of arguments examined that should
     485              :                  be added to ARGSLOC->NARGS to identify expressions
     486              :                  only some but not all of whose operands refer to local
     487              :                  addresses.  */
     488       705147 :               unsigned nargs = 0;
     489       705147 :               if (code == COND_EXPR)
     490              :                 {
     491            0 :                   ptr1 = gimple_assign_rhs2 (def_stmt);
     492            0 :                   ptr2 = gimple_assign_rhs3 (def_stmt);
     493            0 :                   nargs = 2;
     494              :                 }
     495              :               else if (code == MAX_EXPR || code == MIN_EXPR)
     496              :                 {
     497          258 :                   ptr1 = gimple_assign_rhs1 (def_stmt);
     498          258 :                   ptr2 = gimple_assign_rhs2 (def_stmt);
     499          258 :                   nargs = 2;
     500              :                 }
     501              :               else if (code == ADDR_EXPR
     502              :                        || code == NOP_EXPR
     503              :                        || code == POINTER_PLUS_EXPR)
     504              :                 /* Leave NARGS at zero and let the recursive call set it.  */
     505       273749 :                 ptr1 = gimple_assign_rhs1 (def_stmt);
     506              : 
     507              :               /* Avoid short-circuiting the logical OR result in case
     508              :                  both operands refer to local variables, in which case
     509              :                  both should be considered and identified in the warning.  */
     510       979154 :               bool res1 = false, res2 = false;
     511       274007 :               if (ptr1)
     512       274007 :                 res1 = is_addr_local (return_stmt, ptr1, plocmap, visited);
     513       705147 :               if (ptr2)
     514          258 :                 res2 = is_addr_local (return_stmt, ptr2, plocmap, visited);
     515              : 
     516       705147 :               if (nargs)
     517          258 :                 if (args_loc_t *argsloc = plocmap->get (return_stmt))
     518           90 :                   argsloc->nargs += nargs;
     519              : 
     520       705147 :               return res1 || res2;
     521              :             }
     522              :           return false;
     523              :         }
     524              : 
     525       724876 :       if (code == GIMPLE_CALL
     526       724876 :           && gimple_call_builtin_p (def_stmt, BUILT_IN_NORMAL))
     527              :         {
     528              :           /* Handle alloca and friends that return pointers to automatic
     529              :              storage.  */
     530        16529 :           tree fn = gimple_call_fndecl (def_stmt);
     531        16529 :           int code = DECL_FUNCTION_CODE (fn);
     532        16529 :           if (code == BUILT_IN_ALLOCA
     533        16529 :               || code == BUILT_IN_ALLOCA_WITH_ALIGN
     534        14342 :               || code == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX)
     535              :             {
     536         2187 :               args_loc_t &argsloc = plocmap->get_or_insert (return_stmt);
     537         2187 :               argsloc.locvec.safe_push (gimple_location (def_stmt));
     538         2187 :               return true;
     539              :             }
     540              : 
     541        14342 :           if (gimple_call_num_args (def_stmt) < 1)
     542              :             return false;
     543              : 
     544              :           /* Recursively examine the first argument of calls to built-ins
     545              :              that return it.  */
     546        13491 :           switch (code)
     547              :             {
     548         1462 :             case BUILT_IN_MEMCPY:
     549         1462 :             case BUILT_IN_MEMCPY_CHK:
     550         1462 :             case BUILT_IN_MEMPCPY:
     551         1462 :             case BUILT_IN_MEMPCPY_CHK:
     552         1462 :             case BUILT_IN_MEMMOVE:
     553         1462 :             case BUILT_IN_MEMMOVE_CHK:
     554         1462 :             case BUILT_IN_STPCPY:
     555         1462 :             case BUILT_IN_STPCPY_CHK:
     556         1462 :             case BUILT_IN_STPNCPY:
     557         1462 :             case BUILT_IN_STPNCPY_CHK:
     558         1462 :             case BUILT_IN_STRCAT:
     559         1462 :             case BUILT_IN_STRCAT_CHK:
     560         1462 :             case BUILT_IN_STRCHR:
     561         1462 :             case BUILT_IN_STRCPY:
     562         1462 :             case BUILT_IN_STRCPY_CHK:
     563         1462 :             case BUILT_IN_STRNCAT:
     564         1462 :             case BUILT_IN_STRNCAT_CHK:
     565         1462 :             case BUILT_IN_STRNCPY:
     566         1462 :             case BUILT_IN_STRNCPY_CHK:
     567         1462 :             case BUILT_IN_STRRCHR:
     568         1462 :             case BUILT_IN_STRSTR:
     569         1462 :               return is_addr_local (return_stmt,
     570              :                                     gimple_call_arg (def_stmt, 0),
     571         1462 :                                     plocmap, visited);
     572              :             default:
     573              :               return false;
     574              :             }
     575              :         }
     576              : 
     577       708347 :       if (code == GIMPLE_PHI && visited)
     578              :         {
     579        32385 :           gphi *phi_stmt = as_a <gphi *> (def_stmt);
     580        32385 :           if (visited->add (phi_stmt))
     581              :             return false;
     582              : 
     583        21695 :           unsigned count = 0;
     584        21695 :           unsigned nargs = gimple_phi_num_args (phi_stmt);
     585        21695 :           args_loc_t &argsloc = plocmap->get_or_insert (return_stmt);
     586              :           /* Bump up the number of operands examined by the number of
     587              :              operands of this PHI.  */
     588        21695 :           argsloc.nargs += nargs;
     589        86950 :           for (unsigned i = 0; i < gimple_phi_num_args (phi_stmt); ++i)
     590              :             {
     591        65255 :               tree arg = gimple_phi_arg_def (phi_stmt, i);
     592        65255 :               if (is_addr_local (return_stmt, arg, plocmap, visited))
     593           52 :                 ++count;
     594              :             }
     595        21695 :           return count != 0;
     596              :         }
     597              :     }
     598              : 
     599              :   return false;
     600              : }
     601              : 
     602              : /* Detect returning the address of a local variable in a PHI result LHS
     603              :    and argument ARG and PHI edge E in basic block BB.  Add an entry for
     604              :    each use to LOCMAP, setting its NARGS member to the NARGS argument
     605              :    (the number of PHI operands) plus the number of arguments in binary
     606              :    expressions referenced by ARG.  Call isolate_path for each returned
     607              :    address and set *ISOLATED to true if called.
     608              :    Return either DUPLICATE or the most recent result of isolate_path.  */
     609              : 
     610              : static basic_block
     611      7793382 : handle_return_addr_local_phi_arg (basic_block bb, basic_block duplicate,
     612              :                                   tree lhs, tree arg, edge e, locmap_t &locmap,
     613              :                                   unsigned nargs, bool *isolated)
     614              : {
     615              :   /* Use (gimple*)-1 as a temporary placeholder and replace it with
     616              :      the return statement below once it is known.  Using a null doesn't
     617              :      work because it's used by the hash_map to mean "no-entry."  Pass
     618              :      null instead of a visited_phis bitmap to avoid descending into
     619              :      PHIs since they are being processed by the caller.  Those that
     620              :      remain will be checked again later.  */
     621      7793382 :   if (!is_addr_local ((gimple*)-1, arg, &locmap, NULL))
     622              :     {
     623              :       /* Remove the placeholder regardless of success or failure.  */
     624      7756519 :       locmap.remove ((gimple*)-1);
     625      7756519 :       return duplicate;
     626              :     }
     627              : 
     628        36863 :   const args_loc_t* const placeargsloc = locmap.get ((gimple*)-1);
     629        36863 :   const unsigned nlocs = placeargsloc->locvec.length ();
     630        36863 :   gcc_assert (nlocs);
     631              : 
     632              :   /* Add to the number of PHI arguments determined by the caller
     633              :      the number of operands of the expressions referenced by ARG.
     634              :      This lets the caller determine whether it's dealing with
     635              :      a "may return" or "definitely returns."  */
     636        36863 :   nargs += placeargsloc->nargs;
     637              : 
     638              :   /* Set to true if any expressions referenced by ARG involve
     639              :      multiple addresses only some of which are those of locals.  */
     640        36863 :   bool maybe = placeargsloc->nargs > placeargsloc->locvec.length ();
     641              : 
     642        36863 :   gimple *use_stmt;
     643        36863 :   imm_use_iterator iter;
     644              : 
     645              :   /* Look for uses of the PHI result LHS in return statements.  */
     646       178798 :   FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
     647              :     {
     648       141935 :       greturn *return_stmt = dyn_cast <greturn *> (use_stmt);
     649       141935 :       if (!return_stmt)
     650       141805 :         continue;
     651              : 
     652          130 :       if (gimple_return_retval (return_stmt) != lhs
     653          130 :           || !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
     654            6 :         continue;
     655              : 
     656              :       /* Add an entry for the return statement and the locations
     657              :          oof the PHI arguments obtained above to the map.  */
     658          124 :       args_loc_t &argsloc = locmap.get_or_insert (use_stmt);
     659          124 :       argsloc.nargs = nargs;
     660          124 :       unsigned nelts = argsloc.locvec.length () + nlocs;
     661          124 :       argsloc.locvec.reserve (nelts);
     662          124 :       argsloc.locvec.splice (placeargsloc->locvec);
     663              : 
     664          124 :       if (!maybe
     665          109 :           && (flag_isolate_erroneous_paths_dereference
     666            0 :               || flag_isolate_erroneous_paths_attribute)
     667          109 :           && gimple_bb (use_stmt) == bb
     668          233 :           && (duplicate || can_duplicate_block_p (bb)))
     669              :         {
     670          109 :           duplicate = isolate_path (bb, duplicate, e,
     671              :                                     use_stmt, lhs, true);
     672              : 
     673              :           /* Let caller know the path has been isolated.  */
     674          109 :           *isolated = true;
     675              :         }
     676        36863 :     }
     677              : 
     678        36863 :   locmap.remove ((gimple*)-1);
     679              : 
     680        36863 :   return duplicate;
     681              : }
     682              : 
     683              : /* Look for PHI nodes which feed statements in the same block where
     684              :    the value of the PHI node implies the statement is erroneous.
     685              : 
     686              :    For example, a NULL PHI arg value which then feeds a pointer
     687              :    dereference.
     688              : 
     689              :    When found isolate and optimize the path associated with the PHI
     690              :    argument feeding the erroneous statement.  */
     691              : static void
     692       981472 : find_implicit_erroneous_behavior (void)
     693              : {
     694       981472 :   locmap_t locmap;
     695              : 
     696       981472 :   basic_block bb;
     697              : 
     698     10212263 :   FOR_EACH_BB_FN (bb, cfun)
     699              :     {
     700      9230791 :       gphi_iterator si;
     701              : 
     702              :       /* Out of an abundance of caution, do not isolate paths to a
     703              :          block where the block has any abnormal outgoing edges.
     704              : 
     705              :          We might be able to relax this in the future.  We have to detect
     706              :          when we have to split the block with the NULL dereference and
     707              :          the trap we insert.  We have to preserve abnormal edges out
     708              :          of the isolated block which in turn means updating PHIs at
     709              :          the targets of those abnormal outgoing edges.  */
     710      9230791 :       if (has_abnormal_or_eh_outgoing_edge_p (bb))
     711       987639 :         continue;
     712              : 
     713              : 
     714              :       /* If BB has an edge to itself, then duplication of BB below
     715              :          could result in reallocation of BB's PHI nodes.   If that happens
     716              :          then the loop below over the PHIs would use the old PHI and
     717              :          thus invalid information.  We don't have a good way to know
     718              :          if a PHI has been reallocated, so just avoid isolation in
     719              :          this case.  */
     720      8496181 :       if (find_edge (bb, bb))
     721       253029 :         continue;
     722              : 
     723              :       /* First look for a PHI which sets a pointer to NULL and which
     724              :          is then dereferenced within BB.  This is somewhat overly
     725              :          conservative, but probably catches most of the interesting
     726              :          cases.   */
     727      8243152 :       basic_block duplicate = NULL;
     728     11354589 :       for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
     729              :         {
     730      3111437 :           gphi *phi = si.phi ();
     731      3111437 :           tree lhs = gimple_phi_result (phi);
     732              : 
     733              :           /* PHI produces a pointer result.  See if any of the PHI's
     734              :              arguments are NULL.
     735              : 
     736              :              When we remove an edge, we want to reprocess the current
     737              :              index since the argument at that index will have been
     738              :              removed, hence the ugly way we update I for each iteration.  */
     739      3111437 :           for (unsigned i = 0, next_i = 0;
     740     10905932 :                i < gimple_phi_num_args (phi); i = next_i)
     741              :             {
     742      7794495 :               tree arg = gimple_phi_arg_def (phi, i);
     743      7794495 :               edge e = gimple_phi_arg_edge (phi, i);
     744              : 
     745              :               /* Advance the argument index unless a path involving
     746              :                  the current argument has been isolated.  */
     747      7794495 :               next_i = i + 1;
     748              : 
     749      7794495 :               if (!integer_zerop (arg))
     750      7177040 :                 continue;
     751              : 
     752       617455 :               location_t phi_arg_loc = gimple_phi_arg_location (phi, i);
     753              : 
     754       617455 :               imm_use_iterator iter;
     755       617455 :               gimple *use_stmt;
     756              : 
     757              :               /* We've got a NULL PHI argument.  Now see if the
     758              :                  PHI's result is dereferenced within BB.  */
     759       617455 :               auto_vec <gimple *, 4> uses_in_bb;
     760      2160257 :               FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
     761              :                 {
     762              :                   /* We only care about uses in BB.  Catching cases in
     763              :                      in other blocks would require more complex path
     764              :                      isolation code.   */
     765      1542802 :                   if (gimple_bb (use_stmt) != bb)
     766       795229 :                     continue;
     767              : 
     768       747573 :                   location_t loc = gimple_location (use_stmt)
     769       747573 :                     ? gimple_location (use_stmt)
     770              :                     : phi_arg_loc;
     771              : 
     772       747573 :                   if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
     773              :                     {
     774         1374 :                       if (!can_duplicate_block_p (bb))
     775              :                         break;
     776         1374 :                       uses_in_bb.safe_push (use_stmt);
     777              :                     }
     778       617455 :                 }
     779      1853739 :               for (gimple *use_stmt : uses_in_bb)
     780              :                 {
     781         1374 :                   duplicate = isolate_path (bb, duplicate, e,
     782              :                                             use_stmt, lhs, false);
     783              : 
     784              :                   /* When we remove an incoming edge, we need to
     785              :                      reprocess the Ith element.  */
     786         1374 :                   next_i = i;
     787         1374 :                   cfg_altered = true;
     788              :                 }
     789       617455 :             }
     790              :         }
     791              : 
     792              :       /* Then look for a PHI which have addresses of locals that
     793              :          are then returned.  */
     794      8243152 :       duplicate = NULL;
     795     11354589 :       for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
     796              :         {
     797      3111437 :           gphi *phi = si.phi ();
     798      3111437 :           tree lhs = gimple_phi_result (phi);
     799              : 
     800              :           /* Initial number of PHI arguments.  The result may change
     801              :              from one iteration of the loop below to the next in
     802              :              response to changes to the CFG but only the initial
     803              :              value is stored below for use by diagnostics.  */
     804      3111437 :           unsigned nargs = gimple_phi_num_args (phi);
     805              : 
     806              :           /* PHI produces a pointer result.  See if any of the PHI's
     807              :              arguments are NULL.
     808              : 
     809              :              When we remove an edge, we want to reprocess the current
     810              :              index since the argument at that index will have been
     811              :              removed, hence the ugly way we update I for each iteration.  */
     812      3111437 :           for (unsigned i = 0, next_i = 0;
     813     10904819 :                i < gimple_phi_num_args (phi); i = next_i)
     814              :             {
     815      7793382 :               tree arg = gimple_phi_arg_def (phi, i);
     816      7793382 :               edge e = gimple_phi_arg_edge (phi, i);
     817              : 
     818              :               /* Advance the argument index unless a path involving
     819              :                  the current argument has been isolated.  */
     820      7793382 :               next_i = i + 1;
     821      7793382 :               bool isolated = false;
     822      7793382 :               duplicate = handle_return_addr_local_phi_arg (bb, duplicate, lhs,
     823              :                                                             arg, e, locmap,
     824              :                                                             nargs, &isolated);
     825      7793382 :               if (isolated)
     826              :                 {
     827          109 :                   cfg_altered = true;
     828          109 :                   next_i = i;
     829              :                 }
     830              :             }
     831              :         }
     832              : 
     833              :     }
     834              : 
     835       981472 :   diag_returned_locals (false, locmap);
     836       981472 : }
     837              : 
     838              : /* Detect and diagnose returning the address of a local variable
     839              :    in RETURN_STMT in basic block BB.  This only becomes undefined
     840              :    behavior if the result is used, so we do not insert a trap and
     841              :    only return NULL instead.  */
     842              : 
     843              : static void
     844       956872 : warn_return_addr_local (basic_block bb, greturn *return_stmt)
     845              : {
     846       956872 :   tree val = gimple_return_retval (return_stmt);
     847       956872 :   if (!val)
     848       956793 :     return;
     849              : 
     850       547108 :   locmap_t locmap;
     851       547108 :   hash_set<gphi *> visited_phis;
     852       547108 :   if (!is_addr_local (return_stmt, val, &locmap, &visited_phis))
     853              :     return;
     854              : 
     855              :   /* We only need it for this particular case.  */
     856          247 :   calculate_dominance_info (CDI_POST_DOMINATORS);
     857              : 
     858          247 :   const args_loc_t *argsloc = locmap.get (return_stmt);
     859          247 :   gcc_assert (argsloc);
     860              : 
     861          247 :   bool maybe = argsloc->nargs > argsloc->locvec.length ();
     862          247 :   if (!maybe)
     863          215 :     maybe = !dominated_by_p (CDI_POST_DOMINATORS,
     864          215 :                              single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)), bb);
     865              : 
     866          247 :   diag_returned_locals (maybe, locmap);
     867              : 
     868              :   /* Bail if the statement isn't certain to return the address
     869              :      of a local (e.g., if it involves a conditional expression
     870              :      that wasn't transformed into a PHI or if it involves
     871              :      a MAX_EXPR or MIN_EXPR only one of whose operands is a local
     872              :      (even though such an expression isn't valid in C or has
     873              :      defined semantics in C++).  */
     874          247 :   if (maybe)
     875              :     return;
     876              : 
     877              :   /* Do not modify code if the user only asked for warnings.  */
     878           79 :   if (flag_isolate_erroneous_paths_dereference
     879            0 :       || flag_isolate_erroneous_paths_attribute)
     880              :     {
     881           79 :       tree zero = build_zero_cst (TREE_TYPE (val));
     882           79 :       gimple_return_set_retval (return_stmt, zero);
     883           79 :       update_stmt (return_stmt);
     884              :     }
     885       547108 : }
     886              : 
     887              : /* Look for statements which exhibit erroneous behavior.  For example
     888              :    a NULL pointer dereference.
     889              : 
     890              :    When found, optimize the block containing the erroneous behavior.  */
     891              : static void
     892       981472 : find_explicit_erroneous_behavior (void)
     893              : {
     894       981472 :   basic_block bb;
     895       981472 :   auto_vec<gimple *> local_bb_split_points;
     896       981472 :   bb_split_points = &local_bb_split_points;
     897              : 
     898     10213206 :   FOR_EACH_BB_FN (bb, cfun)
     899              :     {
     900      9231734 :       gimple_stmt_iterator si;
     901              : 
     902              :       /* Out of an abundance of caution, do not isolate paths to a
     903              :          block where the block has any abnormal outgoing edges.
     904              : 
     905              :          We might be able to relax this in the future.  We have to detect
     906              :          when we have to split the block with the NULL dereference and
     907              :          the trap we insert.  We have to preserve abnormal edges out
     908              :          of the isolated block which in turn means updating PHIs at
     909              :          the targets of those abnormal outgoing edges.  */
     910      9231734 :       if (has_abnormal_or_eh_outgoing_edge_p (bb))
     911       734610 :         continue;
     912              : 
     913              :       /* Now look at the statements in the block and see if any of
     914              :          them explicitly dereference a NULL pointer.  This happens
     915              :          because of jump threading and constant propagation.  */
     916     96063508 :       for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
     917              :         {
     918     79070461 :           gimple *stmt = gsi_stmt (si);
     919              : 
     920     79070461 :           if (stmt_uses_0_or_null_in_undefined_way (stmt))
     921              :             {
     922         1201 :               insert_trap (&si, null_pointer_node);
     923         1201 :               bb = gimple_bb (gsi_stmt (si));
     924              : 
     925              :               /* Ignore any more operands on this statement and
     926              :                  continue the statement iterator (which should
     927              :                  terminate its loop immediately.  */
     928         1201 :               cfg_altered = true;
     929         1201 :               break;
     930              :             }
     931              : 
     932              :           /* Look for a return statement that returns the address
     933              :              of a local variable or the result of alloca.  */
     934     80026132 :           if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
     935       956872 :             warn_return_addr_local (bb, return_stmt);
     936              :         }
     937              :     }
     938              : 
     939       981472 :   free_dominance_info (CDI_POST_DOMINATORS);
     940              : 
     941              :   /* Perform delayed splitting of blocks.  */
     942       981475 :   for (gimple *stmt : local_bb_split_points)
     943            1 :     split_block (gimple_bb (stmt), stmt);
     944              : 
     945       981472 :   bb_split_points = NULL;
     946       981472 : }
     947              : 
     948              : /* Search the function for statements which, if executed, would cause
     949              :    the program to fault such as a dereference of a NULL pointer.
     950              : 
     951              :    Such a program can't be valid if such a statement was to execute
     952              :    according to ISO standards.
     953              : 
     954              :    We detect explicit NULL pointer dereferences as well as those implied
     955              :    by a PHI argument having a NULL value which unconditionally flows into
     956              :    a dereference in the same block as the PHI.
     957              : 
     958              :    In the former case we replace the offending statement with an
     959              :    unconditional trap and eliminate the outgoing edges from the statement's
     960              :    basic block.  This may expose secondary optimization opportunities.
     961              : 
     962              :    In the latter case, we isolate the path(s) with the NULL PHI
     963              :    feeding the dereference.  We can then replace the offending statement
     964              :    and eliminate the outgoing edges in the duplicate.  Again, this may
     965              :    expose secondary optimization opportunities.
     966              : 
     967              :    A warning for both cases may be advisable as well.
     968              : 
     969              :    Other statically detectable violations of the ISO standard could be
     970              :    handled in a similar way, such as out-of-bounds array indexing.  */
     971              : 
     972              : static unsigned int
     973       981472 : gimple_ssa_isolate_erroneous_paths (void)
     974              : {
     975       981472 :   initialize_original_copy_tables ();
     976              : 
     977              :   /* Search all the blocks for edges which, if traversed, will
     978              :      result in undefined behavior.  */
     979       981472 :   cfg_altered = false;
     980              : 
     981              :   /* First handle cases where traversal of a particular edge
     982              :      triggers undefined behavior.  These cases require creating
     983              :      duplicate blocks and thus new SSA_NAMEs.
     984              : 
     985              :      We want that process complete prior to the phase where we start
     986              :      removing edges from the CFG.  Edge removal may ultimately result in
     987              :      removal of PHI nodes and thus releasing SSA_NAMEs back to the
     988              :      name manager.
     989              : 
     990              :      If the two processes run in parallel we could release an SSA_NAME
     991              :      back to the manager but we could still have dangling references
     992              :      to the released SSA_NAME in unreachable blocks.
     993              :      that any released names not have dangling references in the IL.  */
     994       981472 :   find_implicit_erroneous_behavior ();
     995       981472 :   find_explicit_erroneous_behavior ();
     996              : 
     997       981472 :   free_original_copy_tables ();
     998              : 
     999              :   /* We scramble the CFG and loop structures a bit, clean up
    1000              :      appropriately.  We really should incrementally update the
    1001              :      loop structures, in theory it shouldn't be that hard.  */
    1002       981472 :   if (cfg_altered)
    1003              :     {
    1004         1331 :       free_dominance_info (CDI_DOMINATORS);
    1005         1331 :       loops_state_set (LOOPS_NEED_FIXUP);
    1006         1331 :       return TODO_cleanup_cfg | TODO_update_ssa;
    1007              :     }
    1008              :   return 0;
    1009              : }
    1010              : 
    1011              : namespace {
    1012              : const pass_data pass_data_isolate_erroneous_paths =
    1013              : {
    1014              :   GIMPLE_PASS, /* type */
    1015              :   "isolate-paths", /* name */
    1016              :   OPTGROUP_NONE, /* optinfo_flags */
    1017              :   TV_ISOLATE_ERRONEOUS_PATHS, /* tv_id */
    1018              :   ( PROP_cfg | PROP_ssa ), /* properties_required */
    1019              :   0, /* properties_provided */
    1020              :   0, /* properties_destroyed */
    1021              :   0, /* todo_flags_start */
    1022              :   0, /* todo_flags_finish */
    1023              : };
    1024              : 
    1025              : class pass_isolate_erroneous_paths : public gimple_opt_pass
    1026              : {
    1027              : public:
    1028       294196 :   pass_isolate_erroneous_paths (gcc::context *ctxt)
    1029       588392 :     : gimple_opt_pass (pass_data_isolate_erroneous_paths, ctxt)
    1030              :   {}
    1031              : 
    1032              :   /* opt_pass methods: */
    1033            0 :   opt_pass * clone () final override
    1034              :   {
    1035            0 :     return new pass_isolate_erroneous_paths (m_ctxt);
    1036              :   }
    1037      1060389 :   bool gate (function *) final override
    1038              :     {
    1039              :       /* If we do not have a suitable builtin function for the trap statement,
    1040              :          then do not perform the optimization.  */
    1041      1060389 :       return (flag_isolate_erroneous_paths_dereference != 0
    1042        78851 :               || flag_isolate_erroneous_paths_attribute != 0
    1043      1139238 :               || warn_null_dereference);
    1044              :     }
    1045              : 
    1046       981472 :   unsigned int execute (function *) final override
    1047              :     {
    1048       981472 :       return gimple_ssa_isolate_erroneous_paths ();
    1049              :     }
    1050              : 
    1051              : }; // class pass_isolate_erroneous_paths
    1052              : }
    1053              : 
    1054              : gimple_opt_pass *
    1055       294196 : make_pass_isolate_erroneous_paths (gcc::context *ctxt)
    1056              : {
    1057       294196 :   return new pass_isolate_erroneous_paths (ctxt);
    1058              : }
        

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.