LCOV - code coverage report
Current view: top level - gcc - tree-ssa-phiprop.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 97.1 % 280 272
Test Date: 2026-05-30 15:37:04 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Backward propagation of indirect loads through PHIs.
       2              :    Copyright (C) 2007-2026 Free Software Foundation, Inc.
       3              :    Contributed by Richard Guenther <rguenther@suse.de>
       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 "tree.h"
      26              : #include "gimple.h"
      27              : #include "tree-pass.h"
      28              : #include "ssa.h"
      29              : #include "gimple-pretty-print.h"
      30              : #include "fold-const.h"
      31              : #include "tree-eh.h"
      32              : #include "gimple-iterator.h"
      33              : #include "stor-layout.h"
      34              : #include "tree-ssa-loop.h"
      35              : #include "tree-cfg.h"
      36              : #include "tree-ssa-dce.h"
      37              : #include "cfgloop.h"
      38              : 
      39              : /* This pass propagates indirect loads through the PHI node for its
      40              :    address to make the load source possibly non-addressable and to
      41              :    allow for PHI optimization to trigger.
      42              : 
      43              :    For example the pass changes
      44              : 
      45              :      # addr_1 = PHI <&a, &b>
      46              :      tmp_1 = *addr_1;
      47              : 
      48              :    to
      49              : 
      50              :      # tmp_1 = PHI <a, b>
      51              : 
      52              :    but also handles more complex scenarios like
      53              : 
      54              :      D.2077_2 = &this_1(D)->a1;
      55              :      ...
      56              : 
      57              :      # b_12 = PHI <&c(2), D.2077_2(3)>
      58              :      D.2114_13 = *b_12;
      59              :      ...
      60              : 
      61              :      # b_15 = PHI <b_12(4), &b(5)>
      62              :      D.2080_5 = &this_1(D)->a0;
      63              :      ...
      64              : 
      65              :      # b_18 = PHI <D.2080_5(6), &c(7)>
      66              :      ...
      67              : 
      68              :      # b_21 = PHI <b_15(8), b_18(9)>
      69              :      D.2076_8 = *b_21;
      70              : 
      71              :    where the addresses loaded are defined by PHIs itself.
      72              :    The above happens for
      73              : 
      74              :      std::max(std::min(a0, c), std::min(std::max(a1, c), b))
      75              : 
      76              :    where this pass transforms it to a form later PHI optimization
      77              :    recognizes and transforms it to the simple
      78              : 
      79              :      D.2109_10 = this_1(D)->a1;
      80              :      D.2110_11 = c;
      81              :      D.2114_31 = MAX_EXPR <D.2109_10, D.2110_11>;
      82              :      D.2115_14 = b;
      83              :      D.2125_17 = MIN_EXPR <D.2115_14, D.2114_31>;
      84              :      D.2119_16 = this_1(D)->a0;
      85              :      D.2124_32 = MIN_EXPR <D.2110_11, D.2119_16>;
      86              :      D.2076_33 = MAX_EXPR <D.2125_17, D.2124_32>;
      87              : 
      88              :    The pass does a dominator walk processing loads using a basic-block
      89              :    local analysis and stores the result for use by transformations on
      90              :    dominated basic-blocks.  */
      91              : 
      92              : 
      93              : /* Structure to keep track of the value of a dereferenced PHI result
      94              :    and the virtual operand used for that dereference.  */
      95              : 
      96              : struct phiprop_d
      97              : {
      98              :   tree value;
      99              :   tree vuse;
     100              : };
     101              : 
     102              : /* Insert a new phi node for the dereference of PHI at basic_block
     103              :    BB with the virtual operands from USE_STMT. The vuse for
     104              :    the load will be set to OTHER_VUSE unless there is virtual op
     105              :    phi for BB.  */
     106              : 
     107              : static tree
     108        13982 : phiprop_insert_phi (basic_block bb, gphi *phi, gimple *use_stmt,
     109              :                     struct phiprop_d *phivn, size_t n,
     110              :                     bitmap dce_ssa_names, tree other_vuse)
     111              : {
     112        13982 :   tree res;
     113        13982 :   gphi *new_phi = NULL;
     114        13982 :   edge_iterator ei;
     115        13982 :   edge e;
     116        13982 :   tree phi_result = PHI_RESULT (phi);
     117        13982 :   bitmap_set_bit (dce_ssa_names, SSA_NAME_VERSION (phi_result));
     118              : 
     119        13982 :   gcc_assert (is_gimple_assign (use_stmt)
     120              :               && gimple_assign_rhs_code (use_stmt) == MEM_REF);
     121              : 
     122              :   /* Build a new PHI node to replace the definition of
     123              :      the indirect reference lhs.  */
     124        13982 :   res = gimple_assign_lhs (use_stmt);
     125        13982 :   if (TREE_CODE (res) == SSA_NAME)
     126        13835 :     new_phi = create_phi_node (res, bb);
     127              : 
     128        13982 :   if (dump_file && (dump_flags & TDF_DETAILS))
     129              :     {
     130           26 :       fprintf (dump_file, "Inserting PHI for result of load ");
     131           26 :       print_gimple_stmt (dump_file, use_stmt, 0);
     132              :     }
     133              : 
     134        13982 :   gphi *vphi = get_virtual_phi (bb);
     135              : 
     136              :   /* Add PHI arguments for each edge inserting loads of the
     137              :      addressable operands.  */
     138        40480 :   FOR_EACH_EDGE (e, ei, bb->preds)
     139              :     {
     140        26498 :       tree old_arg, new_var;
     141        26498 :       gassign *tmp;
     142        26498 :       location_t locus;
     143              : 
     144        26498 :       old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
     145        26498 :       locus = gimple_phi_arg_location_from_edge (phi, e);
     146        26498 :       while (TREE_CODE (old_arg) == SSA_NAME
     147        27807 :              && (SSA_NAME_VERSION (old_arg) >= n
     148         1411 :                  || phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE))
     149              :         {
     150         1309 :           gimple *def_stmt = SSA_NAME_DEF_STMT (old_arg);
     151         1309 :           old_arg = gimple_assign_rhs1 (def_stmt);
     152         1309 :           locus = gimple_location (def_stmt);
     153              :         }
     154              : 
     155        26498 :       if (TREE_CODE (old_arg) == SSA_NAME)
     156              :         {
     157          102 :           if (dump_file && (dump_flags & TDF_DETAILS))
     158              :             {
     159            6 :               fprintf (dump_file, "  for edge defining ");
     160            6 :               print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e));
     161            6 :               fprintf (dump_file, " reusing PHI result ");
     162           12 :               print_generic_expr (dump_file,
     163            6 :                                   phivn[SSA_NAME_VERSION (old_arg)].value);
     164            6 :               fprintf (dump_file, "\n");
     165              :             }
     166              :           /* Reuse a formerly created dereference.  */
     167          102 :           new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
     168              :         }
     169              :       else
     170              :         {
     171        26396 :           tree rhs = gimple_assign_rhs1 (use_stmt);
     172        26396 :           gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
     173        26396 :           tree vuse = NULL_TREE;
     174        26396 :           if (TREE_CODE (res) == SSA_NAME)
     175              :             {
     176        26040 :               new_var = make_ssa_name (TREE_TYPE (rhs));
     177        26040 :               if (vphi)
     178          120 :                 vuse = PHI_ARG_DEF_FROM_EDGE (vphi, e);
     179              :               else
     180              :                 vuse = other_vuse;
     181              :             }
     182              :           else
     183              :             /* For the aggregate copy case updating virtual operands
     184              :                we'd have to possibly insert a virtual PHI and we have
     185              :                to split the existing VUSE lifetime.  Leave that to
     186              :                the generic SSA updating.  */
     187          356 :             new_var = unshare_expr (res);
     188        26396 :           if (!is_gimple_min_invariant (old_arg))
     189         1286 :             old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
     190              :           else
     191        25110 :             old_arg = unshare_expr (old_arg);
     192        26396 :           tmp = gimple_build_assign (new_var,
     193        26396 :                                      fold_build2 (MEM_REF, TREE_TYPE (rhs),
     194              :                                                   old_arg,
     195              :                                                   TREE_OPERAND (rhs, 1)));
     196        26396 :           gimple_set_location (tmp, locus);
     197        26396 :           if (vuse)
     198        26040 :             gimple_set_vuse (tmp, vuse);
     199              : 
     200        26396 :           gsi_insert_on_edge (e, tmp);
     201        26396 :           update_stmt (tmp);
     202              : 
     203        26396 :           if (dump_file && (dump_flags & TDF_DETAILS))
     204              :             {
     205           46 :               fprintf (dump_file, "  for edge defining ");
     206           46 :               print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e));
     207           46 :               fprintf (dump_file, " inserting load ");
     208           46 :               print_gimple_stmt (dump_file, tmp, 0);
     209              :             }
     210              :         }
     211              : 
     212        26498 :       if (new_phi)
     213        26142 :         add_phi_arg (new_phi, new_var, e, locus);
     214              :     }
     215              : 
     216        13982 :   if (new_phi)
     217              :     {
     218        13835 :       update_stmt (new_phi);
     219              : 
     220        13835 :       if (dump_file && (dump_flags & TDF_DETAILS))
     221           26 :         print_gimple_stmt (dump_file, new_phi, 0);
     222              :     }
     223              : 
     224        13982 :   return res;
     225              : }
     226              : 
     227              : /* Verify if *idx is available at *DATA.  */
     228              : 
     229              : static bool
     230           50 : chk_uses (tree, tree *idx, void *data)
     231              : {
     232           50 :   basic_block dom = (basic_block) data;
     233           50 :   if (TREE_CODE (*idx) == SSA_NAME)
     234           32 :     return (SSA_NAME_IS_DEFAULT_DEF (*idx)
     235           32 :             || ! dominated_by_p (CDI_DOMINATORS,
     236           18 :                                  gimple_bb (SSA_NAME_DEF_STMT (*idx)), dom));
     237              :   return true;
     238              : }
     239              : 
     240              : /* Check if we can move the loads from LOAD_STMT.
     241              :    This is when the virtual use is the same as the
     242              :    one active at the start of BB which we know either
     243              :    from its virtual PHI def (VPHI) or from the common
     244              :    incoming VUSE (up_vuse).  If neither is present
     245              :    make sure the def stmt of the virtual use is in a
     246              :    different basic block dominating BB.  When the def
     247              :    is an edge-inserted one we know it dominates us.
     248              :    Returns the vuse to use for the inserting.  NULL_TREE
     249              :    is returned when we can't do the insert.  */
     250              : 
     251              : static tree
     252        14849 : can_handle_load (gimple *load_stmt,
     253              :                  basic_block bb,
     254              :                  gphi *vphi, tree up_vuse, bool aggregate)
     255              : {
     256        14849 :   tree vuse = gimple_vuse (load_stmt);
     257              :   /* If the load does not have a store beforehand,
     258              :      then we can do the load in conditional. */
     259        14849 :   if (SSA_NAME_IS_DEFAULT_DEF (vuse))
     260              :     {
     261              :       /* For loads that have no stores before, there should be no
     262              :          vphi.  */
     263         1292 :       gcc_checking_assert (!vphi);
     264              :       /* The common vuse is the same as the default or there is none. */
     265         1292 :       gcc_checking_assert (!up_vuse || up_vuse == vuse);
     266              :       return vuse;
     267              :     }
     268              : 
     269              :   /* If we have a vphi, then that needs to be end point.
     270              :      If we have a common incoming vuse, that needs to be the end point.  */
     271        13557 :   tree expected_vuse = NULL_TREE;
     272        13557 :   if (vphi)
     273          249 :     expected_vuse = gimple_phi_result (vphi);
     274              :   else if (up_vuse)
     275              :     expected_vuse = up_vuse;
     276              :   /* Try to see if the store does not effect the load.  */
     277        13557 :   gimple *other_store = SSA_NAME_DEF_STMT (vuse);
     278              :   /* For aggregates, skipping the store is too
     279              :      hard to handle as you need to check for loads
     280              :      and it is not worth the extra checks so just handle expected vuse
     281              :      and the dominated by case.   */
     282        13557 :   if (aggregate)
     283              :     {
     284              :       /* If the vuse on the load is the same as the expected vuse,
     285              :          there are no stores inbetween.  */
     286          116 :       if (vuse == expected_vuse)
     287              :         return vuse;
     288           88 :       if (expected_vuse)
     289              :         return NULL_TREE;
     290           88 :       if (gimple_bb (other_store) != bb
     291          156 :           && dominated_by_p (CDI_DOMINATORS,
     292           68 :                              bb, gimple_bb (other_store)))
     293              :         return vuse;
     294           20 :       return NULL_TREE;
     295              :     }
     296              : 
     297              :   /* Skip over clobbers in the same bb as the use
     298              :      as they don't interfere with loads.  */
     299        13459 :   while (!SSA_NAME_IS_DEFAULT_DEF (vuse)
     300        13459 :          && gimple_clobber_p (other_store)
     301        13678 :          && gimple_bb (other_store) == bb)
     302              :     {
     303           18 :       vuse = gimple_vuse (other_store);
     304           18 :       other_store = SSA_NAME_DEF_STMT (vuse);
     305              :     }
     306              :   /* If the load does not have a store beforehand,
     307              :      then we can do the load in conditional. */
     308        13441 :   if (SSA_NAME_IS_DEFAULT_DEF (vuse))
     309              :     {
     310              :       /* For loads that have no stores before, there should be no
     311              :          vphi.  */
     312            0 :       gcc_checking_assert (!vphi);
     313              :       /* The common vuse is the same as the default or there is none. */
     314            0 :       gcc_checking_assert (!up_vuse || up_vuse == vuse);
     315              :       return vuse;
     316              :     }
     317              : 
     318              :   /* If the vuse on the load is the same as the expected vuse,
     319              :      there are no stores inbetween.  */
     320        13441 :   if (vuse == expected_vuse)
     321              :     return vuse;
     322              : 
     323              :   /* Only handling the case where the store is in the same
     324              :      bb as the phi.  */
     325        13268 :   if (gimple_bb (other_store) == bb)
     326              :     {
     327          212 :       tree src = gimple_assign_rhs1 (load_stmt);
     328          212 :       ao_ref read;
     329          212 :       ao_ref_init (&read, src);
     330          212 :       if (stmt_may_clobber_ref_p_1 (other_store, &read, false))
     331          178 :         return NULL_TREE;
     332          108 :       vuse = gimple_vuse (other_store);
     333              :       /* If that skipped store was the first store in program,
     334              :          then we can do the load conditional.  */
     335          108 :       if (SSA_NAME_IS_DEFAULT_DEF (vuse))
     336              :         {
     337              :           /* For loads that have no stores before, there should be no
     338              :              vphi.  */
     339            0 :           gcc_checking_assert (!vphi);
     340              :           /* The common vuse is the same as the default or there is none. */
     341            0 :           gcc_checking_assert (!up_vuse || up_vuse == vuse);
     342              :           return vuse;
     343              :         }
     344          108 :       other_store = SSA_NAME_DEF_STMT (vuse);
     345              :       /* If the new vuse (after skipping) is the same as expected
     346              :          then that is the vuse to return.  */
     347          108 :       if (vuse == expected_vuse)
     348              :         return vuse;
     349          101 :       if (gimple_bb (other_store) == bb)
     350              :         return NULL_TREE;
     351              :     }
     352              : 
     353              :   /* If there was no an expected vuse then see if the vuse dominates the phi of
     354              :       the address.  */
     355        13090 :   if (!expected_vuse
     356        26026 :       && dominated_by_p (CDI_DOMINATORS,
     357        12936 :                          bb, gimple_bb (other_store)))
     358              :     return vuse;
     359              : 
     360              :   return NULL_TREE;
     361              : }
     362              : 
     363              : /* Propagate between the phi node arguments of PHI in BB and phi result
     364              :    users.  For now this matches
     365              :         # p_2 = PHI <&x, &y>
     366              :       <Lx>:;
     367              :         p_3 = p_2;
     368              :         z_2 = *p_3;
     369              :    and converts it to
     370              :         # z_2 = PHI <x, y>
     371              :       <Lx>:;
     372              :    Returns true if a transformation was done and edge insertions
     373              :    need to be committed.  Global data PHIVN and N is used to track
     374              :    past transformation results.  VPHI is the virtual PHI node in BB
     375              :    if there is one.  We need to be especially careful here
     376              :    with aliasing issues as we are moving memory reads.  */
     377              : 
     378              : static bool
     379      7619160 : propagate_with_phi (basic_block bb, gphi *vphi, gphi *phi,
     380              :                     struct phiprop_d *phivn, size_t n, bitmap dce_ssa_names)
     381              : {
     382      7619160 :   tree ptr = PHI_RESULT (phi);
     383      7619160 :   gimple *use_stmt;
     384      7619160 :   tree res = NULL_TREE;
     385      7619160 :   gimple_stmt_iterator gsi;
     386      7619160 :   imm_use_iterator ui;
     387      7619160 :   use_operand_p arg_p, use;
     388      7619160 :   ssa_op_iter i;
     389      7619160 :   bool phi_inserted;
     390      7619160 :   bool changed;
     391      7619160 :   tree type = NULL_TREE;
     392              : 
     393     14524331 :   if (!POINTER_TYPE_P (TREE_TYPE (ptr))
     394      7644078 :       || (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr)))
     395       350519 :           && TYPE_MODE (TREE_TYPE (TREE_TYPE (ptr))) == BLKmode))
     396      7138128 :     return false;
     397              : 
     398       481032 :   tree up_vuse = NULL_TREE;
     399       481032 :   bool canpossible_trap = false;
     400              :   /* Check if we can "cheaply" dereference all phi arguments.  */
     401       589103 :   FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_USE)
     402              :     {
     403       560262 :       tree arg = USE_FROM_PTR (arg_p);
     404              :       /* Walk the ssa chain until we reach a ssa name we already
     405              :          created a value for or we reach a definition of the form
     406              :          ssa_name_n = &var;  */
     407       560262 :       while (TREE_CODE (arg) == SSA_NAME
     408       464457 :              && !SSA_NAME_IS_DEFAULT_DEF (arg)
     409      1179938 :              && (SSA_NAME_VERSION (arg) >= n
     410       410954 :                  || phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE))
     411              :         {
     412       410847 :           gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
     413       410847 :           if (!gimple_assign_single_p (def_stmt))
     414              :             return false;
     415       208712 :           arg = gimple_assign_rhs1 (def_stmt);
     416              :         }
     417       358127 :       if (TREE_CODE (arg) == ADDR_EXPR)
     418              :         {
     419       107955 :           tree decl = TREE_OPERAND (arg, 0);
     420       107955 :           if (!canpossible_trap)
     421       105082 :             canpossible_trap = tree_could_trap_p (decl);
     422              :         }
     423              :       /* When we have an SSA name see if we previously encountered a
     424              :          dereference of it.  */
     425       250172 :       else if (TREE_CODE (arg) == SSA_NAME
     426        53610 :                && SSA_NAME_VERSION (arg) < n
     427        53610 :                && phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
     428       250289 :                && (!type
     429            3 :                    || types_compatible_p
     430            3 :                        (type, TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value))))
     431              :         {
     432              :           /* The dereference should be under the VUSE that's active in BB.
     433              :              If the BB has no virtual PHI then record the common "incoming"
     434              :              vuse.  */
     435          117 :           if (vphi)
     436            2 :             up_vuse = gimple_phi_arg_def (vphi, phi_arg_index_from_use (arg_p));
     437          117 :           if (!up_vuse)
     438          112 :             up_vuse = phivn[SSA_NAME_VERSION (arg)].vuse;
     439            5 :           else if (up_vuse != phivn[SSA_NAME_VERSION (arg)].vuse)
     440              :             return false;
     441              :         }
     442              :       else
     443       250055 :         return false;
     444       108071 :       if (!type
     445       108009 :           && TREE_CODE (arg) == SSA_NAME)
     446          113 :         type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value);
     447              :     }
     448              : 
     449              :   /* Find a dereferencing use.  First follow (single use) ssa
     450              :      copy chains for ptr.  */
     451        29937 :   while (single_imm_use (ptr, &use, &use_stmt)
     452        29937 :          && gimple_assign_ssa_name_copy_p (use_stmt))
     453         1096 :     ptr = gimple_assign_lhs (use_stmt);
     454              : 
     455              :   /* Replace the first dereference of *ptr if there is one and if we
     456              :      can move the loads to the place of the ptr phi node.  */
     457        28841 :   phi_inserted = false;
     458        28841 :   changed = false;
     459        28841 :   auto_vec<gimple*> delayed_uses;
     460        70614 :   FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
     461              :     {
     462        41773 :       bool delay = false;
     463              : 
     464              :       /* Check whether this is a load of *ptr.  */
     465        41773 :       if (!(is_gimple_assign (use_stmt)
     466        21574 :             && gimple_assign_rhs_code (use_stmt) == MEM_REF
     467        15103 :             && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
     468        15103 :             && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
     469        15087 :             && (!type
     470          119 :                 || types_compatible_p
     471          119 :                      (TREE_TYPE (gimple_assign_lhs (use_stmt)), type))
     472              :             /* We cannot replace a load that may throw or is volatile.
     473              :                For volatiles the transform can change the number of
     474              :                executions if the load is inside a loop but the address
     475              :                computations outside (PR91812).  We could relax this
     476              :                if we guard against that appropriately.  For loads that can
     477              :                throw we could relax things if the moved loads all are
     478              :                known to not throw.  */
     479        15087 :             && !stmt_can_throw_internal (cfun, use_stmt)
     480        29722 :             && !gimple_has_volatile_ops (use_stmt)))
     481        26924 :         continue;
     482              : 
     483        14849 :       bool aggregate = false;
     484        14849 :       if (!is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (use_stmt))))
     485          215 :         aggregate = true;
     486              : 
     487        14849 :       tree other_vuse;
     488        14849 :       other_vuse = can_handle_load (use_stmt, bb, vphi, up_vuse, aggregate);
     489        14849 :       if (!other_vuse)
     490          544 :         continue;
     491              : 
     492        14305 :       if ((canpossible_trap || aggregate)
     493        14305 :           && !dom_info_available_p (cfun, CDI_POST_DOMINATORS))
     494          551 :         calculate_dominance_info (CDI_POST_DOMINATORS);
     495              : 
     496              :       /* Only replace loads in blocks that post-dominate the PHI node.  That
     497              :          makes sure we don't end up speculating trapping loads or
     498              :          aggregate stores won't happen speculating.  */
     499        14305 :       if ((canpossible_trap || aggregate)
     500        14305 :           && !dominated_by_p (CDI_POST_DOMINATORS,
     501         2392 :                               bb, gimple_bb (use_stmt)))
     502              :         delay = true;
     503              : 
     504              :       /* Amend the post-dominance check for SSA cycles, we need to
     505              :          make sure each PHI result value is dereferenced.
     506              :          We only want to delay this if we don't insert a phi.  */
     507        14305 :       if (!(gimple_bb (use_stmt) == bb
     508          297 :             || (!(bb->flags & BB_IRREDUCIBLE_LOOP)
     509          297 :                 && !(gimple_bb (use_stmt)->flags & BB_IRREDUCIBLE_LOOP)
     510          297 :                 && (bb->loop_father == gimple_bb (use_stmt)->loop_father
     511           89 :                     || flow_loop_nested_p (bb->loop_father,
     512           89 :                                            gimple_bb (use_stmt)->loop_father)))))
     513              :         delay = true;
     514              : 
     515              :       /* Found a proper dereference with an aggregate copy.  Just
     516              :          insert aggregate copies on the edges instead.  */
     517        14305 :       if (aggregate)
     518              :         {
     519              :           /* aggregate copies are too hard to handled if delayed.  */
     520          195 :           if (delay)
     521           48 :             goto next;
     522          358 :           if (!gimple_vdef (use_stmt))
     523            0 :             goto next;
     524              : 
     525              :           /* As we replicate the lhs on each incoming edge all
     526              :              used SSA names have to be available there.  */
     527          179 :           if (! for_each_index (gimple_assign_lhs_ptr (use_stmt),
     528              :                                 chk_uses,
     529          179 :                                 get_immediate_dominator (CDI_DOMINATORS,
     530              :                                                          gimple_bb (phi))))
     531           18 :             goto next;
     532              : 
     533          161 :           gimple *vuse_stmt;
     534          161 :           imm_use_iterator vui;
     535          161 :           use_operand_p vuse_p;
     536          161 :           tree vuse = gimple_vuse (use_stmt);
     537              :           /* In order to move the aggregate copies earlier, make sure
     538              :              there are no statements that could read from memory
     539              :              aliasing the lhs in between the start of bb and use_stmt.
     540              :              As we require use_stmt to have a VDEF above, loads after
     541              :              use_stmt will use a different virtual SSA_NAME.  When
     542              :              we reach an edge inserted load the constraints we place
     543              :              on processing guarantees that program order is preserved
     544              :              so we can avoid checking those.  */
     545          971 :           FOR_EACH_IMM_USE_FAST (vuse_p, vui, vuse)
     546              :             {
     547          663 :               vuse_stmt = USE_STMT (vuse_p);
     548          663 :               if (vuse_stmt == use_stmt)
     549          155 :                 continue;
     550          508 :               if (!gimple_bb (vuse_stmt)
     551          992 :                   || !dominated_by_p (CDI_DOMINATORS,
     552          484 :                                       gimple_bb (vuse_stmt), bb))
     553          494 :                 continue;
     554           14 :               if (ref_maybe_used_by_stmt_p (vuse_stmt,
     555              :                                             gimple_assign_lhs (use_stmt)))
     556           14 :                 goto next;
     557           14 :             }
     558              : 
     559          147 :           phiprop_insert_phi (bb, phi, use_stmt, phivn, n,
     560              :                               dce_ssa_names, other_vuse);
     561              : 
     562              :           /* Remove old stmt. The phi and all of maybe its depedencies
     563              :              will be removed later via simple_dce_from_worklist. */
     564          147 :           gsi = gsi_for_stmt (use_stmt);
     565              :           /* Unlinking the VDEF here is fine as we are sure that we process
     566              :              stmts in execution order due to aggregate copies having VDEFs
     567              :              and we emit loads on the edges in the very same order.
     568              :              We get multiple copies (or intermediate register loads) handled
     569              :              only by walking PHIs or immediate uses in a lucky order though,
     570              :              so we could signal the caller to re-start iterating over PHIs
     571              :              when we come here which would make it quadratic in the number
     572              :              of PHIs.  */
     573          147 :           unlink_stmt_vdef (use_stmt);
     574          147 :           gsi_remove (&gsi, true);
     575              : 
     576          147 :           changed = true;
     577              :         }
     578              :       /* Further replacements are easy, just make a copy out of the
     579              :          load.  */
     580        14110 :       else if (phi_inserted)
     581              :         {
     582            0 :           gimple_assign_set_rhs1 (use_stmt, res);
     583            0 :           update_stmt (use_stmt);
     584            0 :           changed = true;
     585              :         }
     586        14110 :       else if (delay)
     587          275 :         delayed_uses.safe_push (use_stmt);
     588              :       /* Found a proper dereference.  Insert a phi node if this
     589              :          is the first load transformation.  */
     590              :       else
     591              :         {
     592        13835 :           tree vuse = gimple_vuse (use_stmt);
     593        13835 :           res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n,
     594              :                                     dce_ssa_names, other_vuse);
     595        13835 :           type = TREE_TYPE (res);
     596              : 
     597              :           /* Remember the value we created for *ptr.  */
     598        13835 :           phivn[SSA_NAME_VERSION (ptr)].value = res;
     599        13835 :           phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
     600              : 
     601              :           /* Remove old stmt.  The phi and all of maybe its depedencies
     602              :              will be removed later via simple_dce_from_worklist. */
     603        13835 :           gsi = gsi_for_stmt (use_stmt);
     604        13835 :           gsi_remove (&gsi, true);
     605              : 
     606        13835 :           phi_inserted = true;
     607        13835 :           changed = true;
     608              :         }
     609              : 
     610        41773 : next:;
     611              :       /* Continue searching for a proper dereference.  */
     612        28841 :     }
     613              : 
     614              :   /* Update the delayed uses if there is any
     615              :      as now we know this is safe to do. */
     616        28841 :   if (phi_inserted)
     617        14375 :     for (auto use_stmt : delayed_uses)
     618              :       {
     619              :         /* The types must match of the inserted phi.  */
     620          250 :         if (!types_compatible_p (type, TREE_TYPE (gimple_assign_lhs (use_stmt))))
     621            6 :           continue;
     622          244 :         gimple_assign_set_rhs1 (use_stmt, res);
     623          244 :         update_stmt (use_stmt);
     624              :       }
     625              : 
     626        28841 :   return changed;
     627        28841 : }
     628              : 
     629              : /* Main entry for phiprop pass.  */
     630              : 
     631              : namespace {
     632              : 
     633              : const pass_data pass_data_phiprop =
     634              : {
     635              :   GIMPLE_PASS, /* type */
     636              :   "phiprop", /* name */
     637              :   OPTGROUP_NONE, /* optinfo_flags */
     638              :   TV_TREE_PHIPROP, /* tv_id */
     639              :   ( PROP_cfg | PROP_ssa ), /* properties_required */
     640              :   0, /* properties_provided */
     641              :   0, /* properties_destroyed */
     642              :   0, /* todo_flags_start */
     643              :   0, /* todo_flags_finish */
     644              : };
     645              : 
     646              : class pass_phiprop : public gimple_opt_pass
     647              : {
     648              : public:
     649       577534 :   pass_phiprop (gcc::context *ctxt)
     650      1155068 :     : gimple_opt_pass (pass_data_phiprop, ctxt)
     651              :   {}
     652              : 
     653              :   /* opt_pass methods: */
     654       288767 :   opt_pass * clone () final override { return new pass_phiprop (m_ctxt); }
     655      3479629 :   bool gate (function *) final override { return flag_tree_phiprop; }
     656              :   unsigned int execute (function *) final override;
     657              : 
     658              : }; // class pass_phiprop
     659              : 
     660              : unsigned int
     661      3479418 : pass_phiprop::execute (function *fun)
     662              : {
     663      3479418 :   struct phiprop_d *phivn;
     664      3479418 :   bool did_something = false;
     665      3479418 :   basic_block bb;
     666      3479418 :   gphi_iterator gsi;
     667      3479418 :   unsigned i;
     668      3479418 :   size_t n;
     669      3479418 :   auto_bitmap dce_ssa_names;
     670              : 
     671      3479418 :   calculate_dominance_info (CDI_DOMINATORS);
     672              : 
     673      3479418 :   n = num_ssa_names;
     674      3479418 :   phivn = XCNEWVEC (struct phiprop_d, n);
     675              : 
     676              :   /* Walk the dominator tree in preorder.  */
     677      3479418 :   auto_vec<basic_block> bbs
     678              :   = get_all_dominated_blocks (CDI_DOMINATORS,
     679      3479418 :                               single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
     680     28570091 :   FOR_EACH_VEC_ELT (bbs, i, bb)
     681              :     {
     682              :       /* Since we're going to move dereferences across predecessor
     683              :          edges avoid blocks with abnormal predecessors.  */
     684     25090673 :       if (bb_has_abnormal_pred (bb))
     685         8653 :         continue;
     686     25082020 :       gphi *vphi = get_virtual_phi (bb);
     687     32701180 :       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     688      7619160 :         did_something |= propagate_with_phi (bb, vphi, gsi.phi (),
     689              :                                              phivn, n, dce_ssa_names);
     690              :     }
     691              : 
     692      3479418 :   if (did_something)
     693              :     {
     694        11603 :       gsi_commit_edge_inserts ();
     695        11603 :       simple_dce_from_worklist (dce_ssa_names);
     696              :     }
     697              : 
     698      3479418 :   free (phivn);
     699              : 
     700      3479418 :   free_dominance_info (CDI_POST_DOMINATORS);
     701              : 
     702      3479418 :   return did_something ? TODO_update_ssa_only_virtuals : 0;
     703      3479418 : }
     704              : 
     705              : } // anon namespace
     706              : 
     707              : gimple_opt_pass *
     708       288767 : make_pass_phiprop (gcc::context *ctxt)
     709              : {
     710       288767 :   return new pass_phiprop (ctxt);
     711              : }
        

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.