| 1 | 684 | jeremybenn | /* Optimization of PHI nodes by converting them into straightline code.
 | 
      
         | 2 |  |  |    Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
 | 
      
         | 3 |  |  |    Free Software Foundation, Inc.
 | 
      
         | 4 |  |  |  
 | 
      
         | 5 |  |  | This file is part of GCC.
 | 
      
         | 6 |  |  |  
 | 
      
         | 7 |  |  | GCC is free software; you can redistribute it and/or modify it
 | 
      
         | 8 |  |  | under the terms of the GNU General Public License as published by the
 | 
      
         | 9 |  |  | Free Software Foundation; either version 3, or (at your option) any
 | 
      
         | 10 |  |  | later version.
 | 
      
         | 11 |  |  |  
 | 
      
         | 12 |  |  | GCC is distributed in the hope that it will be useful, but WITHOUT
 | 
      
         | 13 |  |  | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
      
         | 14 |  |  | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 | 
      
         | 15 |  |  | 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 "tm.h"
 | 
      
         | 25 |  |  | #include "ggc.h"
 | 
      
         | 26 |  |  | #include "tree.h"
 | 
      
         | 27 |  |  | #include "flags.h"
 | 
      
         | 28 |  |  | #include "tm_p.h"
 | 
      
         | 29 |  |  | #include "basic-block.h"
 | 
      
         | 30 |  |  | #include "timevar.h"
 | 
      
         | 31 |  |  | #include "tree-flow.h"
 | 
      
         | 32 |  |  | #include "tree-pass.h"
 | 
      
         | 33 |  |  | #include "tree-dump.h"
 | 
      
         | 34 |  |  | #include "langhooks.h"
 | 
      
         | 35 |  |  | #include "pointer-set.h"
 | 
      
         | 36 |  |  | #include "domwalk.h"
 | 
      
         | 37 |  |  | #include "cfgloop.h"
 | 
      
         | 38 |  |  | #include "tree-data-ref.h"
 | 
      
         | 39 |  |  |  
 | 
      
         | 40 |  |  | static unsigned int tree_ssa_phiopt (void);
 | 
      
         | 41 |  |  | static unsigned int tree_ssa_phiopt_worker (bool);
 | 
      
         | 42 |  |  | static bool conditional_replacement (basic_block, basic_block,
 | 
      
         | 43 |  |  |                                      edge, edge, gimple, tree, tree);
 | 
      
         | 44 |  |  | static bool value_replacement (basic_block, basic_block,
 | 
      
         | 45 |  |  |                                edge, edge, gimple, tree, tree);
 | 
      
         | 46 |  |  | static bool minmax_replacement (basic_block, basic_block,
 | 
      
         | 47 |  |  |                                 edge, edge, gimple, tree, tree);
 | 
      
         | 48 |  |  | static bool abs_replacement (basic_block, basic_block,
 | 
      
         | 49 |  |  |                              edge, edge, gimple, tree, tree);
 | 
      
         | 50 |  |  | static bool cond_store_replacement (basic_block, basic_block, edge, edge,
 | 
      
         | 51 |  |  |                                     struct pointer_set_t *);
 | 
      
         | 52 |  |  | static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block);
 | 
      
         | 53 |  |  | static struct pointer_set_t * get_non_trapping (void);
 | 
      
         | 54 |  |  | static void replace_phi_edge_with_variable (basic_block, edge, gimple, tree);
 | 
      
         | 55 |  |  |  
 | 
      
         | 56 |  |  | /* This pass tries to replaces an if-then-else block with an
 | 
      
         | 57 |  |  |    assignment.  We have four kinds of transformations.  Some of these
 | 
      
         | 58 |  |  |    transformations are also performed by the ifcvt RTL optimizer.
 | 
      
         | 59 |  |  |  
 | 
      
         | 60 |  |  |    Conditional Replacement
 | 
      
         | 61 |  |  |    -----------------------
 | 
      
         | 62 |  |  |  
 | 
      
         | 63 |  |  |    This transformation, implemented in conditional_replacement,
 | 
      
         | 64 |  |  |    replaces
 | 
      
         | 65 |  |  |  
 | 
      
         | 66 |  |  |      bb0:
 | 
      
         | 67 |  |  |       if (cond) goto bb2; else goto bb1;
 | 
      
         | 68 |  |  |      bb1:
 | 
      
         | 69 |  |  |      bb2:
 | 
      
         | 70 |  |  |       x = PHI <0 (bb1), 1 (bb0), ...>;
 | 
      
         | 71 |  |  |  
 | 
      
         | 72 |  |  |    with
 | 
      
         | 73 |  |  |  
 | 
      
         | 74 |  |  |      bb0:
 | 
      
         | 75 |  |  |       x' = cond;
 | 
      
         | 76 |  |  |       goto bb2;
 | 
      
         | 77 |  |  |      bb2:
 | 
      
         | 78 |  |  |       x = PHI <x' (bb0), ...>;
 | 
      
         | 79 |  |  |  
 | 
      
         | 80 |  |  |    We remove bb1 as it becomes unreachable.  This occurs often due to
 | 
      
         | 81 |  |  |    gimplification of conditionals.
 | 
      
         | 82 |  |  |  
 | 
      
         | 83 |  |  |    Value Replacement
 | 
      
         | 84 |  |  |    -----------------
 | 
      
         | 85 |  |  |  
 | 
      
         | 86 |  |  |    This transformation, implemented in value_replacement, replaces
 | 
      
         | 87 |  |  |  
 | 
      
         | 88 |  |  |      bb0:
 | 
      
         | 89 |  |  |        if (a != b) goto bb2; else goto bb1;
 | 
      
         | 90 |  |  |      bb1:
 | 
      
         | 91 |  |  |      bb2:
 | 
      
         | 92 |  |  |        x = PHI <a (bb1), b (bb0), ...>;
 | 
      
         | 93 |  |  |  
 | 
      
         | 94 |  |  |    with
 | 
      
         | 95 |  |  |  
 | 
      
         | 96 |  |  |      bb0:
 | 
      
         | 97 |  |  |      bb2:
 | 
      
         | 98 |  |  |        x = PHI <b (bb0), ...>;
 | 
      
         | 99 |  |  |  
 | 
      
         | 100 |  |  |    This opportunity can sometimes occur as a result of other
 | 
      
         | 101 |  |  |    optimizations.
 | 
      
         | 102 |  |  |  
 | 
      
         | 103 |  |  |    ABS Replacement
 | 
      
         | 104 |  |  |    ---------------
 | 
      
         | 105 |  |  |  
 | 
      
         | 106 |  |  |    This transformation, implemented in abs_replacement, replaces
 | 
      
         | 107 |  |  |  
 | 
      
         | 108 |  |  |      bb0:
 | 
      
         | 109 |  |  |        if (a >= 0) goto bb2; else goto bb1;
 | 
      
         | 110 |  |  |      bb1:
 | 
      
         | 111 |  |  |        x = -a;
 | 
      
         | 112 |  |  |      bb2:
 | 
      
         | 113 |  |  |        x = PHI <x (bb1), a (bb0), ...>;
 | 
      
         | 114 |  |  |  
 | 
      
         | 115 |  |  |    with
 | 
      
         | 116 |  |  |  
 | 
      
         | 117 |  |  |      bb0:
 | 
      
         | 118 |  |  |        x' = ABS_EXPR< a >;
 | 
      
         | 119 |  |  |      bb2:
 | 
      
         | 120 |  |  |        x = PHI <x' (bb0), ...>;
 | 
      
         | 121 |  |  |  
 | 
      
         | 122 |  |  |    MIN/MAX Replacement
 | 
      
         | 123 |  |  |    -------------------
 | 
      
         | 124 |  |  |  
 | 
      
         | 125 |  |  |    This transformation, minmax_replacement replaces
 | 
      
         | 126 |  |  |  
 | 
      
         | 127 |  |  |      bb0:
 | 
      
         | 128 |  |  |        if (a <= b) goto bb2; else goto bb1;
 | 
      
         | 129 |  |  |      bb1:
 | 
      
         | 130 |  |  |      bb2:
 | 
      
         | 131 |  |  |        x = PHI <b (bb1), a (bb0), ...>;
 | 
      
         | 132 |  |  |  
 | 
      
         | 133 |  |  |    with
 | 
      
         | 134 |  |  |  
 | 
      
         | 135 |  |  |      bb0:
 | 
      
         | 136 |  |  |        x' = MIN_EXPR (a, b)
 | 
      
         | 137 |  |  |      bb2:
 | 
      
         | 138 |  |  |        x = PHI <x' (bb0), ...>;
 | 
      
         | 139 |  |  |  
 | 
      
         | 140 |  |  |    A similar transformation is done for MAX_EXPR.  */
 | 
      
         | 141 |  |  |  
 | 
      
         | 142 |  |  | static unsigned int
 | 
      
         | 143 |  |  | tree_ssa_phiopt (void)
 | 
      
         | 144 |  |  | {
 | 
      
         | 145 |  |  |   return tree_ssa_phiopt_worker (false);
 | 
      
         | 146 |  |  | }
 | 
      
         | 147 |  |  |  
 | 
      
         | 148 |  |  | /* This pass tries to transform conditional stores into unconditional
 | 
      
         | 149 |  |  |    ones, enabling further simplifications with the simpler then and else
 | 
      
         | 150 |  |  |    blocks.  In particular it replaces this:
 | 
      
         | 151 |  |  |  
 | 
      
         | 152 |  |  |      bb0:
 | 
      
         | 153 |  |  |        if (cond) goto bb2; else goto bb1;
 | 
      
         | 154 |  |  |      bb1:
 | 
      
         | 155 |  |  |        *p = RHS;
 | 
      
         | 156 |  |  |      bb2:
 | 
      
         | 157 |  |  |  
 | 
      
         | 158 |  |  |    with
 | 
      
         | 159 |  |  |  
 | 
      
         | 160 |  |  |      bb0:
 | 
      
         | 161 |  |  |        if (cond) goto bb1; else goto bb2;
 | 
      
         | 162 |  |  |      bb1:
 | 
      
         | 163 |  |  |        condtmp' = *p;
 | 
      
         | 164 |  |  |      bb2:
 | 
      
         | 165 |  |  |        condtmp = PHI <RHS, condtmp'>
 | 
      
         | 166 |  |  |        *p = condtmp;
 | 
      
         | 167 |  |  |  
 | 
      
         | 168 |  |  |    This transformation can only be done under several constraints,
 | 
      
         | 169 |  |  |    documented below.  It also replaces:
 | 
      
         | 170 |  |  |  
 | 
      
         | 171 |  |  |      bb0:
 | 
      
         | 172 |  |  |        if (cond) goto bb2; else goto bb1;
 | 
      
         | 173 |  |  |      bb1:
 | 
      
         | 174 |  |  |        *p = RHS1;
 | 
      
         | 175 |  |  |        goto bb3;
 | 
      
         | 176 |  |  |      bb2:
 | 
      
         | 177 |  |  |        *p = RHS2;
 | 
      
         | 178 |  |  |      bb3:
 | 
      
         | 179 |  |  |  
 | 
      
         | 180 |  |  |    with
 | 
      
         | 181 |  |  |  
 | 
      
         | 182 |  |  |      bb0:
 | 
      
         | 183 |  |  |        if (cond) goto bb3; else goto bb1;
 | 
      
         | 184 |  |  |      bb1:
 | 
      
         | 185 |  |  |      bb3:
 | 
      
         | 186 |  |  |        condtmp = PHI <RHS1, RHS2>
 | 
      
         | 187 |  |  |        *p = condtmp;  */
 | 
      
         | 188 |  |  |  
 | 
      
         | 189 |  |  | static unsigned int
 | 
      
         | 190 |  |  | tree_ssa_cs_elim (void)
 | 
      
         | 191 |  |  | {
 | 
      
         | 192 |  |  |   return tree_ssa_phiopt_worker (true);
 | 
      
         | 193 |  |  | }
 | 
      
         | 194 |  |  |  
 | 
      
         | 195 |  |  | /* For conditional store replacement we need a temporary to
 | 
      
         | 196 |  |  |    put the old contents of the memory in.  */
 | 
      
         | 197 |  |  | static tree condstoretemp;
 | 
      
         | 198 |  |  |  
 | 
      
         | 199 |  |  | /* The core routine of conditional store replacement and normal
 | 
      
         | 200 |  |  |    phi optimizations.  Both share much of the infrastructure in how
 | 
      
         | 201 |  |  |    to match applicable basic block patterns.  DO_STORE_ELIM is true
 | 
      
         | 202 |  |  |    when we want to do conditional store replacement, false otherwise.  */
 | 
      
         | 203 |  |  | static unsigned int
 | 
      
         | 204 |  |  | tree_ssa_phiopt_worker (bool do_store_elim)
 | 
      
         | 205 |  |  | {
 | 
      
         | 206 |  |  |   basic_block bb;
 | 
      
         | 207 |  |  |   basic_block *bb_order;
 | 
      
         | 208 |  |  |   unsigned n, i;
 | 
      
         | 209 |  |  |   bool cfgchanged = false;
 | 
      
         | 210 |  |  |   struct pointer_set_t *nontrap = 0;
 | 
      
         | 211 |  |  |  
 | 
      
         | 212 |  |  |   if (do_store_elim)
 | 
      
         | 213 |  |  |     {
 | 
      
         | 214 |  |  |       condstoretemp = NULL_TREE;
 | 
      
         | 215 |  |  |       /* Calculate the set of non-trapping memory accesses.  */
 | 
      
         | 216 |  |  |       nontrap = get_non_trapping ();
 | 
      
         | 217 |  |  |     }
 | 
      
         | 218 |  |  |  
 | 
      
         | 219 |  |  |   /* Search every basic block for COND_EXPR we may be able to optimize.
 | 
      
         | 220 |  |  |  
 | 
      
         | 221 |  |  |      We walk the blocks in order that guarantees that a block with
 | 
      
         | 222 |  |  |      a single predecessor is processed before the predecessor.
 | 
      
         | 223 |  |  |      This ensures that we collapse inner ifs before visiting the
 | 
      
         | 224 |  |  |      outer ones, and also that we do not try to visit a removed
 | 
      
         | 225 |  |  |      block.  */
 | 
      
         | 226 |  |  |   bb_order = blocks_in_phiopt_order ();
 | 
      
         | 227 |  |  |   n = n_basic_blocks - NUM_FIXED_BLOCKS;
 | 
      
         | 228 |  |  |  
 | 
      
         | 229 |  |  |   for (i = 0; i < n; i++)
 | 
      
         | 230 |  |  |     {
 | 
      
         | 231 |  |  |       gimple cond_stmt, phi;
 | 
      
         | 232 |  |  |       basic_block bb1, bb2;
 | 
      
         | 233 |  |  |       edge e1, e2;
 | 
      
         | 234 |  |  |       tree arg0, arg1;
 | 
      
         | 235 |  |  |  
 | 
      
         | 236 |  |  |       bb = bb_order[i];
 | 
      
         | 237 |  |  |  
 | 
      
         | 238 |  |  |       cond_stmt = last_stmt (bb);
 | 
      
         | 239 |  |  |       /* Check to see if the last statement is a GIMPLE_COND.  */
 | 
      
         | 240 |  |  |       if (!cond_stmt
 | 
      
         | 241 |  |  |           || gimple_code (cond_stmt) != GIMPLE_COND)
 | 
      
         | 242 |  |  |         continue;
 | 
      
         | 243 |  |  |  
 | 
      
         | 244 |  |  |       e1 = EDGE_SUCC (bb, 0);
 | 
      
         | 245 |  |  |       bb1 = e1->dest;
 | 
      
         | 246 |  |  |       e2 = EDGE_SUCC (bb, 1);
 | 
      
         | 247 |  |  |       bb2 = e2->dest;
 | 
      
         | 248 |  |  |  
 | 
      
         | 249 |  |  |       /* We cannot do the optimization on abnormal edges.  */
 | 
      
         | 250 |  |  |       if ((e1->flags & EDGE_ABNORMAL) != 0
 | 
      
         | 251 |  |  |           || (e2->flags & EDGE_ABNORMAL) != 0)
 | 
      
         | 252 |  |  |        continue;
 | 
      
         | 253 |  |  |  
 | 
      
         | 254 |  |  |       /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
 | 
      
         | 255 |  |  |       if (EDGE_COUNT (bb1->succs) == 0
 | 
      
         | 256 |  |  |           || bb2 == NULL
 | 
      
         | 257 |  |  |           || EDGE_COUNT (bb2->succs) == 0)
 | 
      
         | 258 |  |  |         continue;
 | 
      
         | 259 |  |  |  
 | 
      
         | 260 |  |  |       /* Find the bb which is the fall through to the other.  */
 | 
      
         | 261 |  |  |       if (EDGE_SUCC (bb1, 0)->dest == bb2)
 | 
      
         | 262 |  |  |         ;
 | 
      
         | 263 |  |  |       else if (EDGE_SUCC (bb2, 0)->dest == bb1)
 | 
      
         | 264 |  |  |         {
 | 
      
         | 265 |  |  |           basic_block bb_tmp = bb1;
 | 
      
         | 266 |  |  |           edge e_tmp = e1;
 | 
      
         | 267 |  |  |           bb1 = bb2;
 | 
      
         | 268 |  |  |           bb2 = bb_tmp;
 | 
      
         | 269 |  |  |           e1 = e2;
 | 
      
         | 270 |  |  |           e2 = e_tmp;
 | 
      
         | 271 |  |  |         }
 | 
      
         | 272 |  |  |       else if (do_store_elim
 | 
      
         | 273 |  |  |                && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
 | 
      
         | 274 |  |  |         {
 | 
      
         | 275 |  |  |           basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;
 | 
      
         | 276 |  |  |  
 | 
      
         | 277 |  |  |           if (!single_succ_p (bb1)
 | 
      
         | 278 |  |  |               || (EDGE_SUCC (bb1, 0)->flags & EDGE_FALLTHRU) == 0
 | 
      
         | 279 |  |  |               || !single_succ_p (bb2)
 | 
      
         | 280 |  |  |               || (EDGE_SUCC (bb2, 0)->flags & EDGE_FALLTHRU) == 0
 | 
      
         | 281 |  |  |               || EDGE_COUNT (bb3->preds) != 2)
 | 
      
         | 282 |  |  |             continue;
 | 
      
         | 283 |  |  |           if (cond_if_else_store_replacement (bb1, bb2, bb3))
 | 
      
         | 284 |  |  |             cfgchanged = true;
 | 
      
         | 285 |  |  |           continue;
 | 
      
         | 286 |  |  |         }
 | 
      
         | 287 |  |  |       else
 | 
      
         | 288 |  |  |         continue;
 | 
      
         | 289 |  |  |  
 | 
      
         | 290 |  |  |       e1 = EDGE_SUCC (bb1, 0);
 | 
      
         | 291 |  |  |  
 | 
      
         | 292 |  |  |       /* Make sure that bb1 is just a fall through.  */
 | 
      
         | 293 |  |  |       if (!single_succ_p (bb1)
 | 
      
         | 294 |  |  |           || (e1->flags & EDGE_FALLTHRU) == 0)
 | 
      
         | 295 |  |  |         continue;
 | 
      
         | 296 |  |  |  
 | 
      
         | 297 |  |  |       /* Also make sure that bb1 only have one predecessor and that it
 | 
      
         | 298 |  |  |          is bb.  */
 | 
      
         | 299 |  |  |       if (!single_pred_p (bb1)
 | 
      
         | 300 |  |  |           || single_pred (bb1) != bb)
 | 
      
         | 301 |  |  |         continue;
 | 
      
         | 302 |  |  |  
 | 
      
         | 303 |  |  |       if (do_store_elim)
 | 
      
         | 304 |  |  |         {
 | 
      
         | 305 |  |  |           /* bb1 is the middle block, bb2 the join block, bb the split block,
 | 
      
         | 306 |  |  |              e1 the fallthrough edge from bb1 to bb2.  We can't do the
 | 
      
         | 307 |  |  |              optimization if the join block has more than two predecessors.  */
 | 
      
         | 308 |  |  |           if (EDGE_COUNT (bb2->preds) > 2)
 | 
      
         | 309 |  |  |             continue;
 | 
      
         | 310 |  |  |           if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
 | 
      
         | 311 |  |  |             cfgchanged = true;
 | 
      
         | 312 |  |  |         }
 | 
      
         | 313 |  |  |       else
 | 
      
         | 314 |  |  |         {
 | 
      
         | 315 |  |  |           gimple_seq phis = phi_nodes (bb2);
 | 
      
         | 316 |  |  |           gimple_stmt_iterator gsi;
 | 
      
         | 317 |  |  |  
 | 
      
         | 318 |  |  |           /* Check to make sure that there is only one non-virtual PHI node.
 | 
      
         | 319 |  |  |              TODO: we could do it with more than one iff the other PHI nodes
 | 
      
         | 320 |  |  |              have the same elements for these two edges.  */
 | 
      
         | 321 |  |  |           phi = NULL;
 | 
      
         | 322 |  |  |           for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
 | 
      
         | 323 |  |  |             {
 | 
      
         | 324 |  |  |               if (!is_gimple_reg (gimple_phi_result (gsi_stmt (gsi))))
 | 
      
         | 325 |  |  |                 continue;
 | 
      
         | 326 |  |  |               if (phi)
 | 
      
         | 327 |  |  |                 {
 | 
      
         | 328 |  |  |                   phi = NULL;
 | 
      
         | 329 |  |  |                   break;
 | 
      
         | 330 |  |  |                 }
 | 
      
         | 331 |  |  |               phi = gsi_stmt (gsi);
 | 
      
         | 332 |  |  |             }
 | 
      
         | 333 |  |  |           if (!phi)
 | 
      
         | 334 |  |  |             continue;
 | 
      
         | 335 |  |  |  
 | 
      
         | 336 |  |  |           arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
 | 
      
         | 337 |  |  |           arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
 | 
      
         | 338 |  |  |  
 | 
      
         | 339 |  |  |           /* Something is wrong if we cannot find the arguments in the PHI
 | 
      
         | 340 |  |  |              node.  */
 | 
      
         | 341 |  |  |           gcc_assert (arg0 != NULL && arg1 != NULL);
 | 
      
         | 342 |  |  |  
 | 
      
         | 343 |  |  |           /* Do the replacement of conditional if it can be done.  */
 | 
      
         | 344 |  |  |           if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
 | 
      
         | 345 |  |  |             cfgchanged = true;
 | 
      
         | 346 |  |  |           else if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
 | 
      
         | 347 |  |  |             cfgchanged = true;
 | 
      
         | 348 |  |  |           else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
 | 
      
         | 349 |  |  |             cfgchanged = true;
 | 
      
         | 350 |  |  |           else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
 | 
      
         | 351 |  |  |             cfgchanged = true;
 | 
      
         | 352 |  |  |         }
 | 
      
         | 353 |  |  |     }
 | 
      
         | 354 |  |  |  
 | 
      
         | 355 |  |  |   free (bb_order);
 | 
      
         | 356 |  |  |  
 | 
      
         | 357 |  |  |   if (do_store_elim)
 | 
      
         | 358 |  |  |     pointer_set_destroy (nontrap);
 | 
      
         | 359 |  |  |   /* If the CFG has changed, we should cleanup the CFG.  */
 | 
      
         | 360 |  |  |   if (cfgchanged && do_store_elim)
 | 
      
         | 361 |  |  |     {
 | 
      
         | 362 |  |  |       /* In cond-store replacement we have added some loads on edges
 | 
      
         | 363 |  |  |          and new VOPS (as we moved the store, and created a load).  */
 | 
      
         | 364 |  |  |       gsi_commit_edge_inserts ();
 | 
      
         | 365 |  |  |       return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
 | 
      
         | 366 |  |  |     }
 | 
      
         | 367 |  |  |   else if (cfgchanged)
 | 
      
         | 368 |  |  |     return TODO_cleanup_cfg;
 | 
      
         | 369 |  |  |   return 0;
 | 
      
         | 370 |  |  | }
 | 
      
         | 371 |  |  |  
 | 
      
         | 372 |  |  | /* Returns the list of basic blocks in the function in an order that guarantees
 | 
      
         | 373 |  |  |    that if a block X has just a single predecessor Y, then Y is after X in the
 | 
      
         | 374 |  |  |    ordering.  */
 | 
      
         | 375 |  |  |  
 | 
      
         | 376 |  |  | basic_block *
 | 
      
         | 377 |  |  | blocks_in_phiopt_order (void)
 | 
      
         | 378 |  |  | {
 | 
      
         | 379 |  |  |   basic_block x, y;
 | 
      
         | 380 |  |  |   basic_block *order = XNEWVEC (basic_block, n_basic_blocks);
 | 
      
         | 381 |  |  |   unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS;
 | 
      
         | 382 |  |  |   unsigned np, i;
 | 
      
         | 383 |  |  |   sbitmap visited = sbitmap_alloc (last_basic_block);
 | 
      
         | 384 |  |  |  
 | 
      
         | 385 |  |  | #define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index))
 | 
      
         | 386 |  |  | #define VISITED_P(BB) (TEST_BIT (visited, (BB)->index))
 | 
      
         | 387 |  |  |  
 | 
      
         | 388 |  |  |   sbitmap_zero (visited);
 | 
      
         | 389 |  |  |  
 | 
      
         | 390 |  |  |   MARK_VISITED (ENTRY_BLOCK_PTR);
 | 
      
         | 391 |  |  |   FOR_EACH_BB (x)
 | 
      
         | 392 |  |  |     {
 | 
      
         | 393 |  |  |       if (VISITED_P (x))
 | 
      
         | 394 |  |  |         continue;
 | 
      
         | 395 |  |  |  
 | 
      
         | 396 |  |  |       /* Walk the predecessors of x as long as they have precisely one
 | 
      
         | 397 |  |  |          predecessor and add them to the list, so that they get stored
 | 
      
         | 398 |  |  |          after x.  */
 | 
      
         | 399 |  |  |       for (y = x, np = 1;
 | 
      
         | 400 |  |  |            single_pred_p (y) && !VISITED_P (single_pred (y));
 | 
      
         | 401 |  |  |            y = single_pred (y))
 | 
      
         | 402 |  |  |         np++;
 | 
      
         | 403 |  |  |       for (y = x, i = n - np;
 | 
      
         | 404 |  |  |            single_pred_p (y) && !VISITED_P (single_pred (y));
 | 
      
         | 405 |  |  |            y = single_pred (y), i++)
 | 
      
         | 406 |  |  |         {
 | 
      
         | 407 |  |  |           order[i] = y;
 | 
      
         | 408 |  |  |           MARK_VISITED (y);
 | 
      
         | 409 |  |  |         }
 | 
      
         | 410 |  |  |       order[i] = y;
 | 
      
         | 411 |  |  |       MARK_VISITED (y);
 | 
      
         | 412 |  |  |  
 | 
      
         | 413 |  |  |       gcc_assert (i == n - 1);
 | 
      
         | 414 |  |  |       n -= np;
 | 
      
         | 415 |  |  |     }
 | 
      
         | 416 |  |  |  
 | 
      
         | 417 |  |  |   sbitmap_free (visited);
 | 
      
         | 418 |  |  |   gcc_assert (n == 0);
 | 
      
         | 419 |  |  |   return order;
 | 
      
         | 420 |  |  |  
 | 
      
         | 421 |  |  | #undef MARK_VISITED
 | 
      
         | 422 |  |  | #undef VISITED_P
 | 
      
         | 423 |  |  | }
 | 
      
         | 424 |  |  |  
 | 
      
         | 425 |  |  |  
 | 
      
         | 426 |  |  | /* Return TRUE if block BB has no executable statements, otherwise return
 | 
      
         | 427 |  |  |    FALSE.  */
 | 
      
         | 428 |  |  |  
 | 
      
         | 429 |  |  | bool
 | 
      
         | 430 |  |  | empty_block_p (basic_block bb)
 | 
      
         | 431 |  |  | {
 | 
      
         | 432 |  |  |   /* BB must have no executable statements.  */
 | 
      
         | 433 |  |  |   gimple_stmt_iterator gsi = gsi_after_labels (bb);
 | 
      
         | 434 |  |  |   if (gsi_end_p (gsi))
 | 
      
         | 435 |  |  |     return true;
 | 
      
         | 436 |  |  |   if (is_gimple_debug (gsi_stmt (gsi)))
 | 
      
         | 437 |  |  |     gsi_next_nondebug (&gsi);
 | 
      
         | 438 |  |  |   return gsi_end_p (gsi);
 | 
      
         | 439 |  |  | }
 | 
      
         | 440 |  |  |  
 | 
      
         | 441 |  |  | /* Replace PHI node element whose edge is E in block BB with variable NEW.
 | 
      
         | 442 |  |  |    Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
 | 
      
         | 443 |  |  |    is known to have two edges, one of which must reach BB).  */
 | 
      
         | 444 |  |  |  
 | 
      
         | 445 |  |  | static void
 | 
      
         | 446 |  |  | replace_phi_edge_with_variable (basic_block cond_block,
 | 
      
         | 447 |  |  |                                 edge e, gimple phi, tree new_tree)
 | 
      
         | 448 |  |  | {
 | 
      
         | 449 |  |  |   basic_block bb = gimple_bb (phi);
 | 
      
         | 450 |  |  |   basic_block block_to_remove;
 | 
      
         | 451 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 452 |  |  |  
 | 
      
         | 453 |  |  |   /* Change the PHI argument to new.  */
 | 
      
         | 454 |  |  |   SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new_tree);
 | 
      
         | 455 |  |  |  
 | 
      
         | 456 |  |  |   /* Remove the empty basic block.  */
 | 
      
         | 457 |  |  |   if (EDGE_SUCC (cond_block, 0)->dest == bb)
 | 
      
         | 458 |  |  |     {
 | 
      
         | 459 |  |  |       EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU;
 | 
      
         | 460 |  |  |       EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
 | 
      
         | 461 |  |  |       EDGE_SUCC (cond_block, 0)->probability = REG_BR_PROB_BASE;
 | 
      
         | 462 |  |  |       EDGE_SUCC (cond_block, 0)->count += EDGE_SUCC (cond_block, 1)->count;
 | 
      
         | 463 |  |  |  
 | 
      
         | 464 |  |  |       block_to_remove = EDGE_SUCC (cond_block, 1)->dest;
 | 
      
         | 465 |  |  |     }
 | 
      
         | 466 |  |  |   else
 | 
      
         | 467 |  |  |     {
 | 
      
         | 468 |  |  |       EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU;
 | 
      
         | 469 |  |  |       EDGE_SUCC (cond_block, 1)->flags
 | 
      
         | 470 |  |  |         &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
 | 
      
         | 471 |  |  |       EDGE_SUCC (cond_block, 1)->probability = REG_BR_PROB_BASE;
 | 
      
         | 472 |  |  |       EDGE_SUCC (cond_block, 1)->count += EDGE_SUCC (cond_block, 0)->count;
 | 
      
         | 473 |  |  |  
 | 
      
         | 474 |  |  |       block_to_remove = EDGE_SUCC (cond_block, 0)->dest;
 | 
      
         | 475 |  |  |     }
 | 
      
         | 476 |  |  |   delete_basic_block (block_to_remove);
 | 
      
         | 477 |  |  |  
 | 
      
         | 478 |  |  |   /* Eliminate the COND_EXPR at the end of COND_BLOCK.  */
 | 
      
         | 479 |  |  |   gsi = gsi_last_bb (cond_block);
 | 
      
         | 480 |  |  |   gsi_remove (&gsi, true);
 | 
      
         | 481 |  |  |  
 | 
      
         | 482 |  |  |   if (dump_file && (dump_flags & TDF_DETAILS))
 | 
      
         | 483 |  |  |     fprintf (dump_file,
 | 
      
         | 484 |  |  |               "COND_EXPR in block %d and PHI in block %d converted to straightline code.\n",
 | 
      
         | 485 |  |  |               cond_block->index,
 | 
      
         | 486 |  |  |               bb->index);
 | 
      
         | 487 |  |  | }
 | 
      
         | 488 |  |  |  
 | 
      
         | 489 |  |  | /*  The function conditional_replacement does the main work of doing the
 | 
      
         | 490 |  |  |     conditional replacement.  Return true if the replacement is done.
 | 
      
         | 491 |  |  |     Otherwise return false.
 | 
      
         | 492 |  |  |     BB is the basic block where the replacement is going to be done on.  ARG0
 | 
      
         | 493 |  |  |     is argument 0 from PHI.  Likewise for ARG1.  */
 | 
      
         | 494 |  |  |  
 | 
      
         | 495 |  |  | static bool
 | 
      
         | 496 |  |  | conditional_replacement (basic_block cond_bb, basic_block middle_bb,
 | 
      
         | 497 |  |  |                          edge e0, edge e1, gimple phi,
 | 
      
         | 498 |  |  |                          tree arg0, tree arg1)
 | 
      
         | 499 |  |  | {
 | 
      
         | 500 |  |  |   tree result;
 | 
      
         | 501 |  |  |   gimple stmt, new_stmt;
 | 
      
         | 502 |  |  |   tree cond;
 | 
      
         | 503 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 504 |  |  |   edge true_edge, false_edge;
 | 
      
         | 505 |  |  |   tree new_var, new_var2;
 | 
      
         | 506 |  |  |  
 | 
      
         | 507 |  |  |   /* FIXME: Gimplification of complex type is too hard for now.  */
 | 
      
         | 508 |  |  |   if (TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
 | 
      
         | 509 |  |  |       || TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE)
 | 
      
         | 510 |  |  |     return false;
 | 
      
         | 511 |  |  |  
 | 
      
         | 512 |  |  |   /* The PHI arguments have the constants 0 and 1, then convert
 | 
      
         | 513 |  |  |      it to the conditional.  */
 | 
      
         | 514 |  |  |   if ((integer_zerop (arg0) && integer_onep (arg1))
 | 
      
         | 515 |  |  |       || (integer_zerop (arg1) && integer_onep (arg0)))
 | 
      
         | 516 |  |  |     ;
 | 
      
         | 517 |  |  |   else
 | 
      
         | 518 |  |  |     return false;
 | 
      
         | 519 |  |  |  
 | 
      
         | 520 |  |  |   if (!empty_block_p (middle_bb))
 | 
      
         | 521 |  |  |     return false;
 | 
      
         | 522 |  |  |  
 | 
      
         | 523 |  |  |   /* At this point we know we have a GIMPLE_COND with two successors.
 | 
      
         | 524 |  |  |      One successor is BB, the other successor is an empty block which
 | 
      
         | 525 |  |  |      falls through into BB.
 | 
      
         | 526 |  |  |  
 | 
      
         | 527 |  |  |      There is a single PHI node at the join point (BB) and its arguments
 | 
      
         | 528 |  |  |      are constants (0, 1).
 | 
      
         | 529 |  |  |  
 | 
      
         | 530 |  |  |      So, given the condition COND, and the two PHI arguments, we can
 | 
      
         | 531 |  |  |      rewrite this PHI into non-branching code:
 | 
      
         | 532 |  |  |  
 | 
      
         | 533 |  |  |        dest = (COND) or dest = COND'
 | 
      
         | 534 |  |  |  
 | 
      
         | 535 |  |  |      We use the condition as-is if the argument associated with the
 | 
      
         | 536 |  |  |      true edge has the value one or the argument associated with the
 | 
      
         | 537 |  |  |      false edge as the value zero.  Note that those conditions are not
 | 
      
         | 538 |  |  |      the same since only one of the outgoing edges from the GIMPLE_COND
 | 
      
         | 539 |  |  |      will directly reach BB and thus be associated with an argument.  */
 | 
      
         | 540 |  |  |  
 | 
      
         | 541 |  |  |   stmt = last_stmt (cond_bb);
 | 
      
         | 542 |  |  |   result = PHI_RESULT (phi);
 | 
      
         | 543 |  |  |  
 | 
      
         | 544 |  |  |   /* To handle special cases like floating point comparison, it is easier and
 | 
      
         | 545 |  |  |      less error-prone to build a tree and gimplify it on the fly though it is
 | 
      
         | 546 |  |  |      less efficient.  */
 | 
      
         | 547 |  |  |   cond = fold_build2_loc (gimple_location (stmt),
 | 
      
         | 548 |  |  |                           gimple_cond_code (stmt), boolean_type_node,
 | 
      
         | 549 |  |  |                           gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
 | 
      
         | 550 |  |  |  
 | 
      
         | 551 |  |  |   /* We need to know which is the true edge and which is the false
 | 
      
         | 552 |  |  |      edge so that we know when to invert the condition below.  */
 | 
      
         | 553 |  |  |   extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
 | 
      
         | 554 |  |  |   if ((e0 == true_edge && integer_zerop (arg0))
 | 
      
         | 555 |  |  |       || (e0 == false_edge && integer_onep (arg0))
 | 
      
         | 556 |  |  |       || (e1 == true_edge && integer_zerop (arg1))
 | 
      
         | 557 |  |  |       || (e1 == false_edge && integer_onep (arg1)))
 | 
      
         | 558 |  |  |     cond = fold_build1_loc (gimple_location (stmt),
 | 
      
         | 559 |  |  |                             TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);
 | 
      
         | 560 |  |  |  
 | 
      
         | 561 |  |  |   /* Insert our new statements at the end of conditional block before the
 | 
      
         | 562 |  |  |      COND_STMT.  */
 | 
      
         | 563 |  |  |   gsi = gsi_for_stmt (stmt);
 | 
      
         | 564 |  |  |   new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true,
 | 
      
         | 565 |  |  |                                       GSI_SAME_STMT);
 | 
      
         | 566 |  |  |  
 | 
      
         | 567 |  |  |   if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var)))
 | 
      
         | 568 |  |  |     {
 | 
      
         | 569 |  |  |       source_location locus_0, locus_1;
 | 
      
         | 570 |  |  |  
 | 
      
         | 571 |  |  |       new_var2 = create_tmp_var (TREE_TYPE (result), NULL);
 | 
      
         | 572 |  |  |       add_referenced_var (new_var2);
 | 
      
         | 573 |  |  |       new_stmt = gimple_build_assign_with_ops (CONVERT_EXPR, new_var2,
 | 
      
         | 574 |  |  |                                                new_var, NULL);
 | 
      
         | 575 |  |  |       new_var2 = make_ssa_name (new_var2, new_stmt);
 | 
      
         | 576 |  |  |       gimple_assign_set_lhs (new_stmt, new_var2);
 | 
      
         | 577 |  |  |       gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
 | 
      
         | 578 |  |  |       new_var = new_var2;
 | 
      
         | 579 |  |  |  
 | 
      
         | 580 |  |  |       /* Set the locus to the first argument, unless is doesn't have one.  */
 | 
      
         | 581 |  |  |       locus_0 = gimple_phi_arg_location (phi, 0);
 | 
      
         | 582 |  |  |       locus_1 = gimple_phi_arg_location (phi, 1);
 | 
      
         | 583 |  |  |       if (locus_0 == UNKNOWN_LOCATION)
 | 
      
         | 584 |  |  |         locus_0 = locus_1;
 | 
      
         | 585 |  |  |       gimple_set_location (new_stmt, locus_0);
 | 
      
         | 586 |  |  |     }
 | 
      
         | 587 |  |  |  
 | 
      
         | 588 |  |  |   replace_phi_edge_with_variable (cond_bb, e1, phi, new_var);
 | 
      
         | 589 |  |  |  
 | 
      
         | 590 |  |  |   /* Note that we optimized this PHI.  */
 | 
      
         | 591 |  |  |   return true;
 | 
      
         | 592 |  |  | }
 | 
      
         | 593 |  |  |  
 | 
      
         | 594 |  |  | /* Update *ARG which is defined in STMT so that it contains the
 | 
      
         | 595 |  |  |    computed value if that seems profitable.  Return true if the
 | 
      
         | 596 |  |  |    statement is made dead by that rewriting.  */
 | 
      
         | 597 |  |  |  
 | 
      
         | 598 |  |  | static bool
 | 
      
         | 599 |  |  | jump_function_from_stmt (tree *arg, gimple stmt)
 | 
      
         | 600 |  |  | {
 | 
      
         | 601 |  |  |   enum tree_code code = gimple_assign_rhs_code (stmt);
 | 
      
         | 602 |  |  |   if (code == ADDR_EXPR)
 | 
      
         | 603 |  |  |     {
 | 
      
         | 604 |  |  |       /* For arg = &p->i transform it to p, if possible.  */
 | 
      
         | 605 |  |  |       tree rhs1 = gimple_assign_rhs1 (stmt);
 | 
      
         | 606 |  |  |       HOST_WIDE_INT offset;
 | 
      
         | 607 |  |  |       tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs1, 0),
 | 
      
         | 608 |  |  |                                                 &offset);
 | 
      
         | 609 |  |  |       if (tem
 | 
      
         | 610 |  |  |           && TREE_CODE (tem) == MEM_REF
 | 
      
         | 611 |  |  |           && double_int_zero_p
 | 
      
         | 612 |  |  |                (double_int_add (mem_ref_offset (tem),
 | 
      
         | 613 |  |  |                                 shwi_to_double_int (offset))))
 | 
      
         | 614 |  |  |         {
 | 
      
         | 615 |  |  |           *arg = TREE_OPERAND (tem, 0);
 | 
      
         | 616 |  |  |           return true;
 | 
      
         | 617 |  |  |         }
 | 
      
         | 618 |  |  |     }
 | 
      
         | 619 |  |  |   /* TODO: Much like IPA-CP jump-functions we want to handle constant
 | 
      
         | 620 |  |  |      additions symbolically here, and we'd need to update the comparison
 | 
      
         | 621 |  |  |      code that compares the arg + cst tuples in our caller.  For now the
 | 
      
         | 622 |  |  |      code above exactly handles the VEC_BASE pattern from vec.h.  */
 | 
      
         | 623 |  |  |   return false;
 | 
      
         | 624 |  |  | }
 | 
      
         | 625 |  |  |  
 | 
      
         | 626 |  |  | /*  The function value_replacement does the main work of doing the value
 | 
      
         | 627 |  |  |     replacement.  Return true if the replacement is done.  Otherwise return
 | 
      
         | 628 |  |  |     false.
 | 
      
         | 629 |  |  |     BB is the basic block where the replacement is going to be done on.  ARG0
 | 
      
         | 630 |  |  |     is argument 0 from the PHI.  Likewise for ARG1.  */
 | 
      
         | 631 |  |  |  
 | 
      
         | 632 |  |  | static bool
 | 
      
         | 633 |  |  | value_replacement (basic_block cond_bb, basic_block middle_bb,
 | 
      
         | 634 |  |  |                    edge e0, edge e1, gimple phi,
 | 
      
         | 635 |  |  |                    tree arg0, tree arg1)
 | 
      
         | 636 |  |  | {
 | 
      
         | 637 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 638 |  |  |   gimple cond;
 | 
      
         | 639 |  |  |   edge true_edge, false_edge;
 | 
      
         | 640 |  |  |   enum tree_code code;
 | 
      
         | 641 |  |  |  
 | 
      
         | 642 |  |  |   /* If the type says honor signed zeros we cannot do this
 | 
      
         | 643 |  |  |      optimization.  */
 | 
      
         | 644 |  |  |   if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
 | 
      
         | 645 |  |  |     return false;
 | 
      
         | 646 |  |  |  
 | 
      
         | 647 |  |  |   /* Allow a single statement in MIDDLE_BB that defines one of the PHI
 | 
      
         | 648 |  |  |      arguments.  */
 | 
      
         | 649 |  |  |   gsi = gsi_after_labels (middle_bb);
 | 
      
         | 650 |  |  |   if (!gsi_end_p (gsi))
 | 
      
         | 651 |  |  |     {
 | 
      
         | 652 |  |  |       if (is_gimple_debug (gsi_stmt (gsi)))
 | 
      
         | 653 |  |  |         gsi_next_nondebug (&gsi);
 | 
      
         | 654 |  |  |       if (!gsi_end_p (gsi))
 | 
      
         | 655 |  |  |         {
 | 
      
         | 656 |  |  |           gimple stmt = gsi_stmt (gsi);
 | 
      
         | 657 |  |  |           tree lhs;
 | 
      
         | 658 |  |  |           gsi_next_nondebug (&gsi);
 | 
      
         | 659 |  |  |           if (!gsi_end_p (gsi))
 | 
      
         | 660 |  |  |             return false;
 | 
      
         | 661 |  |  |           if (!is_gimple_assign (stmt))
 | 
      
         | 662 |  |  |             return false;
 | 
      
         | 663 |  |  |           /* Now try to adjust arg0 or arg1 according to the computation
 | 
      
         | 664 |  |  |              in the single statement.  */
 | 
      
         | 665 |  |  |           lhs = gimple_assign_lhs (stmt);
 | 
      
         | 666 |  |  |           if (!((lhs == arg0
 | 
      
         | 667 |  |  |                  && jump_function_from_stmt (&arg0, stmt))
 | 
      
         | 668 |  |  |                 || (lhs == arg1
 | 
      
         | 669 |  |  |                     && jump_function_from_stmt (&arg1, stmt))))
 | 
      
         | 670 |  |  |             return false;
 | 
      
         | 671 |  |  |         }
 | 
      
         | 672 |  |  |     }
 | 
      
         | 673 |  |  |  
 | 
      
         | 674 |  |  |   cond = last_stmt (cond_bb);
 | 
      
         | 675 |  |  |   code = gimple_cond_code (cond);
 | 
      
         | 676 |  |  |  
 | 
      
         | 677 |  |  |   /* This transformation is only valid for equality comparisons.  */
 | 
      
         | 678 |  |  |   if (code != NE_EXPR && code != EQ_EXPR)
 | 
      
         | 679 |  |  |     return false;
 | 
      
         | 680 |  |  |  
 | 
      
         | 681 |  |  |   /* We need to know which is the true edge and which is the false
 | 
      
         | 682 |  |  |       edge so that we know if have abs or negative abs.  */
 | 
      
         | 683 |  |  |   extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
 | 
      
         | 684 |  |  |  
 | 
      
         | 685 |  |  |   /* At this point we know we have a COND_EXPR with two successors.
 | 
      
         | 686 |  |  |      One successor is BB, the other successor is an empty block which
 | 
      
         | 687 |  |  |      falls through into BB.
 | 
      
         | 688 |  |  |  
 | 
      
         | 689 |  |  |      The condition for the COND_EXPR is known to be NE_EXPR or EQ_EXPR.
 | 
      
         | 690 |  |  |  
 | 
      
         | 691 |  |  |      There is a single PHI node at the join point (BB) with two arguments.
 | 
      
         | 692 |  |  |  
 | 
      
         | 693 |  |  |      We now need to verify that the two arguments in the PHI node match
 | 
      
         | 694 |  |  |      the two arguments to the equality comparison.  */
 | 
      
         | 695 |  |  |  
 | 
      
         | 696 |  |  |   if ((operand_equal_for_phi_arg_p (arg0, gimple_cond_lhs (cond))
 | 
      
         | 697 |  |  |        && operand_equal_for_phi_arg_p (arg1, gimple_cond_rhs (cond)))
 | 
      
         | 698 |  |  |       || (operand_equal_for_phi_arg_p (arg1, gimple_cond_lhs (cond))
 | 
      
         | 699 |  |  |           && operand_equal_for_phi_arg_p (arg0, gimple_cond_rhs (cond))))
 | 
      
         | 700 |  |  |     {
 | 
      
         | 701 |  |  |       edge e;
 | 
      
         | 702 |  |  |       tree arg;
 | 
      
         | 703 |  |  |  
 | 
      
         | 704 |  |  |       /* For NE_EXPR, we want to build an assignment result = arg where
 | 
      
         | 705 |  |  |          arg is the PHI argument associated with the true edge.  For
 | 
      
         | 706 |  |  |          EQ_EXPR we want the PHI argument associated with the false edge.  */
 | 
      
         | 707 |  |  |       e = (code == NE_EXPR ? true_edge : false_edge);
 | 
      
         | 708 |  |  |  
 | 
      
         | 709 |  |  |       /* Unfortunately, E may not reach BB (it may instead have gone to
 | 
      
         | 710 |  |  |          OTHER_BLOCK).  If that is the case, then we want the single outgoing
 | 
      
         | 711 |  |  |          edge from OTHER_BLOCK which reaches BB and represents the desired
 | 
      
         | 712 |  |  |          path from COND_BLOCK.  */
 | 
      
         | 713 |  |  |       if (e->dest == middle_bb)
 | 
      
         | 714 |  |  |         e = single_succ_edge (e->dest);
 | 
      
         | 715 |  |  |  
 | 
      
         | 716 |  |  |       /* Now we know the incoming edge to BB that has the argument for the
 | 
      
         | 717 |  |  |          RHS of our new assignment statement.  */
 | 
      
         | 718 |  |  |       if (e0 == e)
 | 
      
         | 719 |  |  |         arg = arg0;
 | 
      
         | 720 |  |  |       else
 | 
      
         | 721 |  |  |         arg = arg1;
 | 
      
         | 722 |  |  |  
 | 
      
         | 723 |  |  |       replace_phi_edge_with_variable (cond_bb, e1, phi, arg);
 | 
      
         | 724 |  |  |  
 | 
      
         | 725 |  |  |       /* Note that we optimized this PHI.  */
 | 
      
         | 726 |  |  |       return true;
 | 
      
         | 727 |  |  |     }
 | 
      
         | 728 |  |  |   return false;
 | 
      
         | 729 |  |  | }
 | 
      
         | 730 |  |  |  
 | 
      
         | 731 |  |  | /*  The function minmax_replacement does the main work of doing the minmax
 | 
      
         | 732 |  |  |     replacement.  Return true if the replacement is done.  Otherwise return
 | 
      
         | 733 |  |  |     false.
 | 
      
         | 734 |  |  |     BB is the basic block where the replacement is going to be done on.  ARG0
 | 
      
         | 735 |  |  |     is argument 0 from the PHI.  Likewise for ARG1.  */
 | 
      
         | 736 |  |  |  
 | 
      
         | 737 |  |  | static bool
 | 
      
         | 738 |  |  | minmax_replacement (basic_block cond_bb, basic_block middle_bb,
 | 
      
         | 739 |  |  |                     edge e0, edge e1, gimple phi,
 | 
      
         | 740 |  |  |                     tree arg0, tree arg1)
 | 
      
         | 741 |  |  | {
 | 
      
         | 742 |  |  |   tree result, type;
 | 
      
         | 743 |  |  |   gimple cond, new_stmt;
 | 
      
         | 744 |  |  |   edge true_edge, false_edge;
 | 
      
         | 745 |  |  |   enum tree_code cmp, minmax, ass_code;
 | 
      
         | 746 |  |  |   tree smaller, larger, arg_true, arg_false;
 | 
      
         | 747 |  |  |   gimple_stmt_iterator gsi, gsi_from;
 | 
      
         | 748 |  |  |  
 | 
      
         | 749 |  |  |   type = TREE_TYPE (PHI_RESULT (phi));
 | 
      
         | 750 |  |  |  
 | 
      
         | 751 |  |  |   /* The optimization may be unsafe due to NaNs.  */
 | 
      
         | 752 |  |  |   if (HONOR_NANS (TYPE_MODE (type)))
 | 
      
         | 753 |  |  |     return false;
 | 
      
         | 754 |  |  |  
 | 
      
         | 755 |  |  |   cond = last_stmt (cond_bb);
 | 
      
         | 756 |  |  |   cmp = gimple_cond_code (cond);
 | 
      
         | 757 |  |  |  
 | 
      
         | 758 |  |  |   /* This transformation is only valid for order comparisons.  Record which
 | 
      
         | 759 |  |  |      operand is smaller/larger if the result of the comparison is true.  */
 | 
      
         | 760 |  |  |   if (cmp == LT_EXPR || cmp == LE_EXPR)
 | 
      
         | 761 |  |  |     {
 | 
      
         | 762 |  |  |       smaller = gimple_cond_lhs (cond);
 | 
      
         | 763 |  |  |       larger = gimple_cond_rhs (cond);
 | 
      
         | 764 |  |  |     }
 | 
      
         | 765 |  |  |   else if (cmp == GT_EXPR || cmp == GE_EXPR)
 | 
      
         | 766 |  |  |     {
 | 
      
         | 767 |  |  |       smaller = gimple_cond_rhs (cond);
 | 
      
         | 768 |  |  |       larger = gimple_cond_lhs (cond);
 | 
      
         | 769 |  |  |     }
 | 
      
         | 770 |  |  |   else
 | 
      
         | 771 |  |  |     return false;
 | 
      
         | 772 |  |  |  
 | 
      
         | 773 |  |  |   /* We need to know which is the true edge and which is the false
 | 
      
         | 774 |  |  |       edge so that we know if have abs or negative abs.  */
 | 
      
         | 775 |  |  |   extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
 | 
      
         | 776 |  |  |  
 | 
      
         | 777 |  |  |   /* Forward the edges over the middle basic block.  */
 | 
      
         | 778 |  |  |   if (true_edge->dest == middle_bb)
 | 
      
         | 779 |  |  |     true_edge = EDGE_SUCC (true_edge->dest, 0);
 | 
      
         | 780 |  |  |   if (false_edge->dest == middle_bb)
 | 
      
         | 781 |  |  |     false_edge = EDGE_SUCC (false_edge->dest, 0);
 | 
      
         | 782 |  |  |  
 | 
      
         | 783 |  |  |   if (true_edge == e0)
 | 
      
         | 784 |  |  |     {
 | 
      
         | 785 |  |  |       gcc_assert (false_edge == e1);
 | 
      
         | 786 |  |  |       arg_true = arg0;
 | 
      
         | 787 |  |  |       arg_false = arg1;
 | 
      
         | 788 |  |  |     }
 | 
      
         | 789 |  |  |   else
 | 
      
         | 790 |  |  |     {
 | 
      
         | 791 |  |  |       gcc_assert (false_edge == e0);
 | 
      
         | 792 |  |  |       gcc_assert (true_edge == e1);
 | 
      
         | 793 |  |  |       arg_true = arg1;
 | 
      
         | 794 |  |  |       arg_false = arg0;
 | 
      
         | 795 |  |  |     }
 | 
      
         | 796 |  |  |  
 | 
      
         | 797 |  |  |   if (empty_block_p (middle_bb))
 | 
      
         | 798 |  |  |     {
 | 
      
         | 799 |  |  |       if (operand_equal_for_phi_arg_p (arg_true, smaller)
 | 
      
         | 800 |  |  |           && operand_equal_for_phi_arg_p (arg_false, larger))
 | 
      
         | 801 |  |  |         {
 | 
      
         | 802 |  |  |           /* Case
 | 
      
         | 803 |  |  |  
 | 
      
         | 804 |  |  |              if (smaller < larger)
 | 
      
         | 805 |  |  |              rslt = smaller;
 | 
      
         | 806 |  |  |              else
 | 
      
         | 807 |  |  |              rslt = larger;  */
 | 
      
         | 808 |  |  |           minmax = MIN_EXPR;
 | 
      
         | 809 |  |  |         }
 | 
      
         | 810 |  |  |       else if (operand_equal_for_phi_arg_p (arg_false, smaller)
 | 
      
         | 811 |  |  |                && operand_equal_for_phi_arg_p (arg_true, larger))
 | 
      
         | 812 |  |  |         minmax = MAX_EXPR;
 | 
      
         | 813 |  |  |       else
 | 
      
         | 814 |  |  |         return false;
 | 
      
         | 815 |  |  |     }
 | 
      
         | 816 |  |  |   else
 | 
      
         | 817 |  |  |     {
 | 
      
         | 818 |  |  |       /* Recognize the following case, assuming d <= u:
 | 
      
         | 819 |  |  |  
 | 
      
         | 820 |  |  |          if (a <= u)
 | 
      
         | 821 |  |  |            b = MAX (a, d);
 | 
      
         | 822 |  |  |          x = PHI <b, u>
 | 
      
         | 823 |  |  |  
 | 
      
         | 824 |  |  |          This is equivalent to
 | 
      
         | 825 |  |  |  
 | 
      
         | 826 |  |  |          b = MAX (a, d);
 | 
      
         | 827 |  |  |          x = MIN (b, u);  */
 | 
      
         | 828 |  |  |  
 | 
      
         | 829 |  |  |       gimple assign = last_and_only_stmt (middle_bb);
 | 
      
         | 830 |  |  |       tree lhs, op0, op1, bound;
 | 
      
         | 831 |  |  |  
 | 
      
         | 832 |  |  |       if (!assign
 | 
      
         | 833 |  |  |           || gimple_code (assign) != GIMPLE_ASSIGN)
 | 
      
         | 834 |  |  |         return false;
 | 
      
         | 835 |  |  |  
 | 
      
         | 836 |  |  |       lhs = gimple_assign_lhs (assign);
 | 
      
         | 837 |  |  |       ass_code = gimple_assign_rhs_code (assign);
 | 
      
         | 838 |  |  |       if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
 | 
      
         | 839 |  |  |         return false;
 | 
      
         | 840 |  |  |       op0 = gimple_assign_rhs1 (assign);
 | 
      
         | 841 |  |  |       op1 = gimple_assign_rhs2 (assign);
 | 
      
         | 842 |  |  |  
 | 
      
         | 843 |  |  |       if (true_edge->src == middle_bb)
 | 
      
         | 844 |  |  |         {
 | 
      
         | 845 |  |  |           /* We got here if the condition is true, i.e., SMALLER < LARGER.  */
 | 
      
         | 846 |  |  |           if (!operand_equal_for_phi_arg_p (lhs, arg_true))
 | 
      
         | 847 |  |  |             return false;
 | 
      
         | 848 |  |  |  
 | 
      
         | 849 |  |  |           if (operand_equal_for_phi_arg_p (arg_false, larger))
 | 
      
         | 850 |  |  |             {
 | 
      
         | 851 |  |  |               /* Case
 | 
      
         | 852 |  |  |  
 | 
      
         | 853 |  |  |                  if (smaller < larger)
 | 
      
         | 854 |  |  |                    {
 | 
      
         | 855 |  |  |                      r' = MAX_EXPR (smaller, bound)
 | 
      
         | 856 |  |  |                    }
 | 
      
         | 857 |  |  |                  r = PHI <r', larger>  --> to be turned to MIN_EXPR.  */
 | 
      
         | 858 |  |  |               if (ass_code != MAX_EXPR)
 | 
      
         | 859 |  |  |                 return false;
 | 
      
         | 860 |  |  |  
 | 
      
         | 861 |  |  |               minmax = MIN_EXPR;
 | 
      
         | 862 |  |  |               if (operand_equal_for_phi_arg_p (op0, smaller))
 | 
      
         | 863 |  |  |                 bound = op1;
 | 
      
         | 864 |  |  |               else if (operand_equal_for_phi_arg_p (op1, smaller))
 | 
      
         | 865 |  |  |                 bound = op0;
 | 
      
         | 866 |  |  |               else
 | 
      
         | 867 |  |  |                 return false;
 | 
      
         | 868 |  |  |  
 | 
      
         | 869 |  |  |               /* We need BOUND <= LARGER.  */
 | 
      
         | 870 |  |  |               if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
 | 
      
         | 871 |  |  |                                                   bound, larger)))
 | 
      
         | 872 |  |  |                 return false;
 | 
      
         | 873 |  |  |             }
 | 
      
         | 874 |  |  |           else if (operand_equal_for_phi_arg_p (arg_false, smaller))
 | 
      
         | 875 |  |  |             {
 | 
      
         | 876 |  |  |               /* Case
 | 
      
         | 877 |  |  |  
 | 
      
         | 878 |  |  |                  if (smaller < larger)
 | 
      
         | 879 |  |  |                    {
 | 
      
         | 880 |  |  |                      r' = MIN_EXPR (larger, bound)
 | 
      
         | 881 |  |  |                    }
 | 
      
         | 882 |  |  |                  r = PHI <r', smaller>  --> to be turned to MAX_EXPR.  */
 | 
      
         | 883 |  |  |               if (ass_code != MIN_EXPR)
 | 
      
         | 884 |  |  |                 return false;
 | 
      
         | 885 |  |  |  
 | 
      
         | 886 |  |  |               minmax = MAX_EXPR;
 | 
      
         | 887 |  |  |               if (operand_equal_for_phi_arg_p (op0, larger))
 | 
      
         | 888 |  |  |                 bound = op1;
 | 
      
         | 889 |  |  |               else if (operand_equal_for_phi_arg_p (op1, larger))
 | 
      
         | 890 |  |  |                 bound = op0;
 | 
      
         | 891 |  |  |               else
 | 
      
         | 892 |  |  |                 return false;
 | 
      
         | 893 |  |  |  
 | 
      
         | 894 |  |  |               /* We need BOUND >= SMALLER.  */
 | 
      
         | 895 |  |  |               if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
 | 
      
         | 896 |  |  |                                                   bound, smaller)))
 | 
      
         | 897 |  |  |                 return false;
 | 
      
         | 898 |  |  |             }
 | 
      
         | 899 |  |  |           else
 | 
      
         | 900 |  |  |             return false;
 | 
      
         | 901 |  |  |         }
 | 
      
         | 902 |  |  |       else
 | 
      
         | 903 |  |  |         {
 | 
      
         | 904 |  |  |           /* We got here if the condition is false, i.e., SMALLER > LARGER.  */
 | 
      
         | 905 |  |  |           if (!operand_equal_for_phi_arg_p (lhs, arg_false))
 | 
      
         | 906 |  |  |             return false;
 | 
      
         | 907 |  |  |  
 | 
      
         | 908 |  |  |           if (operand_equal_for_phi_arg_p (arg_true, larger))
 | 
      
         | 909 |  |  |             {
 | 
      
         | 910 |  |  |               /* Case
 | 
      
         | 911 |  |  |  
 | 
      
         | 912 |  |  |                  if (smaller > larger)
 | 
      
         | 913 |  |  |                    {
 | 
      
         | 914 |  |  |                      r' = MIN_EXPR (smaller, bound)
 | 
      
         | 915 |  |  |                    }
 | 
      
         | 916 |  |  |                  r = PHI <r', larger>  --> to be turned to MAX_EXPR.  */
 | 
      
         | 917 |  |  |               if (ass_code != MIN_EXPR)
 | 
      
         | 918 |  |  |                 return false;
 | 
      
         | 919 |  |  |  
 | 
      
         | 920 |  |  |               minmax = MAX_EXPR;
 | 
      
         | 921 |  |  |               if (operand_equal_for_phi_arg_p (op0, smaller))
 | 
      
         | 922 |  |  |                 bound = op1;
 | 
      
         | 923 |  |  |               else if (operand_equal_for_phi_arg_p (op1, smaller))
 | 
      
         | 924 |  |  |                 bound = op0;
 | 
      
         | 925 |  |  |               else
 | 
      
         | 926 |  |  |                 return false;
 | 
      
         | 927 |  |  |  
 | 
      
         | 928 |  |  |               /* We need BOUND >= LARGER.  */
 | 
      
         | 929 |  |  |               if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
 | 
      
         | 930 |  |  |                                                   bound, larger)))
 | 
      
         | 931 |  |  |                 return false;
 | 
      
         | 932 |  |  |             }
 | 
      
         | 933 |  |  |           else if (operand_equal_for_phi_arg_p (arg_true, smaller))
 | 
      
         | 934 |  |  |             {
 | 
      
         | 935 |  |  |               /* Case
 | 
      
         | 936 |  |  |  
 | 
      
         | 937 |  |  |                  if (smaller > larger)
 | 
      
         | 938 |  |  |                    {
 | 
      
         | 939 |  |  |                      r' = MAX_EXPR (larger, bound)
 | 
      
         | 940 |  |  |                    }
 | 
      
         | 941 |  |  |                  r = PHI <r', smaller>  --> to be turned to MIN_EXPR.  */
 | 
      
         | 942 |  |  |               if (ass_code != MAX_EXPR)
 | 
      
         | 943 |  |  |                 return false;
 | 
      
         | 944 |  |  |  
 | 
      
         | 945 |  |  |               minmax = MIN_EXPR;
 | 
      
         | 946 |  |  |               if (operand_equal_for_phi_arg_p (op0, larger))
 | 
      
         | 947 |  |  |                 bound = op1;
 | 
      
         | 948 |  |  |               else if (operand_equal_for_phi_arg_p (op1, larger))
 | 
      
         | 949 |  |  |                 bound = op0;
 | 
      
         | 950 |  |  |               else
 | 
      
         | 951 |  |  |                 return false;
 | 
      
         | 952 |  |  |  
 | 
      
         | 953 |  |  |               /* We need BOUND <= SMALLER.  */
 | 
      
         | 954 |  |  |               if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
 | 
      
         | 955 |  |  |                                                   bound, smaller)))
 | 
      
         | 956 |  |  |                 return false;
 | 
      
         | 957 |  |  |             }
 | 
      
         | 958 |  |  |           else
 | 
      
         | 959 |  |  |             return false;
 | 
      
         | 960 |  |  |         }
 | 
      
         | 961 |  |  |  
 | 
      
         | 962 |  |  |       /* Move the statement from the middle block.  */
 | 
      
         | 963 |  |  |       gsi = gsi_last_bb (cond_bb);
 | 
      
         | 964 |  |  |       gsi_from = gsi_last_nondebug_bb (middle_bb);
 | 
      
         | 965 |  |  |       gsi_move_before (&gsi_from, &gsi);
 | 
      
         | 966 |  |  |     }
 | 
      
         | 967 |  |  |  
 | 
      
         | 968 |  |  |   /* Emit the statement to compute min/max.  */
 | 
      
         | 969 |  |  |   result = duplicate_ssa_name (PHI_RESULT (phi), NULL);
 | 
      
         | 970 |  |  |   new_stmt = gimple_build_assign_with_ops (minmax, result, arg0, arg1);
 | 
      
         | 971 |  |  |   gsi = gsi_last_bb (cond_bb);
 | 
      
         | 972 |  |  |   gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 973 |  |  |  
 | 
      
         | 974 |  |  |   replace_phi_edge_with_variable (cond_bb, e1, phi, result);
 | 
      
         | 975 |  |  |   return true;
 | 
      
         | 976 |  |  | }
 | 
      
         | 977 |  |  |  
 | 
      
         | 978 |  |  | /*  The function absolute_replacement does the main work of doing the absolute
 | 
      
         | 979 |  |  |     replacement.  Return true if the replacement is done.  Otherwise return
 | 
      
         | 980 |  |  |     false.
 | 
      
         | 981 |  |  |     bb is the basic block where the replacement is going to be done on.  arg0
 | 
      
         | 982 |  |  |     is argument 0 from the phi.  Likewise for arg1.  */
 | 
      
         | 983 |  |  |  
 | 
      
         | 984 |  |  | static bool
 | 
      
         | 985 |  |  | abs_replacement (basic_block cond_bb, basic_block middle_bb,
 | 
      
         | 986 |  |  |                  edge e0 ATTRIBUTE_UNUSED, edge e1,
 | 
      
         | 987 |  |  |                  gimple phi, tree arg0, tree arg1)
 | 
      
         | 988 |  |  | {
 | 
      
         | 989 |  |  |   tree result;
 | 
      
         | 990 |  |  |   gimple new_stmt, cond;
 | 
      
         | 991 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 992 |  |  |   edge true_edge, false_edge;
 | 
      
         | 993 |  |  |   gimple assign;
 | 
      
         | 994 |  |  |   edge e;
 | 
      
         | 995 |  |  |   tree rhs, lhs;
 | 
      
         | 996 |  |  |   bool negate;
 | 
      
         | 997 |  |  |   enum tree_code cond_code;
 | 
      
         | 998 |  |  |  
 | 
      
         | 999 |  |  |   /* If the type says honor signed zeros we cannot do this
 | 
      
         | 1000 |  |  |      optimization.  */
 | 
      
         | 1001 |  |  |   if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
 | 
      
         | 1002 |  |  |     return false;
 | 
      
         | 1003 |  |  |  
 | 
      
         | 1004 |  |  |   /* OTHER_BLOCK must have only one executable statement which must have the
 | 
      
         | 1005 |  |  |      form arg0 = -arg1 or arg1 = -arg0.  */
 | 
      
         | 1006 |  |  |  
 | 
      
         | 1007 |  |  |   assign = last_and_only_stmt (middle_bb);
 | 
      
         | 1008 |  |  |   /* If we did not find the proper negation assignment, then we can not
 | 
      
         | 1009 |  |  |      optimize.  */
 | 
      
         | 1010 |  |  |   if (assign == NULL)
 | 
      
         | 1011 |  |  |     return false;
 | 
      
         | 1012 |  |  |  
 | 
      
         | 1013 |  |  |   /* If we got here, then we have found the only executable statement
 | 
      
         | 1014 |  |  |      in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
 | 
      
         | 1015 |  |  |      arg1 = -arg0, then we can not optimize.  */
 | 
      
         | 1016 |  |  |   if (gimple_code (assign) != GIMPLE_ASSIGN)
 | 
      
         | 1017 |  |  |     return false;
 | 
      
         | 1018 |  |  |  
 | 
      
         | 1019 |  |  |   lhs = gimple_assign_lhs (assign);
 | 
      
         | 1020 |  |  |  
 | 
      
         | 1021 |  |  |   if (gimple_assign_rhs_code (assign) != NEGATE_EXPR)
 | 
      
         | 1022 |  |  |     return false;
 | 
      
         | 1023 |  |  |  
 | 
      
         | 1024 |  |  |   rhs = gimple_assign_rhs1 (assign);
 | 
      
         | 1025 |  |  |  
 | 
      
         | 1026 |  |  |   /* The assignment has to be arg0 = -arg1 or arg1 = -arg0.  */
 | 
      
         | 1027 |  |  |   if (!(lhs == arg0 && rhs == arg1)
 | 
      
         | 1028 |  |  |       && !(lhs == arg1 && rhs == arg0))
 | 
      
         | 1029 |  |  |     return false;
 | 
      
         | 1030 |  |  |  
 | 
      
         | 1031 |  |  |   cond = last_stmt (cond_bb);
 | 
      
         | 1032 |  |  |   result = PHI_RESULT (phi);
 | 
      
         | 1033 |  |  |  
 | 
      
         | 1034 |  |  |   /* Only relationals comparing arg[01] against zero are interesting.  */
 | 
      
         | 1035 |  |  |   cond_code = gimple_cond_code (cond);
 | 
      
         | 1036 |  |  |   if (cond_code != GT_EXPR && cond_code != GE_EXPR
 | 
      
         | 1037 |  |  |       && cond_code != LT_EXPR && cond_code != LE_EXPR)
 | 
      
         | 1038 |  |  |     return false;
 | 
      
         | 1039 |  |  |  
 | 
      
         | 1040 |  |  |   /* Make sure the conditional is arg[01] OP y.  */
 | 
      
         | 1041 |  |  |   if (gimple_cond_lhs (cond) != rhs)
 | 
      
         | 1042 |  |  |     return false;
 | 
      
         | 1043 |  |  |  
 | 
      
         | 1044 |  |  |   if (FLOAT_TYPE_P (TREE_TYPE (gimple_cond_rhs (cond)))
 | 
      
         | 1045 |  |  |                ? real_zerop (gimple_cond_rhs (cond))
 | 
      
         | 1046 |  |  |                : integer_zerop (gimple_cond_rhs (cond)))
 | 
      
         | 1047 |  |  |     ;
 | 
      
         | 1048 |  |  |   else
 | 
      
         | 1049 |  |  |     return false;
 | 
      
         | 1050 |  |  |  
 | 
      
         | 1051 |  |  |   /* We need to know which is the true edge and which is the false
 | 
      
         | 1052 |  |  |      edge so that we know if have abs or negative abs.  */
 | 
      
         | 1053 |  |  |   extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
 | 
      
         | 1054 |  |  |  
 | 
      
         | 1055 |  |  |   /* For GT_EXPR/GE_EXPR, if the true edge goes to OTHER_BLOCK, then we
 | 
      
         | 1056 |  |  |      will need to negate the result.  Similarly for LT_EXPR/LE_EXPR if
 | 
      
         | 1057 |  |  |      the false edge goes to OTHER_BLOCK.  */
 | 
      
         | 1058 |  |  |   if (cond_code == GT_EXPR || cond_code == GE_EXPR)
 | 
      
         | 1059 |  |  |     e = true_edge;
 | 
      
         | 1060 |  |  |   else
 | 
      
         | 1061 |  |  |     e = false_edge;
 | 
      
         | 1062 |  |  |  
 | 
      
         | 1063 |  |  |   if (e->dest == middle_bb)
 | 
      
         | 1064 |  |  |     negate = true;
 | 
      
         | 1065 |  |  |   else
 | 
      
         | 1066 |  |  |     negate = false;
 | 
      
         | 1067 |  |  |  
 | 
      
         | 1068 |  |  |   result = duplicate_ssa_name (result, NULL);
 | 
      
         | 1069 |  |  |  
 | 
      
         | 1070 |  |  |   if (negate)
 | 
      
         | 1071 |  |  |     {
 | 
      
         | 1072 |  |  |       tree tmp = create_tmp_var (TREE_TYPE (result), NULL);
 | 
      
         | 1073 |  |  |       add_referenced_var (tmp);
 | 
      
         | 1074 |  |  |       lhs = make_ssa_name (tmp, NULL);
 | 
      
         | 1075 |  |  |     }
 | 
      
         | 1076 |  |  |   else
 | 
      
         | 1077 |  |  |     lhs = result;
 | 
      
         | 1078 |  |  |  
 | 
      
         | 1079 |  |  |   /* Build the modify expression with abs expression.  */
 | 
      
         | 1080 |  |  |   new_stmt = gimple_build_assign_with_ops (ABS_EXPR, lhs, rhs, NULL);
 | 
      
         | 1081 |  |  |  
 | 
      
         | 1082 |  |  |   gsi = gsi_last_bb (cond_bb);
 | 
      
         | 1083 |  |  |   gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 1084 |  |  |  
 | 
      
         | 1085 |  |  |   if (negate)
 | 
      
         | 1086 |  |  |     {
 | 
      
         | 1087 |  |  |       /* Get the right GSI.  We want to insert after the recently
 | 
      
         | 1088 |  |  |          added ABS_EXPR statement (which we know is the first statement
 | 
      
         | 1089 |  |  |          in the block.  */
 | 
      
         | 1090 |  |  |       new_stmt = gimple_build_assign_with_ops (NEGATE_EXPR, result, lhs, NULL);
 | 
      
         | 1091 |  |  |  
 | 
      
         | 1092 |  |  |       gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 1093 |  |  |     }
 | 
      
         | 1094 |  |  |  
 | 
      
         | 1095 |  |  |   replace_phi_edge_with_variable (cond_bb, e1, phi, result);
 | 
      
         | 1096 |  |  |  
 | 
      
         | 1097 |  |  |   /* Note that we optimized this PHI.  */
 | 
      
         | 1098 |  |  |   return true;
 | 
      
         | 1099 |  |  | }
 | 
      
         | 1100 |  |  |  
 | 
      
         | 1101 |  |  | /* Auxiliary functions to determine the set of memory accesses which
 | 
      
         | 1102 |  |  |    can't trap because they are preceded by accesses to the same memory
 | 
      
         | 1103 |  |  |    portion.  We do that for MEM_REFs, so we only need to track
 | 
      
         | 1104 |  |  |    the SSA_NAME of the pointer indirectly referenced.  The algorithm
 | 
      
         | 1105 |  |  |    simply is a walk over all instructions in dominator order.  When
 | 
      
         | 1106 |  |  |    we see an MEM_REF we determine if we've already seen a same
 | 
      
         | 1107 |  |  |    ref anywhere up to the root of the dominator tree.  If we do the
 | 
      
         | 1108 |  |  |    current access can't trap.  If we don't see any dominating access
 | 
      
         | 1109 |  |  |    the current access might trap, but might also make later accesses
 | 
      
         | 1110 |  |  |    non-trapping, so we remember it.  We need to be careful with loads
 | 
      
         | 1111 |  |  |    or stores, for instance a load might not trap, while a store would,
 | 
      
         | 1112 |  |  |    so if we see a dominating read access this doesn't mean that a later
 | 
      
         | 1113 |  |  |    write access would not trap.  Hence we also need to differentiate the
 | 
      
         | 1114 |  |  |    type of access(es) seen.
 | 
      
         | 1115 |  |  |  
 | 
      
         | 1116 |  |  |    ??? We currently are very conservative and assume that a load might
 | 
      
         | 1117 |  |  |    trap even if a store doesn't (write-only memory).  This probably is
 | 
      
         | 1118 |  |  |    overly conservative.  */
 | 
      
         | 1119 |  |  |  
 | 
      
         | 1120 |  |  | /* A hash-table of SSA_NAMEs, and in which basic block an MEM_REF
 | 
      
         | 1121 |  |  |    through it was seen, which would constitute a no-trap region for
 | 
      
         | 1122 |  |  |    same accesses.  */
 | 
      
         | 1123 |  |  | struct name_to_bb
 | 
      
         | 1124 |  |  | {
 | 
      
         | 1125 |  |  |   tree ssa_name;
 | 
      
         | 1126 |  |  |   basic_block bb;
 | 
      
         | 1127 |  |  |   unsigned store : 1;
 | 
      
         | 1128 |  |  | };
 | 
      
         | 1129 |  |  |  
 | 
      
         | 1130 |  |  | /* The hash table for remembering what we've seen.  */
 | 
      
         | 1131 |  |  | static htab_t seen_ssa_names;
 | 
      
         | 1132 |  |  |  
 | 
      
         | 1133 |  |  | /* The set of MEM_REFs which can't trap.  */
 | 
      
         | 1134 |  |  | static struct pointer_set_t *nontrap_set;
 | 
      
         | 1135 |  |  |  
 | 
      
         | 1136 |  |  | /* The hash function, based on the pointer to the pointer SSA_NAME.  */
 | 
      
         | 1137 |  |  | static hashval_t
 | 
      
         | 1138 |  |  | name_to_bb_hash (const void *p)
 | 
      
         | 1139 |  |  | {
 | 
      
         | 1140 |  |  |   const_tree n = ((const struct name_to_bb *)p)->ssa_name;
 | 
      
         | 1141 |  |  |   return htab_hash_pointer (n) ^ ((const struct name_to_bb *)p)->store;
 | 
      
         | 1142 |  |  | }
 | 
      
         | 1143 |  |  |  
 | 
      
         | 1144 |  |  | /* The equality function of *P1 and *P2.  SSA_NAMEs are shared, so
 | 
      
         | 1145 |  |  |    it's enough to simply compare them for equality.  */
 | 
      
         | 1146 |  |  | static int
 | 
      
         | 1147 |  |  | name_to_bb_eq (const void *p1, const void *p2)
 | 
      
         | 1148 |  |  | {
 | 
      
         | 1149 |  |  |   const struct name_to_bb *n1 = (const struct name_to_bb *)p1;
 | 
      
         | 1150 |  |  |   const struct name_to_bb *n2 = (const struct name_to_bb *)p2;
 | 
      
         | 1151 |  |  |  
 | 
      
         | 1152 |  |  |   return n1->ssa_name == n2->ssa_name && n1->store == n2->store;
 | 
      
         | 1153 |  |  | }
 | 
      
         | 1154 |  |  |  
 | 
      
         | 1155 |  |  | /* We see the expression EXP in basic block BB.  If it's an interesting
 | 
      
         | 1156 |  |  |    expression (an MEM_REF through an SSA_NAME) possibly insert the
 | 
      
         | 1157 |  |  |    expression into the set NONTRAP or the hash table of seen expressions.
 | 
      
         | 1158 |  |  |    STORE is true if this expression is on the LHS, otherwise it's on
 | 
      
         | 1159 |  |  |    the RHS.  */
 | 
      
         | 1160 |  |  | static void
 | 
      
         | 1161 |  |  | add_or_mark_expr (basic_block bb, tree exp,
 | 
      
         | 1162 |  |  |                   struct pointer_set_t *nontrap, bool store)
 | 
      
         | 1163 |  |  | {
 | 
      
         | 1164 |  |  |   if (TREE_CODE (exp) == MEM_REF
 | 
      
         | 1165 |  |  |       && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME)
 | 
      
         | 1166 |  |  |     {
 | 
      
         | 1167 |  |  |       tree name = TREE_OPERAND (exp, 0);
 | 
      
         | 1168 |  |  |       struct name_to_bb map;
 | 
      
         | 1169 |  |  |       void **slot;
 | 
      
         | 1170 |  |  |       struct name_to_bb *n2bb;
 | 
      
         | 1171 |  |  |       basic_block found_bb = 0;
 | 
      
         | 1172 |  |  |  
 | 
      
         | 1173 |  |  |       /* Try to find the last seen MEM_REF through the same
 | 
      
         | 1174 |  |  |          SSA_NAME, which can trap.  */
 | 
      
         | 1175 |  |  |       map.ssa_name = name;
 | 
      
         | 1176 |  |  |       map.bb = 0;
 | 
      
         | 1177 |  |  |       map.store = store;
 | 
      
         | 1178 |  |  |       slot = htab_find_slot (seen_ssa_names, &map, INSERT);
 | 
      
         | 1179 |  |  |       n2bb = (struct name_to_bb *) *slot;
 | 
      
         | 1180 |  |  |       if (n2bb)
 | 
      
         | 1181 |  |  |         found_bb = n2bb->bb;
 | 
      
         | 1182 |  |  |  
 | 
      
         | 1183 |  |  |       /* If we've found a trapping MEM_REF, _and_ it dominates EXP
 | 
      
         | 1184 |  |  |          (it's in a basic block on the path from us to the dominator root)
 | 
      
         | 1185 |  |  |          then we can't trap.  */
 | 
      
         | 1186 |  |  |       if (found_bb && found_bb->aux == (void *)1)
 | 
      
         | 1187 |  |  |         {
 | 
      
         | 1188 |  |  |           pointer_set_insert (nontrap, exp);
 | 
      
         | 1189 |  |  |         }
 | 
      
         | 1190 |  |  |       else
 | 
      
         | 1191 |  |  |         {
 | 
      
         | 1192 |  |  |           /* EXP might trap, so insert it into the hash table.  */
 | 
      
         | 1193 |  |  |           if (n2bb)
 | 
      
         | 1194 |  |  |             {
 | 
      
         | 1195 |  |  |               n2bb->bb = bb;
 | 
      
         | 1196 |  |  |             }
 | 
      
         | 1197 |  |  |           else
 | 
      
         | 1198 |  |  |             {
 | 
      
         | 1199 |  |  |               n2bb = XNEW (struct name_to_bb);
 | 
      
         | 1200 |  |  |               n2bb->ssa_name = name;
 | 
      
         | 1201 |  |  |               n2bb->bb = bb;
 | 
      
         | 1202 |  |  |               n2bb->store = store;
 | 
      
         | 1203 |  |  |               *slot = n2bb;
 | 
      
         | 1204 |  |  |             }
 | 
      
         | 1205 |  |  |         }
 | 
      
         | 1206 |  |  |     }
 | 
      
         | 1207 |  |  | }
 | 
      
         | 1208 |  |  |  
 | 
      
         | 1209 |  |  | /* Called by walk_dominator_tree, when entering the block BB.  */
 | 
      
         | 1210 |  |  | static void
 | 
      
         | 1211 |  |  | nt_init_block (struct dom_walk_data *data ATTRIBUTE_UNUSED, basic_block bb)
 | 
      
         | 1212 |  |  | {
 | 
      
         | 1213 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 1214 |  |  |   /* Mark this BB as being on the path to dominator root.  */
 | 
      
         | 1215 |  |  |   bb->aux = (void*)1;
 | 
      
         | 1216 |  |  |  
 | 
      
         | 1217 |  |  |   /* And walk the statements in order.  */
 | 
      
         | 1218 |  |  |   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
 | 
      
         | 1219 |  |  |     {
 | 
      
         | 1220 |  |  |       gimple stmt = gsi_stmt (gsi);
 | 
      
         | 1221 |  |  |  
 | 
      
         | 1222 |  |  |       if (is_gimple_assign (stmt))
 | 
      
         | 1223 |  |  |         {
 | 
      
         | 1224 |  |  |           add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true);
 | 
      
         | 1225 |  |  |           add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false);
 | 
      
         | 1226 |  |  |           if (get_gimple_rhs_num_ops (gimple_assign_rhs_code (stmt)) > 1)
 | 
      
         | 1227 |  |  |             add_or_mark_expr (bb, gimple_assign_rhs2 (stmt), nontrap_set,
 | 
      
         | 1228 |  |  |                               false);
 | 
      
         | 1229 |  |  |         }
 | 
      
         | 1230 |  |  |     }
 | 
      
         | 1231 |  |  | }
 | 
      
         | 1232 |  |  |  
 | 
      
         | 1233 |  |  | /* Called by walk_dominator_tree, when basic block BB is exited.  */
 | 
      
         | 1234 |  |  | static void
 | 
      
         | 1235 |  |  | nt_fini_block (struct dom_walk_data *data ATTRIBUTE_UNUSED, basic_block bb)
 | 
      
         | 1236 |  |  | {
 | 
      
         | 1237 |  |  |   /* This BB isn't on the path to dominator root anymore.  */
 | 
      
         | 1238 |  |  |   bb->aux = NULL;
 | 
      
         | 1239 |  |  | }
 | 
      
         | 1240 |  |  |  
 | 
      
         | 1241 |  |  | /* This is the entry point of gathering non trapping memory accesses.
 | 
      
         | 1242 |  |  |    It will do a dominator walk over the whole function, and it will
 | 
      
         | 1243 |  |  |    make use of the bb->aux pointers.  It returns a set of trees
 | 
      
         | 1244 |  |  |    (the MEM_REFs itself) which can't trap.  */
 | 
      
         | 1245 |  |  | static struct pointer_set_t *
 | 
      
         | 1246 |  |  | get_non_trapping (void)
 | 
      
         | 1247 |  |  | {
 | 
      
         | 1248 |  |  |   struct pointer_set_t *nontrap;
 | 
      
         | 1249 |  |  |   struct dom_walk_data walk_data;
 | 
      
         | 1250 |  |  |  
 | 
      
         | 1251 |  |  |   nontrap = pointer_set_create ();
 | 
      
         | 1252 |  |  |   seen_ssa_names = htab_create (128, name_to_bb_hash, name_to_bb_eq,
 | 
      
         | 1253 |  |  |                                 free);
 | 
      
         | 1254 |  |  |   /* We're going to do a dominator walk, so ensure that we have
 | 
      
         | 1255 |  |  |      dominance information.  */
 | 
      
         | 1256 |  |  |   calculate_dominance_info (CDI_DOMINATORS);
 | 
      
         | 1257 |  |  |  
 | 
      
         | 1258 |  |  |   /* Setup callbacks for the generic dominator tree walker.  */
 | 
      
         | 1259 |  |  |   nontrap_set = nontrap;
 | 
      
         | 1260 |  |  |   walk_data.dom_direction = CDI_DOMINATORS;
 | 
      
         | 1261 |  |  |   walk_data.initialize_block_local_data = NULL;
 | 
      
         | 1262 |  |  |   walk_data.before_dom_children = nt_init_block;
 | 
      
         | 1263 |  |  |   walk_data.after_dom_children = nt_fini_block;
 | 
      
         | 1264 |  |  |   walk_data.global_data = NULL;
 | 
      
         | 1265 |  |  |   walk_data.block_local_data_size = 0;
 | 
      
         | 1266 |  |  |  
 | 
      
         | 1267 |  |  |   init_walk_dominator_tree (&walk_data);
 | 
      
         | 1268 |  |  |   walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
 | 
      
         | 1269 |  |  |   fini_walk_dominator_tree (&walk_data);
 | 
      
         | 1270 |  |  |   htab_delete (seen_ssa_names);
 | 
      
         | 1271 |  |  |  
 | 
      
         | 1272 |  |  |   return nontrap;
 | 
      
         | 1273 |  |  | }
 | 
      
         | 1274 |  |  |  
 | 
      
         | 1275 |  |  | /* Do the main work of conditional store replacement.  We already know
 | 
      
         | 1276 |  |  |    that the recognized pattern looks like so:
 | 
      
         | 1277 |  |  |  
 | 
      
         | 1278 |  |  |    split:
 | 
      
         | 1279 |  |  |      if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
 | 
      
         | 1280 |  |  |    MIDDLE_BB:
 | 
      
         | 1281 |  |  |      something
 | 
      
         | 1282 |  |  |      fallthrough (edge E0)
 | 
      
         | 1283 |  |  |    JOIN_BB:
 | 
      
         | 1284 |  |  |      some more
 | 
      
         | 1285 |  |  |  
 | 
      
         | 1286 |  |  |    We check that MIDDLE_BB contains only one store, that that store
 | 
      
         | 1287 |  |  |    doesn't trap (not via NOTRAP, but via checking if an access to the same
 | 
      
         | 1288 |  |  |    memory location dominates us) and that the store has a "simple" RHS.  */
 | 
      
         | 1289 |  |  |  
 | 
      
         | 1290 |  |  | static bool
 | 
      
         | 1291 |  |  | cond_store_replacement (basic_block middle_bb, basic_block join_bb,
 | 
      
         | 1292 |  |  |                         edge e0, edge e1, struct pointer_set_t *nontrap)
 | 
      
         | 1293 |  |  | {
 | 
      
         | 1294 |  |  |   gimple assign = last_and_only_stmt (middle_bb);
 | 
      
         | 1295 |  |  |   tree lhs, rhs, name;
 | 
      
         | 1296 |  |  |   gimple newphi, new_stmt;
 | 
      
         | 1297 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 1298 |  |  |   source_location locus;
 | 
      
         | 1299 |  |  |  
 | 
      
         | 1300 |  |  |   /* Check if middle_bb contains of only one store.  */
 | 
      
         | 1301 |  |  |   if (!assign
 | 
      
         | 1302 |  |  |       || !gimple_assign_single_p (assign))
 | 
      
         | 1303 |  |  |     return false;
 | 
      
         | 1304 |  |  |  
 | 
      
         | 1305 |  |  |   locus = gimple_location (assign);
 | 
      
         | 1306 |  |  |   lhs = gimple_assign_lhs (assign);
 | 
      
         | 1307 |  |  |   rhs = gimple_assign_rhs1 (assign);
 | 
      
         | 1308 |  |  |   if (TREE_CODE (lhs) != MEM_REF
 | 
      
         | 1309 |  |  |       || TREE_CODE (TREE_OPERAND (lhs, 0)) != SSA_NAME
 | 
      
         | 1310 |  |  |       || !is_gimple_reg_type (TREE_TYPE (lhs)))
 | 
      
         | 1311 |  |  |     return false;
 | 
      
         | 1312 |  |  |  
 | 
      
         | 1313 |  |  |   /* Prove that we can move the store down.  We could also check
 | 
      
         | 1314 |  |  |      TREE_THIS_NOTRAP here, but in that case we also could move stores,
 | 
      
         | 1315 |  |  |      whose value is not available readily, which we want to avoid.  */
 | 
      
         | 1316 |  |  |   if (!pointer_set_contains (nontrap, lhs))
 | 
      
         | 1317 |  |  |     return false;
 | 
      
         | 1318 |  |  |  
 | 
      
         | 1319 |  |  |   /* Now we've checked the constraints, so do the transformation:
 | 
      
         | 1320 |  |  |      1) Remove the single store.  */
 | 
      
         | 1321 |  |  |   gsi = gsi_for_stmt (assign);
 | 
      
         | 1322 |  |  |   unlink_stmt_vdef (assign);
 | 
      
         | 1323 |  |  |   gsi_remove (&gsi, true);
 | 
      
         | 1324 |  |  |   release_defs (assign);
 | 
      
         | 1325 |  |  |  
 | 
      
         | 1326 |  |  |   /* 2) Create a temporary where we can store the old content
 | 
      
         | 1327 |  |  |         of the memory touched by the store, if we need to.  */
 | 
      
         | 1328 |  |  |   if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
 | 
      
         | 1329 |  |  |     condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
 | 
      
         | 1330 |  |  |   add_referenced_var (condstoretemp);
 | 
      
         | 1331 |  |  |  
 | 
      
         | 1332 |  |  |   /* 3) Insert a load from the memory of the store to the temporary
 | 
      
         | 1333 |  |  |         on the edge which did not contain the store.  */
 | 
      
         | 1334 |  |  |   lhs = unshare_expr (lhs);
 | 
      
         | 1335 |  |  |   new_stmt = gimple_build_assign (condstoretemp, lhs);
 | 
      
         | 1336 |  |  |   name = make_ssa_name (condstoretemp, new_stmt);
 | 
      
         | 1337 |  |  |   gimple_assign_set_lhs (new_stmt, name);
 | 
      
         | 1338 |  |  |   gimple_set_location (new_stmt, locus);
 | 
      
         | 1339 |  |  |   gsi_insert_on_edge (e1, new_stmt);
 | 
      
         | 1340 |  |  |  
 | 
      
         | 1341 |  |  |   /* 4) Create a PHI node at the join block, with one argument
 | 
      
         | 1342 |  |  |         holding the old RHS, and the other holding the temporary
 | 
      
         | 1343 |  |  |         where we stored the old memory contents.  */
 | 
      
         | 1344 |  |  |   newphi = create_phi_node (condstoretemp, join_bb);
 | 
      
         | 1345 |  |  |   add_phi_arg (newphi, rhs, e0, locus);
 | 
      
         | 1346 |  |  |   add_phi_arg (newphi, name, e1, locus);
 | 
      
         | 1347 |  |  |  
 | 
      
         | 1348 |  |  |   lhs = unshare_expr (lhs);
 | 
      
         | 1349 |  |  |   new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
 | 
      
         | 1350 |  |  |  
 | 
      
         | 1351 |  |  |   /* 5) Insert that PHI node.  */
 | 
      
         | 1352 |  |  |   gsi = gsi_after_labels (join_bb);
 | 
      
         | 1353 |  |  |   if (gsi_end_p (gsi))
 | 
      
         | 1354 |  |  |     {
 | 
      
         | 1355 |  |  |       gsi = gsi_last_bb (join_bb);
 | 
      
         | 1356 |  |  |       gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 1357 |  |  |     }
 | 
      
         | 1358 |  |  |   else
 | 
      
         | 1359 |  |  |     gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 1360 |  |  |  
 | 
      
         | 1361 |  |  |   return true;
 | 
      
         | 1362 |  |  | }
 | 
      
         | 1363 |  |  |  
 | 
      
         | 1364 |  |  | /* Do the main work of conditional store replacement.  */
 | 
      
         | 1365 |  |  |  
 | 
      
         | 1366 |  |  | static bool
 | 
      
         | 1367 |  |  | cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
 | 
      
         | 1368 |  |  |                                   basic_block join_bb, gimple then_assign,
 | 
      
         | 1369 |  |  |                                   gimple else_assign)
 | 
      
         | 1370 |  |  | {
 | 
      
         | 1371 |  |  |   tree lhs_base, lhs, then_rhs, else_rhs;
 | 
      
         | 1372 |  |  |   source_location then_locus, else_locus;
 | 
      
         | 1373 |  |  |   gimple_stmt_iterator gsi;
 | 
      
         | 1374 |  |  |   gimple newphi, new_stmt;
 | 
      
         | 1375 |  |  |  
 | 
      
         | 1376 |  |  |   if (then_assign == NULL
 | 
      
         | 1377 |  |  |       || !gimple_assign_single_p (then_assign)
 | 
      
         | 1378 |  |  |       || gimple_clobber_p (then_assign)
 | 
      
         | 1379 |  |  |       || else_assign == NULL
 | 
      
         | 1380 |  |  |       || !gimple_assign_single_p (else_assign)
 | 
      
         | 1381 |  |  |       || gimple_clobber_p (else_assign))
 | 
      
         | 1382 |  |  |     return false;
 | 
      
         | 1383 |  |  |  
 | 
      
         | 1384 |  |  |   lhs = gimple_assign_lhs (then_assign);
 | 
      
         | 1385 |  |  |   if (!is_gimple_reg_type (TREE_TYPE (lhs))
 | 
      
         | 1386 |  |  |       || !operand_equal_p (lhs, gimple_assign_lhs (else_assign), 0))
 | 
      
         | 1387 |  |  |     return false;
 | 
      
         | 1388 |  |  |  
 | 
      
         | 1389 |  |  |   lhs_base = get_base_address (lhs);
 | 
      
         | 1390 |  |  |   if (lhs_base == NULL_TREE
 | 
      
         | 1391 |  |  |       || (!DECL_P (lhs_base) && TREE_CODE (lhs_base) != MEM_REF))
 | 
      
         | 1392 |  |  |     return false;
 | 
      
         | 1393 |  |  |  
 | 
      
         | 1394 |  |  |   then_rhs = gimple_assign_rhs1 (then_assign);
 | 
      
         | 1395 |  |  |   else_rhs = gimple_assign_rhs1 (else_assign);
 | 
      
         | 1396 |  |  |   then_locus = gimple_location (then_assign);
 | 
      
         | 1397 |  |  |   else_locus = gimple_location (else_assign);
 | 
      
         | 1398 |  |  |  
 | 
      
         | 1399 |  |  |   /* Now we've checked the constraints, so do the transformation:
 | 
      
         | 1400 |  |  |      1) Remove the stores.  */
 | 
      
         | 1401 |  |  |   gsi = gsi_for_stmt (then_assign);
 | 
      
         | 1402 |  |  |   unlink_stmt_vdef (then_assign);
 | 
      
         | 1403 |  |  |   gsi_remove (&gsi, true);
 | 
      
         | 1404 |  |  |   release_defs (then_assign);
 | 
      
         | 1405 |  |  |  
 | 
      
         | 1406 |  |  |   gsi = gsi_for_stmt (else_assign);
 | 
      
         | 1407 |  |  |   unlink_stmt_vdef (else_assign);
 | 
      
         | 1408 |  |  |   gsi_remove (&gsi, true);
 | 
      
         | 1409 |  |  |   release_defs (else_assign);
 | 
      
         | 1410 |  |  |  
 | 
      
         | 1411 |  |  |   /* 2) Create a temporary where we can store the old content
 | 
      
         | 1412 |  |  |         of the memory touched by the store, if we need to.  */
 | 
      
         | 1413 |  |  |   if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
 | 
      
         | 1414 |  |  |     condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
 | 
      
         | 1415 |  |  |   add_referenced_var (condstoretemp);
 | 
      
         | 1416 |  |  |  
 | 
      
         | 1417 |  |  |   /* 3) Create a PHI node at the join block, with one argument
 | 
      
         | 1418 |  |  |         holding the old RHS, and the other holding the temporary
 | 
      
         | 1419 |  |  |         where we stored the old memory contents.  */
 | 
      
         | 1420 |  |  |   newphi = create_phi_node (condstoretemp, join_bb);
 | 
      
         | 1421 |  |  |   add_phi_arg (newphi, then_rhs, EDGE_SUCC (then_bb, 0), then_locus);
 | 
      
         | 1422 |  |  |   add_phi_arg (newphi, else_rhs, EDGE_SUCC (else_bb, 0), else_locus);
 | 
      
         | 1423 |  |  |  
 | 
      
         | 1424 |  |  |   new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
 | 
      
         | 1425 |  |  |  
 | 
      
         | 1426 |  |  |   /* 4) Insert that PHI node.  */
 | 
      
         | 1427 |  |  |   gsi = gsi_after_labels (join_bb);
 | 
      
         | 1428 |  |  |   if (gsi_end_p (gsi))
 | 
      
         | 1429 |  |  |     {
 | 
      
         | 1430 |  |  |       gsi = gsi_last_bb (join_bb);
 | 
      
         | 1431 |  |  |       gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 1432 |  |  |     }
 | 
      
         | 1433 |  |  |   else
 | 
      
         | 1434 |  |  |     gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
 | 
      
         | 1435 |  |  |  
 | 
      
         | 1436 |  |  |   return true;
 | 
      
         | 1437 |  |  | }
 | 
      
         | 1438 |  |  |  
 | 
      
         | 1439 |  |  | /* Conditional store replacement.  We already know
 | 
      
         | 1440 |  |  |    that the recognized pattern looks like so:
 | 
      
         | 1441 |  |  |  
 | 
      
         | 1442 |  |  |    split:
 | 
      
         | 1443 |  |  |      if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
 | 
      
         | 1444 |  |  |    THEN_BB:
 | 
      
         | 1445 |  |  |      ...
 | 
      
         | 1446 |  |  |      X = Y;
 | 
      
         | 1447 |  |  |      ...
 | 
      
         | 1448 |  |  |      goto JOIN_BB;
 | 
      
         | 1449 |  |  |    ELSE_BB:
 | 
      
         | 1450 |  |  |      ...
 | 
      
         | 1451 |  |  |      X = Z;
 | 
      
         | 1452 |  |  |      ...
 | 
      
         | 1453 |  |  |      fallthrough (edge E0)
 | 
      
         | 1454 |  |  |    JOIN_BB:
 | 
      
         | 1455 |  |  |      some more
 | 
      
         | 1456 |  |  |  
 | 
      
         | 1457 |  |  |    We check that it is safe to sink the store to JOIN_BB by verifying that
 | 
      
         | 1458 |  |  |    there are no read-after-write or write-after-write dependencies in
 | 
      
         | 1459 |  |  |    THEN_BB and ELSE_BB.  */
 | 
      
         | 1460 |  |  |  
 | 
      
         | 1461 |  |  | static bool
 | 
      
         | 1462 |  |  | cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
 | 
      
         | 1463 |  |  |                                 basic_block join_bb)
 | 
      
         | 1464 |  |  | {
 | 
      
         | 1465 |  |  |   gimple then_assign = last_and_only_stmt (then_bb);
 | 
      
         | 1466 |  |  |   gimple else_assign = last_and_only_stmt (else_bb);
 | 
      
         | 1467 |  |  |   VEC (data_reference_p, heap) *then_datarefs, *else_datarefs;
 | 
      
         | 1468 |  |  |   VEC (ddr_p, heap) *then_ddrs, *else_ddrs;
 | 
      
         | 1469 |  |  |   gimple then_store, else_store;
 | 
      
         | 1470 |  |  |   bool found, ok = false, res;
 | 
      
         | 1471 |  |  |   struct data_dependence_relation *ddr;
 | 
      
         | 1472 |  |  |   data_reference_p then_dr, else_dr;
 | 
      
         | 1473 |  |  |   int i, j;
 | 
      
         | 1474 |  |  |   tree then_lhs, else_lhs;
 | 
      
         | 1475 |  |  |   VEC (gimple, heap) *then_stores, *else_stores;
 | 
      
         | 1476 |  |  |   basic_block blocks[3];
 | 
      
         | 1477 |  |  |  
 | 
      
         | 1478 |  |  |   if (MAX_STORES_TO_SINK == 0)
 | 
      
         | 1479 |  |  |     return false;
 | 
      
         | 1480 |  |  |  
 | 
      
         | 1481 |  |  |   /* Handle the case with single statement in THEN_BB and ELSE_BB.  */
 | 
      
         | 1482 |  |  |   if (then_assign && else_assign)
 | 
      
         | 1483 |  |  |     return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
 | 
      
         | 1484 |  |  |                                              then_assign, else_assign);
 | 
      
         | 1485 |  |  |  
 | 
      
         | 1486 |  |  |   /* Find data references.  */
 | 
      
         | 1487 |  |  |   then_datarefs = VEC_alloc (data_reference_p, heap, 1);
 | 
      
         | 1488 |  |  |   else_datarefs = VEC_alloc (data_reference_p, heap, 1);
 | 
      
         | 1489 |  |  |   if ((find_data_references_in_bb (NULL, then_bb, &then_datarefs)
 | 
      
         | 1490 |  |  |         == chrec_dont_know)
 | 
      
         | 1491 |  |  |       || !VEC_length (data_reference_p, then_datarefs)
 | 
      
         | 1492 |  |  |       || (find_data_references_in_bb (NULL, else_bb, &else_datarefs)
 | 
      
         | 1493 |  |  |         == chrec_dont_know)
 | 
      
         | 1494 |  |  |       || !VEC_length (data_reference_p, else_datarefs))
 | 
      
         | 1495 |  |  |     {
 | 
      
         | 1496 |  |  |       free_data_refs (then_datarefs);
 | 
      
         | 1497 |  |  |       free_data_refs (else_datarefs);
 | 
      
         | 1498 |  |  |       return false;
 | 
      
         | 1499 |  |  |     }
 | 
      
         | 1500 |  |  |  
 | 
      
         | 1501 |  |  |   /* Find pairs of stores with equal LHS.  */
 | 
      
         | 1502 |  |  |   then_stores = VEC_alloc (gimple, heap, 1);
 | 
      
         | 1503 |  |  |   else_stores = VEC_alloc (gimple, heap, 1);
 | 
      
         | 1504 |  |  |   FOR_EACH_VEC_ELT (data_reference_p, then_datarefs, i, then_dr)
 | 
      
         | 1505 |  |  |     {
 | 
      
         | 1506 |  |  |       if (DR_IS_READ (then_dr))
 | 
      
         | 1507 |  |  |         continue;
 | 
      
         | 1508 |  |  |  
 | 
      
         | 1509 |  |  |       then_store = DR_STMT (then_dr);
 | 
      
         | 1510 |  |  |       then_lhs = gimple_get_lhs (then_store);
 | 
      
         | 1511 |  |  |       found = false;
 | 
      
         | 1512 |  |  |  
 | 
      
         | 1513 |  |  |       FOR_EACH_VEC_ELT (data_reference_p, else_datarefs, j, else_dr)
 | 
      
         | 1514 |  |  |         {
 | 
      
         | 1515 |  |  |           if (DR_IS_READ (else_dr))
 | 
      
         | 1516 |  |  |             continue;
 | 
      
         | 1517 |  |  |  
 | 
      
         | 1518 |  |  |           else_store = DR_STMT (else_dr);
 | 
      
         | 1519 |  |  |           else_lhs = gimple_get_lhs (else_store);
 | 
      
         | 1520 |  |  |  
 | 
      
         | 1521 |  |  |           if (operand_equal_p (then_lhs, else_lhs, 0))
 | 
      
         | 1522 |  |  |             {
 | 
      
         | 1523 |  |  |               found = true;
 | 
      
         | 1524 |  |  |               break;
 | 
      
         | 1525 |  |  |             }
 | 
      
         | 1526 |  |  |         }
 | 
      
         | 1527 |  |  |  
 | 
      
         | 1528 |  |  |       if (!found)
 | 
      
         | 1529 |  |  |         continue;
 | 
      
         | 1530 |  |  |  
 | 
      
         | 1531 |  |  |       VEC_safe_push (gimple, heap, then_stores, then_store);
 | 
      
         | 1532 |  |  |       VEC_safe_push (gimple, heap, else_stores, else_store);
 | 
      
         | 1533 |  |  |     }
 | 
      
         | 1534 |  |  |  
 | 
      
         | 1535 |  |  |   /* No pairs of stores found.  */
 | 
      
         | 1536 |  |  |   if (!VEC_length (gimple, then_stores)
 | 
      
         | 1537 |  |  |       || VEC_length (gimple, then_stores) > (unsigned) MAX_STORES_TO_SINK)
 | 
      
         | 1538 |  |  |     {
 | 
      
         | 1539 |  |  |       free_data_refs (then_datarefs);
 | 
      
         | 1540 |  |  |       free_data_refs (else_datarefs);
 | 
      
         | 1541 |  |  |       VEC_free (gimple, heap, then_stores);
 | 
      
         | 1542 |  |  |       VEC_free (gimple, heap, else_stores);
 | 
      
         | 1543 |  |  |       return false;
 | 
      
         | 1544 |  |  |     }
 | 
      
         | 1545 |  |  |  
 | 
      
         | 1546 |  |  |   /* Compute and check data dependencies in both basic blocks.  */
 | 
      
         | 1547 |  |  |   then_ddrs = VEC_alloc (ddr_p, heap, 1);
 | 
      
         | 1548 |  |  |   else_ddrs = VEC_alloc (ddr_p, heap, 1);
 | 
      
         | 1549 |  |  |   compute_all_dependences (then_datarefs, &then_ddrs, NULL, false);
 | 
      
         | 1550 |  |  |   compute_all_dependences (else_datarefs, &else_ddrs, NULL, false);
 | 
      
         | 1551 |  |  |   blocks[0] = then_bb;
 | 
      
         | 1552 |  |  |   blocks[1] = else_bb;
 | 
      
         | 1553 |  |  |   blocks[2] = join_bb;
 | 
      
         | 1554 |  |  |   renumber_gimple_stmt_uids_in_blocks (blocks, 3);
 | 
      
         | 1555 |  |  |  
 | 
      
         | 1556 |  |  |   /* Check that there are no read-after-write or write-after-write dependencies
 | 
      
         | 1557 |  |  |      in THEN_BB.  */
 | 
      
         | 1558 |  |  |   FOR_EACH_VEC_ELT (ddr_p, then_ddrs, i, ddr)
 | 
      
         | 1559 |  |  |     {
 | 
      
         | 1560 |  |  |       struct data_reference *dra = DDR_A (ddr);
 | 
      
         | 1561 |  |  |       struct data_reference *drb = DDR_B (ddr);
 | 
      
         | 1562 |  |  |  
 | 
      
         | 1563 |  |  |       if (DDR_ARE_DEPENDENT (ddr) != chrec_known
 | 
      
         | 1564 |  |  |           && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
 | 
      
         | 1565 |  |  |                && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
 | 
      
         | 1566 |  |  |               || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
 | 
      
         | 1567 |  |  |                   && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
 | 
      
         | 1568 |  |  |               || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
 | 
      
         | 1569 |  |  |         {
 | 
      
         | 1570 |  |  |           free_dependence_relations (then_ddrs);
 | 
      
         | 1571 |  |  |           free_dependence_relations (else_ddrs);
 | 
      
         | 1572 |  |  |           free_data_refs (then_datarefs);
 | 
      
         | 1573 |  |  |           free_data_refs (else_datarefs);
 | 
      
         | 1574 |  |  |           VEC_free (gimple, heap, then_stores);
 | 
      
         | 1575 |  |  |           VEC_free (gimple, heap, else_stores);
 | 
      
         | 1576 |  |  |           return false;
 | 
      
         | 1577 |  |  |         }
 | 
      
         | 1578 |  |  |     }
 | 
      
         | 1579 |  |  |  
 | 
      
         | 1580 |  |  |   /* Check that there are no read-after-write or write-after-write dependencies
 | 
      
         | 1581 |  |  |      in ELSE_BB.  */
 | 
      
         | 1582 |  |  |   FOR_EACH_VEC_ELT (ddr_p, else_ddrs, i, ddr)
 | 
      
         | 1583 |  |  |     {
 | 
      
         | 1584 |  |  |       struct data_reference *dra = DDR_A (ddr);
 | 
      
         | 1585 |  |  |       struct data_reference *drb = DDR_B (ddr);
 | 
      
         | 1586 |  |  |  
 | 
      
         | 1587 |  |  |       if (DDR_ARE_DEPENDENT (ddr) != chrec_known
 | 
      
         | 1588 |  |  |           && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
 | 
      
         | 1589 |  |  |                && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
 | 
      
         | 1590 |  |  |               || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
 | 
      
         | 1591 |  |  |                   && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
 | 
      
         | 1592 |  |  |               || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
 | 
      
         | 1593 |  |  |         {
 | 
      
         | 1594 |  |  |           free_dependence_relations (then_ddrs);
 | 
      
         | 1595 |  |  |           free_dependence_relations (else_ddrs);
 | 
      
         | 1596 |  |  |           free_data_refs (then_datarefs);
 | 
      
         | 1597 |  |  |           free_data_refs (else_datarefs);
 | 
      
         | 1598 |  |  |           VEC_free (gimple, heap, then_stores);
 | 
      
         | 1599 |  |  |           VEC_free (gimple, heap, else_stores);
 | 
      
         | 1600 |  |  |           return false;
 | 
      
         | 1601 |  |  |         }
 | 
      
         | 1602 |  |  |     }
 | 
      
         | 1603 |  |  |  
 | 
      
         | 1604 |  |  |   /* Sink stores with same LHS.  */
 | 
      
         | 1605 |  |  |   FOR_EACH_VEC_ELT (gimple, then_stores, i, then_store)
 | 
      
         | 1606 |  |  |     {
 | 
      
         | 1607 |  |  |       else_store = VEC_index (gimple, else_stores, i);
 | 
      
         | 1608 |  |  |       res = cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
 | 
      
         | 1609 |  |  |                                               then_store, else_store);
 | 
      
         | 1610 |  |  |       ok = ok || res;
 | 
      
         | 1611 |  |  |     }
 | 
      
         | 1612 |  |  |  
 | 
      
         | 1613 |  |  |   free_dependence_relations (then_ddrs);
 | 
      
         | 1614 |  |  |   free_dependence_relations (else_ddrs);
 | 
      
         | 1615 |  |  |   free_data_refs (then_datarefs);
 | 
      
         | 1616 |  |  |   free_data_refs (else_datarefs);
 | 
      
         | 1617 |  |  |   VEC_free (gimple, heap, then_stores);
 | 
      
         | 1618 |  |  |   VEC_free (gimple, heap, else_stores);
 | 
      
         | 1619 |  |  |  
 | 
      
         | 1620 |  |  |   return ok;
 | 
      
         | 1621 |  |  | }
 | 
      
         | 1622 |  |  |  
 | 
      
         | 1623 |  |  | /* Always do these optimizations if we have SSA
 | 
      
         | 1624 |  |  |    trees to work on.  */
 | 
      
         | 1625 |  |  | static bool
 | 
      
         | 1626 |  |  | gate_phiopt (void)
 | 
      
         | 1627 |  |  | {
 | 
      
         | 1628 |  |  |   return 1;
 | 
      
         | 1629 |  |  | }
 | 
      
         | 1630 |  |  |  
 | 
      
         | 1631 |  |  | struct gimple_opt_pass pass_phiopt =
 | 
      
         | 1632 |  |  | {
 | 
      
         | 1633 |  |  |  {
 | 
      
         | 1634 |  |  |   GIMPLE_PASS,
 | 
      
         | 1635 |  |  |   "phiopt",                             /* name */
 | 
      
         | 1636 |  |  |   gate_phiopt,                          /* gate */
 | 
      
         | 1637 |  |  |   tree_ssa_phiopt,                      /* execute */
 | 
      
         | 1638 |  |  |   NULL,                                 /* sub */
 | 
      
         | 1639 |  |  |   NULL,                                 /* next */
 | 
      
         | 1640 |  |  |   0,                                     /* static_pass_number */
 | 
      
         | 1641 |  |  |   TV_TREE_PHIOPT,                       /* tv_id */
 | 
      
         | 1642 |  |  |   PROP_cfg | PROP_ssa,                  /* properties_required */
 | 
      
         | 1643 |  |  |   0,                                     /* properties_provided */
 | 
      
         | 1644 |  |  |   0,                                     /* properties_destroyed */
 | 
      
         | 1645 |  |  |   0,                                     /* todo_flags_start */
 | 
      
         | 1646 |  |  |   TODO_ggc_collect
 | 
      
         | 1647 |  |  |     | TODO_verify_ssa
 | 
      
         | 1648 |  |  |     | TODO_verify_flow
 | 
      
         | 1649 |  |  |     | TODO_verify_stmts                 /* todo_flags_finish */
 | 
      
         | 1650 |  |  |  }
 | 
      
         | 1651 |  |  | };
 | 
      
         | 1652 |  |  |  
 | 
      
         | 1653 |  |  | static bool
 | 
      
         | 1654 |  |  | gate_cselim (void)
 | 
      
         | 1655 |  |  | {
 | 
      
         | 1656 |  |  |   return flag_tree_cselim;
 | 
      
         | 1657 |  |  | }
 | 
      
         | 1658 |  |  |  
 | 
      
         | 1659 |  |  | struct gimple_opt_pass pass_cselim =
 | 
      
         | 1660 |  |  | {
 | 
      
         | 1661 |  |  |  {
 | 
      
         | 1662 |  |  |   GIMPLE_PASS,
 | 
      
         | 1663 |  |  |   "cselim",                             /* name */
 | 
      
         | 1664 |  |  |   gate_cselim,                          /* gate */
 | 
      
         | 1665 |  |  |   tree_ssa_cs_elim,                     /* execute */
 | 
      
         | 1666 |  |  |   NULL,                                 /* sub */
 | 
      
         | 1667 |  |  |   NULL,                                 /* next */
 | 
      
         | 1668 |  |  |   0,                                     /* static_pass_number */
 | 
      
         | 1669 |  |  |   TV_TREE_PHIOPT,                       /* tv_id */
 | 
      
         | 1670 |  |  |   PROP_cfg | PROP_ssa,                  /* properties_required */
 | 
      
         | 1671 |  |  |   0,                                     /* properties_provided */
 | 
      
         | 1672 |  |  |   0,                                     /* properties_destroyed */
 | 
      
         | 1673 |  |  |   0,                                     /* todo_flags_start */
 | 
      
         | 1674 |  |  |   TODO_ggc_collect
 | 
      
         | 1675 |  |  |     | TODO_verify_ssa
 | 
      
         | 1676 |  |  |     | TODO_verify_flow
 | 
      
         | 1677 |  |  |     | TODO_verify_stmts                 /* todo_flags_finish */
 | 
      
         | 1678 |  |  |  }
 | 
      
         | 1679 |  |  | };
 |