1*e4b17023SJohn Marino /* Reassociation for trees. 2*e4b17023SJohn Marino Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011 3*e4b17023SJohn Marino Free Software Foundation, Inc. 4*e4b17023SJohn Marino Contributed by Daniel Berlin <dan@dberlin.org> 5*e4b17023SJohn Marino 6*e4b17023SJohn Marino This file is part of GCC. 7*e4b17023SJohn Marino 8*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify 9*e4b17023SJohn Marino it under the terms of the GNU General Public License as published by 10*e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option) 11*e4b17023SJohn Marino any later version. 12*e4b17023SJohn Marino 13*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, 14*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of 15*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*e4b17023SJohn Marino GNU General Public License for more details. 17*e4b17023SJohn Marino 18*e4b17023SJohn Marino You should have received a copy of the GNU General Public License 19*e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see 20*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */ 21*e4b17023SJohn Marino 22*e4b17023SJohn Marino #include "config.h" 23*e4b17023SJohn Marino #include "system.h" 24*e4b17023SJohn Marino #include "coretypes.h" 25*e4b17023SJohn Marino #include "tm.h" 26*e4b17023SJohn Marino #include "tree.h" 27*e4b17023SJohn Marino #include "basic-block.h" 28*e4b17023SJohn Marino #include "tree-pretty-print.h" 29*e4b17023SJohn Marino #include "gimple-pretty-print.h" 30*e4b17023SJohn Marino #include "tree-inline.h" 31*e4b17023SJohn Marino #include "tree-flow.h" 32*e4b17023SJohn Marino #include "gimple.h" 33*e4b17023SJohn Marino #include "tree-dump.h" 34*e4b17023SJohn Marino #include "timevar.h" 35*e4b17023SJohn Marino #include "tree-iterator.h" 36*e4b17023SJohn Marino #include "tree-pass.h" 37*e4b17023SJohn Marino #include "alloc-pool.h" 38*e4b17023SJohn Marino #include "vec.h" 39*e4b17023SJohn Marino #include "langhooks.h" 40*e4b17023SJohn Marino #include "pointer-set.h" 41*e4b17023SJohn Marino #include "cfgloop.h" 42*e4b17023SJohn Marino #include "flags.h" 43*e4b17023SJohn Marino #include "target.h" 44*e4b17023SJohn Marino #include "params.h" 45*e4b17023SJohn Marino #include "diagnostic-core.h" 46*e4b17023SJohn Marino 47*e4b17023SJohn Marino /* This is a simple global reassociation pass. It is, in part, based 48*e4b17023SJohn Marino on the LLVM pass of the same name (They do some things more/less 49*e4b17023SJohn Marino than we do, in different orders, etc). 50*e4b17023SJohn Marino 51*e4b17023SJohn Marino It consists of five steps: 52*e4b17023SJohn Marino 53*e4b17023SJohn Marino 1. Breaking up subtract operations into addition + negate, where 54*e4b17023SJohn Marino it would promote the reassociation of adds. 55*e4b17023SJohn Marino 56*e4b17023SJohn Marino 2. Left linearization of the expression trees, so that (A+B)+(C+D) 57*e4b17023SJohn Marino becomes (((A+B)+C)+D), which is easier for us to rewrite later. 58*e4b17023SJohn Marino During linearization, we place the operands of the binary 59*e4b17023SJohn Marino expressions into a vector of operand_entry_t 60*e4b17023SJohn Marino 61*e4b17023SJohn Marino 3. Optimization of the operand lists, eliminating things like a + 62*e4b17023SJohn Marino -a, a & a, etc. 63*e4b17023SJohn Marino 64*e4b17023SJohn Marino 4. Rewrite the expression trees we linearized and optimized so 65*e4b17023SJohn Marino they are in proper rank order. 66*e4b17023SJohn Marino 67*e4b17023SJohn Marino 5. Repropagate negates, as nothing else will clean it up ATM. 68*e4b17023SJohn Marino 69*e4b17023SJohn Marino A bit of theory on #4, since nobody seems to write anything down 70*e4b17023SJohn Marino about why it makes sense to do it the way they do it: 71*e4b17023SJohn Marino 72*e4b17023SJohn Marino We could do this much nicer theoretically, but don't (for reasons 73*e4b17023SJohn Marino explained after how to do it theoretically nice :P). 74*e4b17023SJohn Marino 75*e4b17023SJohn Marino In order to promote the most redundancy elimination, you want 76*e4b17023SJohn Marino binary expressions whose operands are the same rank (or 77*e4b17023SJohn Marino preferably, the same value) exposed to the redundancy eliminator, 78*e4b17023SJohn Marino for possible elimination. 79*e4b17023SJohn Marino 80*e4b17023SJohn Marino So the way to do this if we really cared, is to build the new op 81*e4b17023SJohn Marino tree from the leaves to the roots, merging as you go, and putting the 82*e4b17023SJohn Marino new op on the end of the worklist, until you are left with one 83*e4b17023SJohn Marino thing on the worklist. 84*e4b17023SJohn Marino 85*e4b17023SJohn Marino IE if you have to rewrite the following set of operands (listed with 86*e4b17023SJohn Marino rank in parentheses), with opcode PLUS_EXPR: 87*e4b17023SJohn Marino 88*e4b17023SJohn Marino a (1), b (1), c (1), d (2), e (2) 89*e4b17023SJohn Marino 90*e4b17023SJohn Marino 91*e4b17023SJohn Marino We start with our merge worklist empty, and the ops list with all of 92*e4b17023SJohn Marino those on it. 93*e4b17023SJohn Marino 94*e4b17023SJohn Marino You want to first merge all leaves of the same rank, as much as 95*e4b17023SJohn Marino possible. 96*e4b17023SJohn Marino 97*e4b17023SJohn Marino So first build a binary op of 98*e4b17023SJohn Marino 99*e4b17023SJohn Marino mergetmp = a + b, and put "mergetmp" on the merge worklist. 100*e4b17023SJohn Marino 101*e4b17023SJohn Marino Because there is no three operand form of PLUS_EXPR, c is not going to 102*e4b17023SJohn Marino be exposed to redundancy elimination as a rank 1 operand. 103*e4b17023SJohn Marino 104*e4b17023SJohn Marino So you might as well throw it on the merge worklist (you could also 105*e4b17023SJohn Marino consider it to now be a rank two operand, and merge it with d and e, 106*e4b17023SJohn Marino but in this case, you then have evicted e from a binary op. So at 107*e4b17023SJohn Marino least in this situation, you can't win.) 108*e4b17023SJohn Marino 109*e4b17023SJohn Marino Then build a binary op of d + e 110*e4b17023SJohn Marino mergetmp2 = d + e 111*e4b17023SJohn Marino 112*e4b17023SJohn Marino and put mergetmp2 on the merge worklist. 113*e4b17023SJohn Marino 114*e4b17023SJohn Marino so merge worklist = {mergetmp, c, mergetmp2} 115*e4b17023SJohn Marino 116*e4b17023SJohn Marino Continue building binary ops of these operations until you have only 117*e4b17023SJohn Marino one operation left on the worklist. 118*e4b17023SJohn Marino 119*e4b17023SJohn Marino So we have 120*e4b17023SJohn Marino 121*e4b17023SJohn Marino build binary op 122*e4b17023SJohn Marino mergetmp3 = mergetmp + c 123*e4b17023SJohn Marino 124*e4b17023SJohn Marino worklist = {mergetmp2, mergetmp3} 125*e4b17023SJohn Marino 126*e4b17023SJohn Marino mergetmp4 = mergetmp2 + mergetmp3 127*e4b17023SJohn Marino 128*e4b17023SJohn Marino worklist = {mergetmp4} 129*e4b17023SJohn Marino 130*e4b17023SJohn Marino because we have one operation left, we can now just set the original 131*e4b17023SJohn Marino statement equal to the result of that operation. 132*e4b17023SJohn Marino 133*e4b17023SJohn Marino This will at least expose a + b and d + e to redundancy elimination 134*e4b17023SJohn Marino as binary operations. 135*e4b17023SJohn Marino 136*e4b17023SJohn Marino For extra points, you can reuse the old statements to build the 137*e4b17023SJohn Marino mergetmps, since you shouldn't run out. 138*e4b17023SJohn Marino 139*e4b17023SJohn Marino So why don't we do this? 140*e4b17023SJohn Marino 141*e4b17023SJohn Marino Because it's expensive, and rarely will help. Most trees we are 142*e4b17023SJohn Marino reassociating have 3 or less ops. If they have 2 ops, they already 143*e4b17023SJohn Marino will be written into a nice single binary op. If you have 3 ops, a 144*e4b17023SJohn Marino single simple check suffices to tell you whether the first two are of the 145*e4b17023SJohn Marino same rank. If so, you know to order it 146*e4b17023SJohn Marino 147*e4b17023SJohn Marino mergetmp = op1 + op2 148*e4b17023SJohn Marino newstmt = mergetmp + op3 149*e4b17023SJohn Marino 150*e4b17023SJohn Marino instead of 151*e4b17023SJohn Marino mergetmp = op2 + op3 152*e4b17023SJohn Marino newstmt = mergetmp + op1 153*e4b17023SJohn Marino 154*e4b17023SJohn Marino If all three are of the same rank, you can't expose them all in a 155*e4b17023SJohn Marino single binary operator anyway, so the above is *still* the best you 156*e4b17023SJohn Marino can do. 157*e4b17023SJohn Marino 158*e4b17023SJohn Marino Thus, this is what we do. When we have three ops left, we check to see 159*e4b17023SJohn Marino what order to put them in, and call it a day. As a nod to vector sum 160*e4b17023SJohn Marino reduction, we check if any of the ops are really a phi node that is a 161*e4b17023SJohn Marino destructive update for the associating op, and keep the destructive 162*e4b17023SJohn Marino update together for vector sum reduction recognition. */ 163*e4b17023SJohn Marino 164*e4b17023SJohn Marino 165*e4b17023SJohn Marino /* Statistics */ 166*e4b17023SJohn Marino static struct 167*e4b17023SJohn Marino { 168*e4b17023SJohn Marino int linearized; 169*e4b17023SJohn Marino int constants_eliminated; 170*e4b17023SJohn Marino int ops_eliminated; 171*e4b17023SJohn Marino int rewritten; 172*e4b17023SJohn Marino } reassociate_stats; 173*e4b17023SJohn Marino 174*e4b17023SJohn Marino /* Operator, rank pair. */ 175*e4b17023SJohn Marino typedef struct operand_entry 176*e4b17023SJohn Marino { 177*e4b17023SJohn Marino unsigned int rank; 178*e4b17023SJohn Marino int id; 179*e4b17023SJohn Marino tree op; 180*e4b17023SJohn Marino } *operand_entry_t; 181*e4b17023SJohn Marino 182*e4b17023SJohn Marino static alloc_pool operand_entry_pool; 183*e4b17023SJohn Marino 184*e4b17023SJohn Marino /* This is used to assign a unique ID to each struct operand_entry 185*e4b17023SJohn Marino so that qsort results are identical on different hosts. */ 186*e4b17023SJohn Marino static int next_operand_entry_id; 187*e4b17023SJohn Marino 188*e4b17023SJohn Marino /* Starting rank number for a given basic block, so that we can rank 189*e4b17023SJohn Marino operations using unmovable instructions in that BB based on the bb 190*e4b17023SJohn Marino depth. */ 191*e4b17023SJohn Marino static long *bb_rank; 192*e4b17023SJohn Marino 193*e4b17023SJohn Marino /* Operand->rank hashtable. */ 194*e4b17023SJohn Marino static struct pointer_map_t *operand_rank; 195*e4b17023SJohn Marino 196*e4b17023SJohn Marino /* Forward decls. */ 197*e4b17023SJohn Marino static long get_rank (tree); 198*e4b17023SJohn Marino 199*e4b17023SJohn Marino 200*e4b17023SJohn Marino /* Bias amount for loop-carried phis. We want this to be larger than 201*e4b17023SJohn Marino the depth of any reassociation tree we can see, but not larger than 202*e4b17023SJohn Marino the rank difference between two blocks. */ 203*e4b17023SJohn Marino #define PHI_LOOP_BIAS (1 << 15) 204*e4b17023SJohn Marino 205*e4b17023SJohn Marino /* Rank assigned to a phi statement. If STMT is a loop-carried phi of 206*e4b17023SJohn Marino an innermost loop, and the phi has only a single use which is inside 207*e4b17023SJohn Marino the loop, then the rank is the block rank of the loop latch plus an 208*e4b17023SJohn Marino extra bias for the loop-carried dependence. This causes expressions 209*e4b17023SJohn Marino calculated into an accumulator variable to be independent for each 210*e4b17023SJohn Marino iteration of the loop. If STMT is some other phi, the rank is the 211*e4b17023SJohn Marino block rank of its containing block. */ 212*e4b17023SJohn Marino static long 213*e4b17023SJohn Marino phi_rank (gimple stmt) 214*e4b17023SJohn Marino { 215*e4b17023SJohn Marino basic_block bb = gimple_bb (stmt); 216*e4b17023SJohn Marino struct loop *father = bb->loop_father; 217*e4b17023SJohn Marino tree res; 218*e4b17023SJohn Marino unsigned i; 219*e4b17023SJohn Marino use_operand_p use; 220*e4b17023SJohn Marino gimple use_stmt; 221*e4b17023SJohn Marino 222*e4b17023SJohn Marino /* We only care about real loops (those with a latch). */ 223*e4b17023SJohn Marino if (!father->latch) 224*e4b17023SJohn Marino return bb_rank[bb->index]; 225*e4b17023SJohn Marino 226*e4b17023SJohn Marino /* Interesting phis must be in headers of innermost loops. */ 227*e4b17023SJohn Marino if (bb != father->header 228*e4b17023SJohn Marino || father->inner) 229*e4b17023SJohn Marino return bb_rank[bb->index]; 230*e4b17023SJohn Marino 231*e4b17023SJohn Marino /* Ignore virtual SSA_NAMEs. */ 232*e4b17023SJohn Marino res = gimple_phi_result (stmt); 233*e4b17023SJohn Marino if (!is_gimple_reg (SSA_NAME_VAR (res))) 234*e4b17023SJohn Marino return bb_rank[bb->index]; 235*e4b17023SJohn Marino 236*e4b17023SJohn Marino /* The phi definition must have a single use, and that use must be 237*e4b17023SJohn Marino within the loop. Otherwise this isn't an accumulator pattern. */ 238*e4b17023SJohn Marino if (!single_imm_use (res, &use, &use_stmt) 239*e4b17023SJohn Marino || gimple_bb (use_stmt)->loop_father != father) 240*e4b17023SJohn Marino return bb_rank[bb->index]; 241*e4b17023SJohn Marino 242*e4b17023SJohn Marino /* Look for phi arguments from within the loop. If found, bias this phi. */ 243*e4b17023SJohn Marino for (i = 0; i < gimple_phi_num_args (stmt); i++) 244*e4b17023SJohn Marino { 245*e4b17023SJohn Marino tree arg = gimple_phi_arg_def (stmt, i); 246*e4b17023SJohn Marino if (TREE_CODE (arg) == SSA_NAME 247*e4b17023SJohn Marino && !SSA_NAME_IS_DEFAULT_DEF (arg)) 248*e4b17023SJohn Marino { 249*e4b17023SJohn Marino gimple def_stmt = SSA_NAME_DEF_STMT (arg); 250*e4b17023SJohn Marino if (gimple_bb (def_stmt)->loop_father == father) 251*e4b17023SJohn Marino return bb_rank[father->latch->index] + PHI_LOOP_BIAS; 252*e4b17023SJohn Marino } 253*e4b17023SJohn Marino } 254*e4b17023SJohn Marino 255*e4b17023SJohn Marino /* Must be an uninteresting phi. */ 256*e4b17023SJohn Marino return bb_rank[bb->index]; 257*e4b17023SJohn Marino } 258*e4b17023SJohn Marino 259*e4b17023SJohn Marino /* If EXP is an SSA_NAME defined by a PHI statement that represents a 260*e4b17023SJohn Marino loop-carried dependence of an innermost loop, return TRUE; else 261*e4b17023SJohn Marino return FALSE. */ 262*e4b17023SJohn Marino static bool 263*e4b17023SJohn Marino loop_carried_phi (tree exp) 264*e4b17023SJohn Marino { 265*e4b17023SJohn Marino gimple phi_stmt; 266*e4b17023SJohn Marino long block_rank; 267*e4b17023SJohn Marino 268*e4b17023SJohn Marino if (TREE_CODE (exp) != SSA_NAME 269*e4b17023SJohn Marino || SSA_NAME_IS_DEFAULT_DEF (exp)) 270*e4b17023SJohn Marino return false; 271*e4b17023SJohn Marino 272*e4b17023SJohn Marino phi_stmt = SSA_NAME_DEF_STMT (exp); 273*e4b17023SJohn Marino 274*e4b17023SJohn Marino if (gimple_code (SSA_NAME_DEF_STMT (exp)) != GIMPLE_PHI) 275*e4b17023SJohn Marino return false; 276*e4b17023SJohn Marino 277*e4b17023SJohn Marino /* Non-loop-carried phis have block rank. Loop-carried phis have 278*e4b17023SJohn Marino an additional bias added in. If this phi doesn't have block rank, 279*e4b17023SJohn Marino it's biased and should not be propagated. */ 280*e4b17023SJohn Marino block_rank = bb_rank[gimple_bb (phi_stmt)->index]; 281*e4b17023SJohn Marino 282*e4b17023SJohn Marino if (phi_rank (phi_stmt) != block_rank) 283*e4b17023SJohn Marino return true; 284*e4b17023SJohn Marino 285*e4b17023SJohn Marino return false; 286*e4b17023SJohn Marino } 287*e4b17023SJohn Marino 288*e4b17023SJohn Marino /* Return the maximum of RANK and the rank that should be propagated 289*e4b17023SJohn Marino from expression OP. For most operands, this is just the rank of OP. 290*e4b17023SJohn Marino For loop-carried phis, the value is zero to avoid undoing the bias 291*e4b17023SJohn Marino in favor of the phi. */ 292*e4b17023SJohn Marino static long 293*e4b17023SJohn Marino propagate_rank (long rank, tree op) 294*e4b17023SJohn Marino { 295*e4b17023SJohn Marino long op_rank; 296*e4b17023SJohn Marino 297*e4b17023SJohn Marino if (loop_carried_phi (op)) 298*e4b17023SJohn Marino return rank; 299*e4b17023SJohn Marino 300*e4b17023SJohn Marino op_rank = get_rank (op); 301*e4b17023SJohn Marino 302*e4b17023SJohn Marino return MAX (rank, op_rank); 303*e4b17023SJohn Marino } 304*e4b17023SJohn Marino 305*e4b17023SJohn Marino /* Look up the operand rank structure for expression E. */ 306*e4b17023SJohn Marino 307*e4b17023SJohn Marino static inline long 308*e4b17023SJohn Marino find_operand_rank (tree e) 309*e4b17023SJohn Marino { 310*e4b17023SJohn Marino void **slot = pointer_map_contains (operand_rank, e); 311*e4b17023SJohn Marino return slot ? (long) (intptr_t) *slot : -1; 312*e4b17023SJohn Marino } 313*e4b17023SJohn Marino 314*e4b17023SJohn Marino /* Insert {E,RANK} into the operand rank hashtable. */ 315*e4b17023SJohn Marino 316*e4b17023SJohn Marino static inline void 317*e4b17023SJohn Marino insert_operand_rank (tree e, long rank) 318*e4b17023SJohn Marino { 319*e4b17023SJohn Marino void **slot; 320*e4b17023SJohn Marino gcc_assert (rank > 0); 321*e4b17023SJohn Marino slot = pointer_map_insert (operand_rank, e); 322*e4b17023SJohn Marino gcc_assert (!*slot); 323*e4b17023SJohn Marino *slot = (void *) (intptr_t) rank; 324*e4b17023SJohn Marino } 325*e4b17023SJohn Marino 326*e4b17023SJohn Marino /* Given an expression E, return the rank of the expression. */ 327*e4b17023SJohn Marino 328*e4b17023SJohn Marino static long 329*e4b17023SJohn Marino get_rank (tree e) 330*e4b17023SJohn Marino { 331*e4b17023SJohn Marino /* Constants have rank 0. */ 332*e4b17023SJohn Marino if (is_gimple_min_invariant (e)) 333*e4b17023SJohn Marino return 0; 334*e4b17023SJohn Marino 335*e4b17023SJohn Marino /* SSA_NAME's have the rank of the expression they are the result 336*e4b17023SJohn Marino of. 337*e4b17023SJohn Marino For globals and uninitialized values, the rank is 0. 338*e4b17023SJohn Marino For function arguments, use the pre-setup rank. 339*e4b17023SJohn Marino For PHI nodes, stores, asm statements, etc, we use the rank of 340*e4b17023SJohn Marino the BB. 341*e4b17023SJohn Marino For simple operations, the rank is the maximum rank of any of 342*e4b17023SJohn Marino its operands, or the bb_rank, whichever is less. 343*e4b17023SJohn Marino I make no claims that this is optimal, however, it gives good 344*e4b17023SJohn Marino results. */ 345*e4b17023SJohn Marino 346*e4b17023SJohn Marino /* We make an exception to the normal ranking system to break 347*e4b17023SJohn Marino dependences of accumulator variables in loops. Suppose we 348*e4b17023SJohn Marino have a simple one-block loop containing: 349*e4b17023SJohn Marino 350*e4b17023SJohn Marino x_1 = phi(x_0, x_2) 351*e4b17023SJohn Marino b = a + x_1 352*e4b17023SJohn Marino c = b + d 353*e4b17023SJohn Marino x_2 = c + e 354*e4b17023SJohn Marino 355*e4b17023SJohn Marino As shown, each iteration of the calculation into x is fully 356*e4b17023SJohn Marino dependent upon the iteration before it. We would prefer to 357*e4b17023SJohn Marino see this in the form: 358*e4b17023SJohn Marino 359*e4b17023SJohn Marino x_1 = phi(x_0, x_2) 360*e4b17023SJohn Marino b = a + d 361*e4b17023SJohn Marino c = b + e 362*e4b17023SJohn Marino x_2 = c + x_1 363*e4b17023SJohn Marino 364*e4b17023SJohn Marino If the loop is unrolled, the calculations of b and c from 365*e4b17023SJohn Marino different iterations can be interleaved. 366*e4b17023SJohn Marino 367*e4b17023SJohn Marino To obtain this result during reassociation, we bias the rank 368*e4b17023SJohn Marino of the phi definition x_1 upward, when it is recognized as an 369*e4b17023SJohn Marino accumulator pattern. The artificial rank causes it to be 370*e4b17023SJohn Marino added last, providing the desired independence. */ 371*e4b17023SJohn Marino 372*e4b17023SJohn Marino if (TREE_CODE (e) == SSA_NAME) 373*e4b17023SJohn Marino { 374*e4b17023SJohn Marino gimple stmt; 375*e4b17023SJohn Marino long rank; 376*e4b17023SJohn Marino int i, n; 377*e4b17023SJohn Marino tree op; 378*e4b17023SJohn Marino 379*e4b17023SJohn Marino if (TREE_CODE (SSA_NAME_VAR (e)) == PARM_DECL 380*e4b17023SJohn Marino && SSA_NAME_IS_DEFAULT_DEF (e)) 381*e4b17023SJohn Marino return find_operand_rank (e); 382*e4b17023SJohn Marino 383*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (e); 384*e4b17023SJohn Marino if (gimple_bb (stmt) == NULL) 385*e4b17023SJohn Marino return 0; 386*e4b17023SJohn Marino 387*e4b17023SJohn Marino if (gimple_code (stmt) == GIMPLE_PHI) 388*e4b17023SJohn Marino return phi_rank (stmt); 389*e4b17023SJohn Marino 390*e4b17023SJohn Marino if (!is_gimple_assign (stmt) 391*e4b17023SJohn Marino || gimple_vdef (stmt)) 392*e4b17023SJohn Marino return bb_rank[gimple_bb (stmt)->index]; 393*e4b17023SJohn Marino 394*e4b17023SJohn Marino /* If we already have a rank for this expression, use that. */ 395*e4b17023SJohn Marino rank = find_operand_rank (e); 396*e4b17023SJohn Marino if (rank != -1) 397*e4b17023SJohn Marino return rank; 398*e4b17023SJohn Marino 399*e4b17023SJohn Marino /* Otherwise, find the maximum rank for the operands. As an 400*e4b17023SJohn Marino exception, remove the bias from loop-carried phis when propagating 401*e4b17023SJohn Marino the rank so that dependent operations are not also biased. */ 402*e4b17023SJohn Marino rank = 0; 403*e4b17023SJohn Marino if (gimple_assign_single_p (stmt)) 404*e4b17023SJohn Marino { 405*e4b17023SJohn Marino tree rhs = gimple_assign_rhs1 (stmt); 406*e4b17023SJohn Marino n = TREE_OPERAND_LENGTH (rhs); 407*e4b17023SJohn Marino if (n == 0) 408*e4b17023SJohn Marino rank = propagate_rank (rank, rhs); 409*e4b17023SJohn Marino else 410*e4b17023SJohn Marino { 411*e4b17023SJohn Marino for (i = 0; i < n; i++) 412*e4b17023SJohn Marino { 413*e4b17023SJohn Marino op = TREE_OPERAND (rhs, i); 414*e4b17023SJohn Marino 415*e4b17023SJohn Marino if (op != NULL_TREE) 416*e4b17023SJohn Marino rank = propagate_rank (rank, op); 417*e4b17023SJohn Marino } 418*e4b17023SJohn Marino } 419*e4b17023SJohn Marino } 420*e4b17023SJohn Marino else 421*e4b17023SJohn Marino { 422*e4b17023SJohn Marino n = gimple_num_ops (stmt); 423*e4b17023SJohn Marino for (i = 1; i < n; i++) 424*e4b17023SJohn Marino { 425*e4b17023SJohn Marino op = gimple_op (stmt, i); 426*e4b17023SJohn Marino gcc_assert (op); 427*e4b17023SJohn Marino rank = propagate_rank (rank, op); 428*e4b17023SJohn Marino } 429*e4b17023SJohn Marino } 430*e4b17023SJohn Marino 431*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 432*e4b17023SJohn Marino { 433*e4b17023SJohn Marino fprintf (dump_file, "Rank for "); 434*e4b17023SJohn Marino print_generic_expr (dump_file, e, 0); 435*e4b17023SJohn Marino fprintf (dump_file, " is %ld\n", (rank + 1)); 436*e4b17023SJohn Marino } 437*e4b17023SJohn Marino 438*e4b17023SJohn Marino /* Note the rank in the hashtable so we don't recompute it. */ 439*e4b17023SJohn Marino insert_operand_rank (e, (rank + 1)); 440*e4b17023SJohn Marino return (rank + 1); 441*e4b17023SJohn Marino } 442*e4b17023SJohn Marino 443*e4b17023SJohn Marino /* Globals, etc, are rank 0 */ 444*e4b17023SJohn Marino return 0; 445*e4b17023SJohn Marino } 446*e4b17023SJohn Marino 447*e4b17023SJohn Marino DEF_VEC_P(operand_entry_t); 448*e4b17023SJohn Marino DEF_VEC_ALLOC_P(operand_entry_t, heap); 449*e4b17023SJohn Marino 450*e4b17023SJohn Marino /* We want integer ones to end up last no matter what, since they are 451*e4b17023SJohn Marino the ones we can do the most with. */ 452*e4b17023SJohn Marino #define INTEGER_CONST_TYPE 1 << 3 453*e4b17023SJohn Marino #define FLOAT_CONST_TYPE 1 << 2 454*e4b17023SJohn Marino #define OTHER_CONST_TYPE 1 << 1 455*e4b17023SJohn Marino 456*e4b17023SJohn Marino /* Classify an invariant tree into integer, float, or other, so that 457*e4b17023SJohn Marino we can sort them to be near other constants of the same type. */ 458*e4b17023SJohn Marino static inline int 459*e4b17023SJohn Marino constant_type (tree t) 460*e4b17023SJohn Marino { 461*e4b17023SJohn Marino if (INTEGRAL_TYPE_P (TREE_TYPE (t))) 462*e4b17023SJohn Marino return INTEGER_CONST_TYPE; 463*e4b17023SJohn Marino else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (t))) 464*e4b17023SJohn Marino return FLOAT_CONST_TYPE; 465*e4b17023SJohn Marino else 466*e4b17023SJohn Marino return OTHER_CONST_TYPE; 467*e4b17023SJohn Marino } 468*e4b17023SJohn Marino 469*e4b17023SJohn Marino /* qsort comparison function to sort operand entries PA and PB by rank 470*e4b17023SJohn Marino so that the sorted array is ordered by rank in decreasing order. */ 471*e4b17023SJohn Marino static int 472*e4b17023SJohn Marino sort_by_operand_rank (const void *pa, const void *pb) 473*e4b17023SJohn Marino { 474*e4b17023SJohn Marino const operand_entry_t oea = *(const operand_entry_t *)pa; 475*e4b17023SJohn Marino const operand_entry_t oeb = *(const operand_entry_t *)pb; 476*e4b17023SJohn Marino 477*e4b17023SJohn Marino /* It's nicer for optimize_expression if constants that are likely 478*e4b17023SJohn Marino to fold when added/multiplied//whatever are put next to each 479*e4b17023SJohn Marino other. Since all constants have rank 0, order them by type. */ 480*e4b17023SJohn Marino if (oeb->rank == 0 && oea->rank == 0) 481*e4b17023SJohn Marino { 482*e4b17023SJohn Marino if (constant_type (oeb->op) != constant_type (oea->op)) 483*e4b17023SJohn Marino return constant_type (oeb->op) - constant_type (oea->op); 484*e4b17023SJohn Marino else 485*e4b17023SJohn Marino /* To make sorting result stable, we use unique IDs to determine 486*e4b17023SJohn Marino order. */ 487*e4b17023SJohn Marino return oeb->id - oea->id; 488*e4b17023SJohn Marino } 489*e4b17023SJohn Marino 490*e4b17023SJohn Marino /* Lastly, make sure the versions that are the same go next to each 491*e4b17023SJohn Marino other. We use SSA_NAME_VERSION because it's stable. */ 492*e4b17023SJohn Marino if ((oeb->rank - oea->rank == 0) 493*e4b17023SJohn Marino && TREE_CODE (oea->op) == SSA_NAME 494*e4b17023SJohn Marino && TREE_CODE (oeb->op) == SSA_NAME) 495*e4b17023SJohn Marino { 496*e4b17023SJohn Marino if (SSA_NAME_VERSION (oeb->op) != SSA_NAME_VERSION (oea->op)) 497*e4b17023SJohn Marino return SSA_NAME_VERSION (oeb->op) - SSA_NAME_VERSION (oea->op); 498*e4b17023SJohn Marino else 499*e4b17023SJohn Marino return oeb->id - oea->id; 500*e4b17023SJohn Marino } 501*e4b17023SJohn Marino 502*e4b17023SJohn Marino if (oeb->rank != oea->rank) 503*e4b17023SJohn Marino return oeb->rank - oea->rank; 504*e4b17023SJohn Marino else 505*e4b17023SJohn Marino return oeb->id - oea->id; 506*e4b17023SJohn Marino } 507*e4b17023SJohn Marino 508*e4b17023SJohn Marino /* Add an operand entry to *OPS for the tree operand OP. */ 509*e4b17023SJohn Marino 510*e4b17023SJohn Marino static void 511*e4b17023SJohn Marino add_to_ops_vec (VEC(operand_entry_t, heap) **ops, tree op) 512*e4b17023SJohn Marino { 513*e4b17023SJohn Marino operand_entry_t oe = (operand_entry_t) pool_alloc (operand_entry_pool); 514*e4b17023SJohn Marino 515*e4b17023SJohn Marino oe->op = op; 516*e4b17023SJohn Marino oe->rank = get_rank (op); 517*e4b17023SJohn Marino oe->id = next_operand_entry_id++; 518*e4b17023SJohn Marino VEC_safe_push (operand_entry_t, heap, *ops, oe); 519*e4b17023SJohn Marino } 520*e4b17023SJohn Marino 521*e4b17023SJohn Marino /* Return true if STMT is reassociable operation containing a binary 522*e4b17023SJohn Marino operation with tree code CODE, and is inside LOOP. */ 523*e4b17023SJohn Marino 524*e4b17023SJohn Marino static bool 525*e4b17023SJohn Marino is_reassociable_op (gimple stmt, enum tree_code code, struct loop *loop) 526*e4b17023SJohn Marino { 527*e4b17023SJohn Marino basic_block bb = gimple_bb (stmt); 528*e4b17023SJohn Marino 529*e4b17023SJohn Marino if (gimple_bb (stmt) == NULL) 530*e4b17023SJohn Marino return false; 531*e4b17023SJohn Marino 532*e4b17023SJohn Marino if (!flow_bb_inside_loop_p (loop, bb)) 533*e4b17023SJohn Marino return false; 534*e4b17023SJohn Marino 535*e4b17023SJohn Marino if (is_gimple_assign (stmt) 536*e4b17023SJohn Marino && gimple_assign_rhs_code (stmt) == code 537*e4b17023SJohn Marino && has_single_use (gimple_assign_lhs (stmt))) 538*e4b17023SJohn Marino return true; 539*e4b17023SJohn Marino 540*e4b17023SJohn Marino return false; 541*e4b17023SJohn Marino } 542*e4b17023SJohn Marino 543*e4b17023SJohn Marino 544*e4b17023SJohn Marino /* Given NAME, if NAME is defined by a unary operation OPCODE, return the 545*e4b17023SJohn Marino operand of the negate operation. Otherwise, return NULL. */ 546*e4b17023SJohn Marino 547*e4b17023SJohn Marino static tree 548*e4b17023SJohn Marino get_unary_op (tree name, enum tree_code opcode) 549*e4b17023SJohn Marino { 550*e4b17023SJohn Marino gimple stmt = SSA_NAME_DEF_STMT (name); 551*e4b17023SJohn Marino 552*e4b17023SJohn Marino if (!is_gimple_assign (stmt)) 553*e4b17023SJohn Marino return NULL_TREE; 554*e4b17023SJohn Marino 555*e4b17023SJohn Marino if (gimple_assign_rhs_code (stmt) == opcode) 556*e4b17023SJohn Marino return gimple_assign_rhs1 (stmt); 557*e4b17023SJohn Marino return NULL_TREE; 558*e4b17023SJohn Marino } 559*e4b17023SJohn Marino 560*e4b17023SJohn Marino /* If CURR and LAST are a pair of ops that OPCODE allows us to 561*e4b17023SJohn Marino eliminate through equivalences, do so, remove them from OPS, and 562*e4b17023SJohn Marino return true. Otherwise, return false. */ 563*e4b17023SJohn Marino 564*e4b17023SJohn Marino static bool 565*e4b17023SJohn Marino eliminate_duplicate_pair (enum tree_code opcode, 566*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops, 567*e4b17023SJohn Marino bool *all_done, 568*e4b17023SJohn Marino unsigned int i, 569*e4b17023SJohn Marino operand_entry_t curr, 570*e4b17023SJohn Marino operand_entry_t last) 571*e4b17023SJohn Marino { 572*e4b17023SJohn Marino 573*e4b17023SJohn Marino /* If we have two of the same op, and the opcode is & |, min, or max, 574*e4b17023SJohn Marino we can eliminate one of them. 575*e4b17023SJohn Marino If we have two of the same op, and the opcode is ^, we can 576*e4b17023SJohn Marino eliminate both of them. */ 577*e4b17023SJohn Marino 578*e4b17023SJohn Marino if (last && last->op == curr->op) 579*e4b17023SJohn Marino { 580*e4b17023SJohn Marino switch (opcode) 581*e4b17023SJohn Marino { 582*e4b17023SJohn Marino case MAX_EXPR: 583*e4b17023SJohn Marino case MIN_EXPR: 584*e4b17023SJohn Marino case BIT_IOR_EXPR: 585*e4b17023SJohn Marino case BIT_AND_EXPR: 586*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 587*e4b17023SJohn Marino { 588*e4b17023SJohn Marino fprintf (dump_file, "Equivalence: "); 589*e4b17023SJohn Marino print_generic_expr (dump_file, curr->op, 0); 590*e4b17023SJohn Marino fprintf (dump_file, " [&|minmax] "); 591*e4b17023SJohn Marino print_generic_expr (dump_file, last->op, 0); 592*e4b17023SJohn Marino fprintf (dump_file, " -> "); 593*e4b17023SJohn Marino print_generic_stmt (dump_file, last->op, 0); 594*e4b17023SJohn Marino } 595*e4b17023SJohn Marino 596*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, i); 597*e4b17023SJohn Marino reassociate_stats.ops_eliminated ++; 598*e4b17023SJohn Marino 599*e4b17023SJohn Marino return true; 600*e4b17023SJohn Marino 601*e4b17023SJohn Marino case BIT_XOR_EXPR: 602*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 603*e4b17023SJohn Marino { 604*e4b17023SJohn Marino fprintf (dump_file, "Equivalence: "); 605*e4b17023SJohn Marino print_generic_expr (dump_file, curr->op, 0); 606*e4b17023SJohn Marino fprintf (dump_file, " ^ "); 607*e4b17023SJohn Marino print_generic_expr (dump_file, last->op, 0); 608*e4b17023SJohn Marino fprintf (dump_file, " -> nothing\n"); 609*e4b17023SJohn Marino } 610*e4b17023SJohn Marino 611*e4b17023SJohn Marino reassociate_stats.ops_eliminated += 2; 612*e4b17023SJohn Marino 613*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) == 2) 614*e4b17023SJohn Marino { 615*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, *ops); 616*e4b17023SJohn Marino *ops = NULL; 617*e4b17023SJohn Marino add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (last->op))); 618*e4b17023SJohn Marino *all_done = true; 619*e4b17023SJohn Marino } 620*e4b17023SJohn Marino else 621*e4b17023SJohn Marino { 622*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, i-1); 623*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, i-1); 624*e4b17023SJohn Marino } 625*e4b17023SJohn Marino 626*e4b17023SJohn Marino return true; 627*e4b17023SJohn Marino 628*e4b17023SJohn Marino default: 629*e4b17023SJohn Marino break; 630*e4b17023SJohn Marino } 631*e4b17023SJohn Marino } 632*e4b17023SJohn Marino return false; 633*e4b17023SJohn Marino } 634*e4b17023SJohn Marino 635*e4b17023SJohn Marino static VEC(tree, heap) *plus_negates; 636*e4b17023SJohn Marino 637*e4b17023SJohn Marino /* If OPCODE is PLUS_EXPR, CURR->OP is a negate expression or a bitwise not 638*e4b17023SJohn Marino expression, look in OPS for a corresponding positive operation to cancel 639*e4b17023SJohn Marino it out. If we find one, remove the other from OPS, replace 640*e4b17023SJohn Marino OPS[CURRINDEX] with 0 or -1, respectively, and return true. Otherwise, 641*e4b17023SJohn Marino return false. */ 642*e4b17023SJohn Marino 643*e4b17023SJohn Marino static bool 644*e4b17023SJohn Marino eliminate_plus_minus_pair (enum tree_code opcode, 645*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops, 646*e4b17023SJohn Marino unsigned int currindex, 647*e4b17023SJohn Marino operand_entry_t curr) 648*e4b17023SJohn Marino { 649*e4b17023SJohn Marino tree negateop; 650*e4b17023SJohn Marino tree notop; 651*e4b17023SJohn Marino unsigned int i; 652*e4b17023SJohn Marino operand_entry_t oe; 653*e4b17023SJohn Marino 654*e4b17023SJohn Marino if (opcode != PLUS_EXPR || TREE_CODE (curr->op) != SSA_NAME) 655*e4b17023SJohn Marino return false; 656*e4b17023SJohn Marino 657*e4b17023SJohn Marino negateop = get_unary_op (curr->op, NEGATE_EXPR); 658*e4b17023SJohn Marino notop = get_unary_op (curr->op, BIT_NOT_EXPR); 659*e4b17023SJohn Marino if (negateop == NULL_TREE && notop == NULL_TREE) 660*e4b17023SJohn Marino return false; 661*e4b17023SJohn Marino 662*e4b17023SJohn Marino /* Any non-negated version will have a rank that is one less than 663*e4b17023SJohn Marino the current rank. So once we hit those ranks, if we don't find 664*e4b17023SJohn Marino one, we can stop. */ 665*e4b17023SJohn Marino 666*e4b17023SJohn Marino for (i = currindex + 1; 667*e4b17023SJohn Marino VEC_iterate (operand_entry_t, *ops, i, oe) 668*e4b17023SJohn Marino && oe->rank >= curr->rank - 1 ; 669*e4b17023SJohn Marino i++) 670*e4b17023SJohn Marino { 671*e4b17023SJohn Marino if (oe->op == negateop) 672*e4b17023SJohn Marino { 673*e4b17023SJohn Marino 674*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 675*e4b17023SJohn Marino { 676*e4b17023SJohn Marino fprintf (dump_file, "Equivalence: "); 677*e4b17023SJohn Marino print_generic_expr (dump_file, negateop, 0); 678*e4b17023SJohn Marino fprintf (dump_file, " + -"); 679*e4b17023SJohn Marino print_generic_expr (dump_file, oe->op, 0); 680*e4b17023SJohn Marino fprintf (dump_file, " -> 0\n"); 681*e4b17023SJohn Marino } 682*e4b17023SJohn Marino 683*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, i); 684*e4b17023SJohn Marino add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (oe->op))); 685*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, currindex); 686*e4b17023SJohn Marino reassociate_stats.ops_eliminated ++; 687*e4b17023SJohn Marino 688*e4b17023SJohn Marino return true; 689*e4b17023SJohn Marino } 690*e4b17023SJohn Marino else if (oe->op == notop) 691*e4b17023SJohn Marino { 692*e4b17023SJohn Marino tree op_type = TREE_TYPE (oe->op); 693*e4b17023SJohn Marino 694*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 695*e4b17023SJohn Marino { 696*e4b17023SJohn Marino fprintf (dump_file, "Equivalence: "); 697*e4b17023SJohn Marino print_generic_expr (dump_file, notop, 0); 698*e4b17023SJohn Marino fprintf (dump_file, " + ~"); 699*e4b17023SJohn Marino print_generic_expr (dump_file, oe->op, 0); 700*e4b17023SJohn Marino fprintf (dump_file, " -> -1\n"); 701*e4b17023SJohn Marino } 702*e4b17023SJohn Marino 703*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, i); 704*e4b17023SJohn Marino add_to_ops_vec (ops, build_int_cst_type (op_type, -1)); 705*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, currindex); 706*e4b17023SJohn Marino reassociate_stats.ops_eliminated ++; 707*e4b17023SJohn Marino 708*e4b17023SJohn Marino return true; 709*e4b17023SJohn Marino } 710*e4b17023SJohn Marino } 711*e4b17023SJohn Marino 712*e4b17023SJohn Marino /* CURR->OP is a negate expr in a plus expr: save it for later 713*e4b17023SJohn Marino inspection in repropagate_negates(). */ 714*e4b17023SJohn Marino if (negateop != NULL_TREE) 715*e4b17023SJohn Marino VEC_safe_push (tree, heap, plus_negates, curr->op); 716*e4b17023SJohn Marino 717*e4b17023SJohn Marino return false; 718*e4b17023SJohn Marino } 719*e4b17023SJohn Marino 720*e4b17023SJohn Marino /* If OPCODE is BIT_IOR_EXPR, BIT_AND_EXPR, and, CURR->OP is really a 721*e4b17023SJohn Marino bitwise not expression, look in OPS for a corresponding operand to 722*e4b17023SJohn Marino cancel it out. If we find one, remove the other from OPS, replace 723*e4b17023SJohn Marino OPS[CURRINDEX] with 0, and return true. Otherwise, return 724*e4b17023SJohn Marino false. */ 725*e4b17023SJohn Marino 726*e4b17023SJohn Marino static bool 727*e4b17023SJohn Marino eliminate_not_pairs (enum tree_code opcode, 728*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops, 729*e4b17023SJohn Marino unsigned int currindex, 730*e4b17023SJohn Marino operand_entry_t curr) 731*e4b17023SJohn Marino { 732*e4b17023SJohn Marino tree notop; 733*e4b17023SJohn Marino unsigned int i; 734*e4b17023SJohn Marino operand_entry_t oe; 735*e4b17023SJohn Marino 736*e4b17023SJohn Marino if ((opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR) 737*e4b17023SJohn Marino || TREE_CODE (curr->op) != SSA_NAME) 738*e4b17023SJohn Marino return false; 739*e4b17023SJohn Marino 740*e4b17023SJohn Marino notop = get_unary_op (curr->op, BIT_NOT_EXPR); 741*e4b17023SJohn Marino if (notop == NULL_TREE) 742*e4b17023SJohn Marino return false; 743*e4b17023SJohn Marino 744*e4b17023SJohn Marino /* Any non-not version will have a rank that is one less than 745*e4b17023SJohn Marino the current rank. So once we hit those ranks, if we don't find 746*e4b17023SJohn Marino one, we can stop. */ 747*e4b17023SJohn Marino 748*e4b17023SJohn Marino for (i = currindex + 1; 749*e4b17023SJohn Marino VEC_iterate (operand_entry_t, *ops, i, oe) 750*e4b17023SJohn Marino && oe->rank >= curr->rank - 1; 751*e4b17023SJohn Marino i++) 752*e4b17023SJohn Marino { 753*e4b17023SJohn Marino if (oe->op == notop) 754*e4b17023SJohn Marino { 755*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 756*e4b17023SJohn Marino { 757*e4b17023SJohn Marino fprintf (dump_file, "Equivalence: "); 758*e4b17023SJohn Marino print_generic_expr (dump_file, notop, 0); 759*e4b17023SJohn Marino if (opcode == BIT_AND_EXPR) 760*e4b17023SJohn Marino fprintf (dump_file, " & ~"); 761*e4b17023SJohn Marino else if (opcode == BIT_IOR_EXPR) 762*e4b17023SJohn Marino fprintf (dump_file, " | ~"); 763*e4b17023SJohn Marino print_generic_expr (dump_file, oe->op, 0); 764*e4b17023SJohn Marino if (opcode == BIT_AND_EXPR) 765*e4b17023SJohn Marino fprintf (dump_file, " -> 0\n"); 766*e4b17023SJohn Marino else if (opcode == BIT_IOR_EXPR) 767*e4b17023SJohn Marino fprintf (dump_file, " -> -1\n"); 768*e4b17023SJohn Marino } 769*e4b17023SJohn Marino 770*e4b17023SJohn Marino if (opcode == BIT_AND_EXPR) 771*e4b17023SJohn Marino oe->op = build_zero_cst (TREE_TYPE (oe->op)); 772*e4b17023SJohn Marino else if (opcode == BIT_IOR_EXPR) 773*e4b17023SJohn Marino oe->op = build_low_bits_mask (TREE_TYPE (oe->op), 774*e4b17023SJohn Marino TYPE_PRECISION (TREE_TYPE (oe->op))); 775*e4b17023SJohn Marino 776*e4b17023SJohn Marino reassociate_stats.ops_eliminated 777*e4b17023SJohn Marino += VEC_length (operand_entry_t, *ops) - 1; 778*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, *ops); 779*e4b17023SJohn Marino *ops = NULL; 780*e4b17023SJohn Marino VEC_safe_push (operand_entry_t, heap, *ops, oe); 781*e4b17023SJohn Marino return true; 782*e4b17023SJohn Marino } 783*e4b17023SJohn Marino } 784*e4b17023SJohn Marino 785*e4b17023SJohn Marino return false; 786*e4b17023SJohn Marino } 787*e4b17023SJohn Marino 788*e4b17023SJohn Marino /* Use constant value that may be present in OPS to try to eliminate 789*e4b17023SJohn Marino operands. Note that this function is only really used when we've 790*e4b17023SJohn Marino eliminated ops for other reasons, or merged constants. Across 791*e4b17023SJohn Marino single statements, fold already does all of this, plus more. There 792*e4b17023SJohn Marino is little point in duplicating logic, so I've only included the 793*e4b17023SJohn Marino identities that I could ever construct testcases to trigger. */ 794*e4b17023SJohn Marino 795*e4b17023SJohn Marino static void 796*e4b17023SJohn Marino eliminate_using_constants (enum tree_code opcode, 797*e4b17023SJohn Marino VEC(operand_entry_t, heap) **ops) 798*e4b17023SJohn Marino { 799*e4b17023SJohn Marino operand_entry_t oelast = VEC_last (operand_entry_t, *ops); 800*e4b17023SJohn Marino tree type = TREE_TYPE (oelast->op); 801*e4b17023SJohn Marino 802*e4b17023SJohn Marino if (oelast->rank == 0 803*e4b17023SJohn Marino && (INTEGRAL_TYPE_P (type) || FLOAT_TYPE_P (type))) 804*e4b17023SJohn Marino { 805*e4b17023SJohn Marino switch (opcode) 806*e4b17023SJohn Marino { 807*e4b17023SJohn Marino case BIT_AND_EXPR: 808*e4b17023SJohn Marino if (integer_zerop (oelast->op)) 809*e4b17023SJohn Marino { 810*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 811*e4b17023SJohn Marino { 812*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 813*e4b17023SJohn Marino fprintf (dump_file, "Found & 0, removing all other ops\n"); 814*e4b17023SJohn Marino 815*e4b17023SJohn Marino reassociate_stats.ops_eliminated 816*e4b17023SJohn Marino += VEC_length (operand_entry_t, *ops) - 1; 817*e4b17023SJohn Marino 818*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, *ops); 819*e4b17023SJohn Marino *ops = NULL; 820*e4b17023SJohn Marino VEC_safe_push (operand_entry_t, heap, *ops, oelast); 821*e4b17023SJohn Marino return; 822*e4b17023SJohn Marino } 823*e4b17023SJohn Marino } 824*e4b17023SJohn Marino else if (integer_all_onesp (oelast->op)) 825*e4b17023SJohn Marino { 826*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 827*e4b17023SJohn Marino { 828*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 829*e4b17023SJohn Marino fprintf (dump_file, "Found & -1, removing\n"); 830*e4b17023SJohn Marino VEC_pop (operand_entry_t, *ops); 831*e4b17023SJohn Marino reassociate_stats.ops_eliminated++; 832*e4b17023SJohn Marino } 833*e4b17023SJohn Marino } 834*e4b17023SJohn Marino break; 835*e4b17023SJohn Marino case BIT_IOR_EXPR: 836*e4b17023SJohn Marino if (integer_all_onesp (oelast->op)) 837*e4b17023SJohn Marino { 838*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 839*e4b17023SJohn Marino { 840*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 841*e4b17023SJohn Marino fprintf (dump_file, "Found | -1, removing all other ops\n"); 842*e4b17023SJohn Marino 843*e4b17023SJohn Marino reassociate_stats.ops_eliminated 844*e4b17023SJohn Marino += VEC_length (operand_entry_t, *ops) - 1; 845*e4b17023SJohn Marino 846*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, *ops); 847*e4b17023SJohn Marino *ops = NULL; 848*e4b17023SJohn Marino VEC_safe_push (operand_entry_t, heap, *ops, oelast); 849*e4b17023SJohn Marino return; 850*e4b17023SJohn Marino } 851*e4b17023SJohn Marino } 852*e4b17023SJohn Marino else if (integer_zerop (oelast->op)) 853*e4b17023SJohn Marino { 854*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 855*e4b17023SJohn Marino { 856*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 857*e4b17023SJohn Marino fprintf (dump_file, "Found | 0, removing\n"); 858*e4b17023SJohn Marino VEC_pop (operand_entry_t, *ops); 859*e4b17023SJohn Marino reassociate_stats.ops_eliminated++; 860*e4b17023SJohn Marino } 861*e4b17023SJohn Marino } 862*e4b17023SJohn Marino break; 863*e4b17023SJohn Marino case MULT_EXPR: 864*e4b17023SJohn Marino if (integer_zerop (oelast->op) 865*e4b17023SJohn Marino || (FLOAT_TYPE_P (type) 866*e4b17023SJohn Marino && !HONOR_NANS (TYPE_MODE (type)) 867*e4b17023SJohn Marino && !HONOR_SIGNED_ZEROS (TYPE_MODE (type)) 868*e4b17023SJohn Marino && real_zerop (oelast->op))) 869*e4b17023SJohn Marino { 870*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 871*e4b17023SJohn Marino { 872*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 873*e4b17023SJohn Marino fprintf (dump_file, "Found * 0, removing all other ops\n"); 874*e4b17023SJohn Marino 875*e4b17023SJohn Marino reassociate_stats.ops_eliminated 876*e4b17023SJohn Marino += VEC_length (operand_entry_t, *ops) - 1; 877*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, *ops); 878*e4b17023SJohn Marino *ops = NULL; 879*e4b17023SJohn Marino VEC_safe_push (operand_entry_t, heap, *ops, oelast); 880*e4b17023SJohn Marino return; 881*e4b17023SJohn Marino } 882*e4b17023SJohn Marino } 883*e4b17023SJohn Marino else if (integer_onep (oelast->op) 884*e4b17023SJohn Marino || (FLOAT_TYPE_P (type) 885*e4b17023SJohn Marino && !HONOR_SNANS (TYPE_MODE (type)) 886*e4b17023SJohn Marino && real_onep (oelast->op))) 887*e4b17023SJohn Marino { 888*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 889*e4b17023SJohn Marino { 890*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 891*e4b17023SJohn Marino fprintf (dump_file, "Found * 1, removing\n"); 892*e4b17023SJohn Marino VEC_pop (operand_entry_t, *ops); 893*e4b17023SJohn Marino reassociate_stats.ops_eliminated++; 894*e4b17023SJohn Marino return; 895*e4b17023SJohn Marino } 896*e4b17023SJohn Marino } 897*e4b17023SJohn Marino break; 898*e4b17023SJohn Marino case BIT_XOR_EXPR: 899*e4b17023SJohn Marino case PLUS_EXPR: 900*e4b17023SJohn Marino case MINUS_EXPR: 901*e4b17023SJohn Marino if (integer_zerop (oelast->op) 902*e4b17023SJohn Marino || (FLOAT_TYPE_P (type) 903*e4b17023SJohn Marino && (opcode == PLUS_EXPR || opcode == MINUS_EXPR) 904*e4b17023SJohn Marino && fold_real_zero_addition_p (type, oelast->op, 905*e4b17023SJohn Marino opcode == MINUS_EXPR))) 906*e4b17023SJohn Marino { 907*e4b17023SJohn Marino if (VEC_length (operand_entry_t, *ops) != 1) 908*e4b17023SJohn Marino { 909*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 910*e4b17023SJohn Marino fprintf (dump_file, "Found [|^+] 0, removing\n"); 911*e4b17023SJohn Marino VEC_pop (operand_entry_t, *ops); 912*e4b17023SJohn Marino reassociate_stats.ops_eliminated++; 913*e4b17023SJohn Marino return; 914*e4b17023SJohn Marino } 915*e4b17023SJohn Marino } 916*e4b17023SJohn Marino break; 917*e4b17023SJohn Marino default: 918*e4b17023SJohn Marino break; 919*e4b17023SJohn Marino } 920*e4b17023SJohn Marino } 921*e4b17023SJohn Marino } 922*e4b17023SJohn Marino 923*e4b17023SJohn Marino 924*e4b17023SJohn Marino static void linearize_expr_tree (VEC(operand_entry_t, heap) **, gimple, 925*e4b17023SJohn Marino bool, bool); 926*e4b17023SJohn Marino 927*e4b17023SJohn Marino /* Structure for tracking and counting operands. */ 928*e4b17023SJohn Marino typedef struct oecount_s { 929*e4b17023SJohn Marino int cnt; 930*e4b17023SJohn Marino int id; 931*e4b17023SJohn Marino enum tree_code oecode; 932*e4b17023SJohn Marino tree op; 933*e4b17023SJohn Marino } oecount; 934*e4b17023SJohn Marino 935*e4b17023SJohn Marino DEF_VEC_O(oecount); 936*e4b17023SJohn Marino DEF_VEC_ALLOC_O(oecount,heap); 937*e4b17023SJohn Marino 938*e4b17023SJohn Marino /* The heap for the oecount hashtable and the sorted list of operands. */ 939*e4b17023SJohn Marino static VEC (oecount, heap) *cvec; 940*e4b17023SJohn Marino 941*e4b17023SJohn Marino /* Hash function for oecount. */ 942*e4b17023SJohn Marino 943*e4b17023SJohn Marino static hashval_t 944*e4b17023SJohn Marino oecount_hash (const void *p) 945*e4b17023SJohn Marino { 946*e4b17023SJohn Marino const oecount *c = VEC_index (oecount, cvec, (size_t)p - 42); 947*e4b17023SJohn Marino return htab_hash_pointer (c->op) ^ (hashval_t)c->oecode; 948*e4b17023SJohn Marino } 949*e4b17023SJohn Marino 950*e4b17023SJohn Marino /* Comparison function for oecount. */ 951*e4b17023SJohn Marino 952*e4b17023SJohn Marino static int 953*e4b17023SJohn Marino oecount_eq (const void *p1, const void *p2) 954*e4b17023SJohn Marino { 955*e4b17023SJohn Marino const oecount *c1 = VEC_index (oecount, cvec, (size_t)p1 - 42); 956*e4b17023SJohn Marino const oecount *c2 = VEC_index (oecount, cvec, (size_t)p2 - 42); 957*e4b17023SJohn Marino return (c1->oecode == c2->oecode 958*e4b17023SJohn Marino && c1->op == c2->op); 959*e4b17023SJohn Marino } 960*e4b17023SJohn Marino 961*e4b17023SJohn Marino /* Comparison function for qsort sorting oecount elements by count. */ 962*e4b17023SJohn Marino 963*e4b17023SJohn Marino static int 964*e4b17023SJohn Marino oecount_cmp (const void *p1, const void *p2) 965*e4b17023SJohn Marino { 966*e4b17023SJohn Marino const oecount *c1 = (const oecount *)p1; 967*e4b17023SJohn Marino const oecount *c2 = (const oecount *)p2; 968*e4b17023SJohn Marino if (c1->cnt != c2->cnt) 969*e4b17023SJohn Marino return c1->cnt - c2->cnt; 970*e4b17023SJohn Marino else 971*e4b17023SJohn Marino /* If counts are identical, use unique IDs to stabilize qsort. */ 972*e4b17023SJohn Marino return c1->id - c2->id; 973*e4b17023SJohn Marino } 974*e4b17023SJohn Marino 975*e4b17023SJohn Marino /* Walks the linear chain with result *DEF searching for an operation 976*e4b17023SJohn Marino with operand OP and code OPCODE removing that from the chain. *DEF 977*e4b17023SJohn Marino is updated if there is only one operand but no operation left. */ 978*e4b17023SJohn Marino 979*e4b17023SJohn Marino static void 980*e4b17023SJohn Marino zero_one_operation (tree *def, enum tree_code opcode, tree op) 981*e4b17023SJohn Marino { 982*e4b17023SJohn Marino gimple stmt = SSA_NAME_DEF_STMT (*def); 983*e4b17023SJohn Marino 984*e4b17023SJohn Marino do 985*e4b17023SJohn Marino { 986*e4b17023SJohn Marino tree name = gimple_assign_rhs1 (stmt); 987*e4b17023SJohn Marino 988*e4b17023SJohn Marino /* If this is the operation we look for and one of the operands 989*e4b17023SJohn Marino is ours simply propagate the other operand into the stmts 990*e4b17023SJohn Marino single use. */ 991*e4b17023SJohn Marino if (gimple_assign_rhs_code (stmt) == opcode 992*e4b17023SJohn Marino && (name == op 993*e4b17023SJohn Marino || gimple_assign_rhs2 (stmt) == op)) 994*e4b17023SJohn Marino { 995*e4b17023SJohn Marino gimple use_stmt; 996*e4b17023SJohn Marino use_operand_p use; 997*e4b17023SJohn Marino gimple_stmt_iterator gsi; 998*e4b17023SJohn Marino if (name == op) 999*e4b17023SJohn Marino name = gimple_assign_rhs2 (stmt); 1000*e4b17023SJohn Marino gcc_assert (has_single_use (gimple_assign_lhs (stmt))); 1001*e4b17023SJohn Marino single_imm_use (gimple_assign_lhs (stmt), &use, &use_stmt); 1002*e4b17023SJohn Marino if (gimple_assign_lhs (stmt) == *def) 1003*e4b17023SJohn Marino *def = name; 1004*e4b17023SJohn Marino SET_USE (use, name); 1005*e4b17023SJohn Marino if (TREE_CODE (name) != SSA_NAME) 1006*e4b17023SJohn Marino update_stmt (use_stmt); 1007*e4b17023SJohn Marino gsi = gsi_for_stmt (stmt); 1008*e4b17023SJohn Marino gsi_remove (&gsi, true); 1009*e4b17023SJohn Marino release_defs (stmt); 1010*e4b17023SJohn Marino return; 1011*e4b17023SJohn Marino } 1012*e4b17023SJohn Marino 1013*e4b17023SJohn Marino /* Continue walking the chain. */ 1014*e4b17023SJohn Marino gcc_assert (name != op 1015*e4b17023SJohn Marino && TREE_CODE (name) == SSA_NAME); 1016*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (name); 1017*e4b17023SJohn Marino } 1018*e4b17023SJohn Marino while (1); 1019*e4b17023SJohn Marino } 1020*e4b17023SJohn Marino 1021*e4b17023SJohn Marino /* Builds one statement performing OP1 OPCODE OP2 using TMPVAR for 1022*e4b17023SJohn Marino the result. Places the statement after the definition of either 1023*e4b17023SJohn Marino OP1 or OP2. Returns the new statement. */ 1024*e4b17023SJohn Marino 1025*e4b17023SJohn Marino static gimple 1026*e4b17023SJohn Marino build_and_add_sum (tree tmpvar, tree op1, tree op2, enum tree_code opcode) 1027*e4b17023SJohn Marino { 1028*e4b17023SJohn Marino gimple op1def = NULL, op2def = NULL; 1029*e4b17023SJohn Marino gimple_stmt_iterator gsi; 1030*e4b17023SJohn Marino tree op; 1031*e4b17023SJohn Marino gimple sum; 1032*e4b17023SJohn Marino 1033*e4b17023SJohn Marino /* Create the addition statement. */ 1034*e4b17023SJohn Marino sum = gimple_build_assign_with_ops (opcode, tmpvar, op1, op2); 1035*e4b17023SJohn Marino op = make_ssa_name (tmpvar, sum); 1036*e4b17023SJohn Marino gimple_assign_set_lhs (sum, op); 1037*e4b17023SJohn Marino 1038*e4b17023SJohn Marino /* Find an insertion place and insert. */ 1039*e4b17023SJohn Marino if (TREE_CODE (op1) == SSA_NAME) 1040*e4b17023SJohn Marino op1def = SSA_NAME_DEF_STMT (op1); 1041*e4b17023SJohn Marino if (TREE_CODE (op2) == SSA_NAME) 1042*e4b17023SJohn Marino op2def = SSA_NAME_DEF_STMT (op2); 1043*e4b17023SJohn Marino if ((!op1def || gimple_nop_p (op1def)) 1044*e4b17023SJohn Marino && (!op2def || gimple_nop_p (op2def))) 1045*e4b17023SJohn Marino { 1046*e4b17023SJohn Marino gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR)); 1047*e4b17023SJohn Marino gsi_insert_before (&gsi, sum, GSI_NEW_STMT); 1048*e4b17023SJohn Marino } 1049*e4b17023SJohn Marino else if ((!op1def || gimple_nop_p (op1def)) 1050*e4b17023SJohn Marino || (op2def && !gimple_nop_p (op2def) 1051*e4b17023SJohn Marino && stmt_dominates_stmt_p (op1def, op2def))) 1052*e4b17023SJohn Marino { 1053*e4b17023SJohn Marino if (gimple_code (op2def) == GIMPLE_PHI) 1054*e4b17023SJohn Marino { 1055*e4b17023SJohn Marino gsi = gsi_after_labels (gimple_bb (op2def)); 1056*e4b17023SJohn Marino gsi_insert_before (&gsi, sum, GSI_NEW_STMT); 1057*e4b17023SJohn Marino } 1058*e4b17023SJohn Marino else 1059*e4b17023SJohn Marino { 1060*e4b17023SJohn Marino if (!stmt_ends_bb_p (op2def)) 1061*e4b17023SJohn Marino { 1062*e4b17023SJohn Marino gsi = gsi_for_stmt (op2def); 1063*e4b17023SJohn Marino gsi_insert_after (&gsi, sum, GSI_NEW_STMT); 1064*e4b17023SJohn Marino } 1065*e4b17023SJohn Marino else 1066*e4b17023SJohn Marino { 1067*e4b17023SJohn Marino edge e; 1068*e4b17023SJohn Marino edge_iterator ei; 1069*e4b17023SJohn Marino 1070*e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, gimple_bb (op2def)->succs) 1071*e4b17023SJohn Marino if (e->flags & EDGE_FALLTHRU) 1072*e4b17023SJohn Marino gsi_insert_on_edge_immediate (e, sum); 1073*e4b17023SJohn Marino } 1074*e4b17023SJohn Marino } 1075*e4b17023SJohn Marino } 1076*e4b17023SJohn Marino else 1077*e4b17023SJohn Marino { 1078*e4b17023SJohn Marino if (gimple_code (op1def) == GIMPLE_PHI) 1079*e4b17023SJohn Marino { 1080*e4b17023SJohn Marino gsi = gsi_after_labels (gimple_bb (op1def)); 1081*e4b17023SJohn Marino gsi_insert_before (&gsi, sum, GSI_NEW_STMT); 1082*e4b17023SJohn Marino } 1083*e4b17023SJohn Marino else 1084*e4b17023SJohn Marino { 1085*e4b17023SJohn Marino if (!stmt_ends_bb_p (op1def)) 1086*e4b17023SJohn Marino { 1087*e4b17023SJohn Marino gsi = gsi_for_stmt (op1def); 1088*e4b17023SJohn Marino gsi_insert_after (&gsi, sum, GSI_NEW_STMT); 1089*e4b17023SJohn Marino } 1090*e4b17023SJohn Marino else 1091*e4b17023SJohn Marino { 1092*e4b17023SJohn Marino edge e; 1093*e4b17023SJohn Marino edge_iterator ei; 1094*e4b17023SJohn Marino 1095*e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, gimple_bb (op1def)->succs) 1096*e4b17023SJohn Marino if (e->flags & EDGE_FALLTHRU) 1097*e4b17023SJohn Marino gsi_insert_on_edge_immediate (e, sum); 1098*e4b17023SJohn Marino } 1099*e4b17023SJohn Marino } 1100*e4b17023SJohn Marino } 1101*e4b17023SJohn Marino update_stmt (sum); 1102*e4b17023SJohn Marino 1103*e4b17023SJohn Marino return sum; 1104*e4b17023SJohn Marino } 1105*e4b17023SJohn Marino 1106*e4b17023SJohn Marino /* Perform un-distribution of divisions and multiplications. 1107*e4b17023SJohn Marino A * X + B * X is transformed into (A + B) * X and A / X + B / X 1108*e4b17023SJohn Marino to (A + B) / X for real X. 1109*e4b17023SJohn Marino 1110*e4b17023SJohn Marino The algorithm is organized as follows. 1111*e4b17023SJohn Marino 1112*e4b17023SJohn Marino - First we walk the addition chain *OPS looking for summands that 1113*e4b17023SJohn Marino are defined by a multiplication or a real division. This results 1114*e4b17023SJohn Marino in the candidates bitmap with relevant indices into *OPS. 1115*e4b17023SJohn Marino 1116*e4b17023SJohn Marino - Second we build the chains of multiplications or divisions for 1117*e4b17023SJohn Marino these candidates, counting the number of occurences of (operand, code) 1118*e4b17023SJohn Marino pairs in all of the candidates chains. 1119*e4b17023SJohn Marino 1120*e4b17023SJohn Marino - Third we sort the (operand, code) pairs by number of occurence and 1121*e4b17023SJohn Marino process them starting with the pair with the most uses. 1122*e4b17023SJohn Marino 1123*e4b17023SJohn Marino * For each such pair we walk the candidates again to build a 1124*e4b17023SJohn Marino second candidate bitmap noting all multiplication/division chains 1125*e4b17023SJohn Marino that have at least one occurence of (operand, code). 1126*e4b17023SJohn Marino 1127*e4b17023SJohn Marino * We build an alternate addition chain only covering these 1128*e4b17023SJohn Marino candidates with one (operand, code) operation removed from their 1129*e4b17023SJohn Marino multiplication/division chain. 1130*e4b17023SJohn Marino 1131*e4b17023SJohn Marino * The first candidate gets replaced by the alternate addition chain 1132*e4b17023SJohn Marino multiplied/divided by the operand. 1133*e4b17023SJohn Marino 1134*e4b17023SJohn Marino * All candidate chains get disabled for further processing and 1135*e4b17023SJohn Marino processing of (operand, code) pairs continues. 1136*e4b17023SJohn Marino 1137*e4b17023SJohn Marino The alternate addition chains built are re-processed by the main 1138*e4b17023SJohn Marino reassociation algorithm which allows optimizing a * x * y + b * y * x 1139*e4b17023SJohn Marino to (a + b ) * x * y in one invocation of the reassociation pass. */ 1140*e4b17023SJohn Marino 1141*e4b17023SJohn Marino static bool 1142*e4b17023SJohn Marino undistribute_ops_list (enum tree_code opcode, 1143*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops, struct loop *loop) 1144*e4b17023SJohn Marino { 1145*e4b17023SJohn Marino unsigned int length = VEC_length (operand_entry_t, *ops); 1146*e4b17023SJohn Marino operand_entry_t oe1; 1147*e4b17023SJohn Marino unsigned i, j; 1148*e4b17023SJohn Marino sbitmap candidates, candidates2; 1149*e4b17023SJohn Marino unsigned nr_candidates, nr_candidates2; 1150*e4b17023SJohn Marino sbitmap_iterator sbi0; 1151*e4b17023SJohn Marino VEC (operand_entry_t, heap) **subops; 1152*e4b17023SJohn Marino htab_t ctable; 1153*e4b17023SJohn Marino bool changed = false; 1154*e4b17023SJohn Marino int next_oecount_id = 0; 1155*e4b17023SJohn Marino 1156*e4b17023SJohn Marino if (length <= 1 1157*e4b17023SJohn Marino || opcode != PLUS_EXPR) 1158*e4b17023SJohn Marino return false; 1159*e4b17023SJohn Marino 1160*e4b17023SJohn Marino /* Build a list of candidates to process. */ 1161*e4b17023SJohn Marino candidates = sbitmap_alloc (length); 1162*e4b17023SJohn Marino sbitmap_zero (candidates); 1163*e4b17023SJohn Marino nr_candidates = 0; 1164*e4b17023SJohn Marino FOR_EACH_VEC_ELT (operand_entry_t, *ops, i, oe1) 1165*e4b17023SJohn Marino { 1166*e4b17023SJohn Marino enum tree_code dcode; 1167*e4b17023SJohn Marino gimple oe1def; 1168*e4b17023SJohn Marino 1169*e4b17023SJohn Marino if (TREE_CODE (oe1->op) != SSA_NAME) 1170*e4b17023SJohn Marino continue; 1171*e4b17023SJohn Marino oe1def = SSA_NAME_DEF_STMT (oe1->op); 1172*e4b17023SJohn Marino if (!is_gimple_assign (oe1def)) 1173*e4b17023SJohn Marino continue; 1174*e4b17023SJohn Marino dcode = gimple_assign_rhs_code (oe1def); 1175*e4b17023SJohn Marino if ((dcode != MULT_EXPR 1176*e4b17023SJohn Marino && dcode != RDIV_EXPR) 1177*e4b17023SJohn Marino || !is_reassociable_op (oe1def, dcode, loop)) 1178*e4b17023SJohn Marino continue; 1179*e4b17023SJohn Marino 1180*e4b17023SJohn Marino SET_BIT (candidates, i); 1181*e4b17023SJohn Marino nr_candidates++; 1182*e4b17023SJohn Marino } 1183*e4b17023SJohn Marino 1184*e4b17023SJohn Marino if (nr_candidates < 2) 1185*e4b17023SJohn Marino { 1186*e4b17023SJohn Marino sbitmap_free (candidates); 1187*e4b17023SJohn Marino return false; 1188*e4b17023SJohn Marino } 1189*e4b17023SJohn Marino 1190*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1191*e4b17023SJohn Marino { 1192*e4b17023SJohn Marino fprintf (dump_file, "searching for un-distribute opportunities "); 1193*e4b17023SJohn Marino print_generic_expr (dump_file, 1194*e4b17023SJohn Marino VEC_index (operand_entry_t, *ops, 1195*e4b17023SJohn Marino sbitmap_first_set_bit (candidates))->op, 0); 1196*e4b17023SJohn Marino fprintf (dump_file, " %d\n", nr_candidates); 1197*e4b17023SJohn Marino } 1198*e4b17023SJohn Marino 1199*e4b17023SJohn Marino /* Build linearized sub-operand lists and the counting table. */ 1200*e4b17023SJohn Marino cvec = NULL; 1201*e4b17023SJohn Marino ctable = htab_create (15, oecount_hash, oecount_eq, NULL); 1202*e4b17023SJohn Marino subops = XCNEWVEC (VEC (operand_entry_t, heap) *, 1203*e4b17023SJohn Marino VEC_length (operand_entry_t, *ops)); 1204*e4b17023SJohn Marino EXECUTE_IF_SET_IN_SBITMAP (candidates, 0, i, sbi0) 1205*e4b17023SJohn Marino { 1206*e4b17023SJohn Marino gimple oedef; 1207*e4b17023SJohn Marino enum tree_code oecode; 1208*e4b17023SJohn Marino unsigned j; 1209*e4b17023SJohn Marino 1210*e4b17023SJohn Marino oedef = SSA_NAME_DEF_STMT (VEC_index (operand_entry_t, *ops, i)->op); 1211*e4b17023SJohn Marino oecode = gimple_assign_rhs_code (oedef); 1212*e4b17023SJohn Marino linearize_expr_tree (&subops[i], oedef, 1213*e4b17023SJohn Marino associative_tree_code (oecode), false); 1214*e4b17023SJohn Marino 1215*e4b17023SJohn Marino FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1) 1216*e4b17023SJohn Marino { 1217*e4b17023SJohn Marino oecount c; 1218*e4b17023SJohn Marino void **slot; 1219*e4b17023SJohn Marino size_t idx; 1220*e4b17023SJohn Marino c.oecode = oecode; 1221*e4b17023SJohn Marino c.cnt = 1; 1222*e4b17023SJohn Marino c.id = next_oecount_id++; 1223*e4b17023SJohn Marino c.op = oe1->op; 1224*e4b17023SJohn Marino VEC_safe_push (oecount, heap, cvec, &c); 1225*e4b17023SJohn Marino idx = VEC_length (oecount, cvec) + 41; 1226*e4b17023SJohn Marino slot = htab_find_slot (ctable, (void *)idx, INSERT); 1227*e4b17023SJohn Marino if (!*slot) 1228*e4b17023SJohn Marino { 1229*e4b17023SJohn Marino *slot = (void *)idx; 1230*e4b17023SJohn Marino } 1231*e4b17023SJohn Marino else 1232*e4b17023SJohn Marino { 1233*e4b17023SJohn Marino VEC_pop (oecount, cvec); 1234*e4b17023SJohn Marino VEC_index (oecount, cvec, (size_t)*slot - 42)->cnt++; 1235*e4b17023SJohn Marino } 1236*e4b17023SJohn Marino } 1237*e4b17023SJohn Marino } 1238*e4b17023SJohn Marino htab_delete (ctable); 1239*e4b17023SJohn Marino 1240*e4b17023SJohn Marino /* Sort the counting table. */ 1241*e4b17023SJohn Marino VEC_qsort (oecount, cvec, oecount_cmp); 1242*e4b17023SJohn Marino 1243*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1244*e4b17023SJohn Marino { 1245*e4b17023SJohn Marino oecount *c; 1246*e4b17023SJohn Marino fprintf (dump_file, "Candidates:\n"); 1247*e4b17023SJohn Marino FOR_EACH_VEC_ELT (oecount, cvec, j, c) 1248*e4b17023SJohn Marino { 1249*e4b17023SJohn Marino fprintf (dump_file, " %u %s: ", c->cnt, 1250*e4b17023SJohn Marino c->oecode == MULT_EXPR 1251*e4b17023SJohn Marino ? "*" : c->oecode == RDIV_EXPR ? "/" : "?"); 1252*e4b17023SJohn Marino print_generic_expr (dump_file, c->op, 0); 1253*e4b17023SJohn Marino fprintf (dump_file, "\n"); 1254*e4b17023SJohn Marino } 1255*e4b17023SJohn Marino } 1256*e4b17023SJohn Marino 1257*e4b17023SJohn Marino /* Process the (operand, code) pairs in order of most occurence. */ 1258*e4b17023SJohn Marino candidates2 = sbitmap_alloc (length); 1259*e4b17023SJohn Marino while (!VEC_empty (oecount, cvec)) 1260*e4b17023SJohn Marino { 1261*e4b17023SJohn Marino oecount *c = VEC_last (oecount, cvec); 1262*e4b17023SJohn Marino if (c->cnt < 2) 1263*e4b17023SJohn Marino break; 1264*e4b17023SJohn Marino 1265*e4b17023SJohn Marino /* Now collect the operands in the outer chain that contain 1266*e4b17023SJohn Marino the common operand in their inner chain. */ 1267*e4b17023SJohn Marino sbitmap_zero (candidates2); 1268*e4b17023SJohn Marino nr_candidates2 = 0; 1269*e4b17023SJohn Marino EXECUTE_IF_SET_IN_SBITMAP (candidates, 0, i, sbi0) 1270*e4b17023SJohn Marino { 1271*e4b17023SJohn Marino gimple oedef; 1272*e4b17023SJohn Marino enum tree_code oecode; 1273*e4b17023SJohn Marino unsigned j; 1274*e4b17023SJohn Marino tree op = VEC_index (operand_entry_t, *ops, i)->op; 1275*e4b17023SJohn Marino 1276*e4b17023SJohn Marino /* If we undistributed in this chain already this may be 1277*e4b17023SJohn Marino a constant. */ 1278*e4b17023SJohn Marino if (TREE_CODE (op) != SSA_NAME) 1279*e4b17023SJohn Marino continue; 1280*e4b17023SJohn Marino 1281*e4b17023SJohn Marino oedef = SSA_NAME_DEF_STMT (op); 1282*e4b17023SJohn Marino oecode = gimple_assign_rhs_code (oedef); 1283*e4b17023SJohn Marino if (oecode != c->oecode) 1284*e4b17023SJohn Marino continue; 1285*e4b17023SJohn Marino 1286*e4b17023SJohn Marino FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1) 1287*e4b17023SJohn Marino { 1288*e4b17023SJohn Marino if (oe1->op == c->op) 1289*e4b17023SJohn Marino { 1290*e4b17023SJohn Marino SET_BIT (candidates2, i); 1291*e4b17023SJohn Marino ++nr_candidates2; 1292*e4b17023SJohn Marino break; 1293*e4b17023SJohn Marino } 1294*e4b17023SJohn Marino } 1295*e4b17023SJohn Marino } 1296*e4b17023SJohn Marino 1297*e4b17023SJohn Marino if (nr_candidates2 >= 2) 1298*e4b17023SJohn Marino { 1299*e4b17023SJohn Marino operand_entry_t oe1, oe2; 1300*e4b17023SJohn Marino tree tmpvar; 1301*e4b17023SJohn Marino gimple prod; 1302*e4b17023SJohn Marino int first = sbitmap_first_set_bit (candidates2); 1303*e4b17023SJohn Marino 1304*e4b17023SJohn Marino /* Build the new addition chain. */ 1305*e4b17023SJohn Marino oe1 = VEC_index (operand_entry_t, *ops, first); 1306*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1307*e4b17023SJohn Marino { 1308*e4b17023SJohn Marino fprintf (dump_file, "Building ("); 1309*e4b17023SJohn Marino print_generic_expr (dump_file, oe1->op, 0); 1310*e4b17023SJohn Marino } 1311*e4b17023SJohn Marino tmpvar = create_tmp_reg (TREE_TYPE (oe1->op), NULL); 1312*e4b17023SJohn Marino add_referenced_var (tmpvar); 1313*e4b17023SJohn Marino zero_one_operation (&oe1->op, c->oecode, c->op); 1314*e4b17023SJohn Marino EXECUTE_IF_SET_IN_SBITMAP (candidates2, first+1, i, sbi0) 1315*e4b17023SJohn Marino { 1316*e4b17023SJohn Marino gimple sum; 1317*e4b17023SJohn Marino oe2 = VEC_index (operand_entry_t, *ops, i); 1318*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1319*e4b17023SJohn Marino { 1320*e4b17023SJohn Marino fprintf (dump_file, " + "); 1321*e4b17023SJohn Marino print_generic_expr (dump_file, oe2->op, 0); 1322*e4b17023SJohn Marino } 1323*e4b17023SJohn Marino zero_one_operation (&oe2->op, c->oecode, c->op); 1324*e4b17023SJohn Marino sum = build_and_add_sum (tmpvar, oe1->op, oe2->op, opcode); 1325*e4b17023SJohn Marino oe2->op = build_zero_cst (TREE_TYPE (oe2->op)); 1326*e4b17023SJohn Marino oe2->rank = 0; 1327*e4b17023SJohn Marino oe1->op = gimple_get_lhs (sum); 1328*e4b17023SJohn Marino } 1329*e4b17023SJohn Marino 1330*e4b17023SJohn Marino /* Apply the multiplication/division. */ 1331*e4b17023SJohn Marino prod = build_and_add_sum (tmpvar, oe1->op, c->op, c->oecode); 1332*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1333*e4b17023SJohn Marino { 1334*e4b17023SJohn Marino fprintf (dump_file, ") %s ", c->oecode == MULT_EXPR ? "*" : "/"); 1335*e4b17023SJohn Marino print_generic_expr (dump_file, c->op, 0); 1336*e4b17023SJohn Marino fprintf (dump_file, "\n"); 1337*e4b17023SJohn Marino } 1338*e4b17023SJohn Marino 1339*e4b17023SJohn Marino /* Record it in the addition chain and disable further 1340*e4b17023SJohn Marino undistribution with this op. */ 1341*e4b17023SJohn Marino oe1->op = gimple_assign_lhs (prod); 1342*e4b17023SJohn Marino oe1->rank = get_rank (oe1->op); 1343*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, subops[first]); 1344*e4b17023SJohn Marino 1345*e4b17023SJohn Marino changed = true; 1346*e4b17023SJohn Marino } 1347*e4b17023SJohn Marino 1348*e4b17023SJohn Marino VEC_pop (oecount, cvec); 1349*e4b17023SJohn Marino } 1350*e4b17023SJohn Marino 1351*e4b17023SJohn Marino for (i = 0; i < VEC_length (operand_entry_t, *ops); ++i) 1352*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, subops[i]); 1353*e4b17023SJohn Marino free (subops); 1354*e4b17023SJohn Marino VEC_free (oecount, heap, cvec); 1355*e4b17023SJohn Marino sbitmap_free (candidates); 1356*e4b17023SJohn Marino sbitmap_free (candidates2); 1357*e4b17023SJohn Marino 1358*e4b17023SJohn Marino return changed; 1359*e4b17023SJohn Marino } 1360*e4b17023SJohn Marino 1361*e4b17023SJohn Marino /* If OPCODE is BIT_IOR_EXPR or BIT_AND_EXPR and CURR is a comparison 1362*e4b17023SJohn Marino expression, examine the other OPS to see if any of them are comparisons 1363*e4b17023SJohn Marino of the same values, which we may be able to combine or eliminate. 1364*e4b17023SJohn Marino For example, we can rewrite (a < b) | (a == b) as (a <= b). */ 1365*e4b17023SJohn Marino 1366*e4b17023SJohn Marino static bool 1367*e4b17023SJohn Marino eliminate_redundant_comparison (enum tree_code opcode, 1368*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops, 1369*e4b17023SJohn Marino unsigned int currindex, 1370*e4b17023SJohn Marino operand_entry_t curr) 1371*e4b17023SJohn Marino { 1372*e4b17023SJohn Marino tree op1, op2; 1373*e4b17023SJohn Marino enum tree_code lcode, rcode; 1374*e4b17023SJohn Marino gimple def1, def2; 1375*e4b17023SJohn Marino int i; 1376*e4b17023SJohn Marino operand_entry_t oe; 1377*e4b17023SJohn Marino 1378*e4b17023SJohn Marino if (opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR) 1379*e4b17023SJohn Marino return false; 1380*e4b17023SJohn Marino 1381*e4b17023SJohn Marino /* Check that CURR is a comparison. */ 1382*e4b17023SJohn Marino if (TREE_CODE (curr->op) != SSA_NAME) 1383*e4b17023SJohn Marino return false; 1384*e4b17023SJohn Marino def1 = SSA_NAME_DEF_STMT (curr->op); 1385*e4b17023SJohn Marino if (!is_gimple_assign (def1)) 1386*e4b17023SJohn Marino return false; 1387*e4b17023SJohn Marino lcode = gimple_assign_rhs_code (def1); 1388*e4b17023SJohn Marino if (TREE_CODE_CLASS (lcode) != tcc_comparison) 1389*e4b17023SJohn Marino return false; 1390*e4b17023SJohn Marino op1 = gimple_assign_rhs1 (def1); 1391*e4b17023SJohn Marino op2 = gimple_assign_rhs2 (def1); 1392*e4b17023SJohn Marino 1393*e4b17023SJohn Marino /* Now look for a similar comparison in the remaining OPS. */ 1394*e4b17023SJohn Marino for (i = currindex + 1; 1395*e4b17023SJohn Marino VEC_iterate (operand_entry_t, *ops, i, oe); 1396*e4b17023SJohn Marino i++) 1397*e4b17023SJohn Marino { 1398*e4b17023SJohn Marino tree t; 1399*e4b17023SJohn Marino 1400*e4b17023SJohn Marino if (TREE_CODE (oe->op) != SSA_NAME) 1401*e4b17023SJohn Marino continue; 1402*e4b17023SJohn Marino def2 = SSA_NAME_DEF_STMT (oe->op); 1403*e4b17023SJohn Marino if (!is_gimple_assign (def2)) 1404*e4b17023SJohn Marino continue; 1405*e4b17023SJohn Marino rcode = gimple_assign_rhs_code (def2); 1406*e4b17023SJohn Marino if (TREE_CODE_CLASS (rcode) != tcc_comparison) 1407*e4b17023SJohn Marino continue; 1408*e4b17023SJohn Marino 1409*e4b17023SJohn Marino /* If we got here, we have a match. See if we can combine the 1410*e4b17023SJohn Marino two comparisons. */ 1411*e4b17023SJohn Marino if (opcode == BIT_IOR_EXPR) 1412*e4b17023SJohn Marino t = maybe_fold_or_comparisons (lcode, op1, op2, 1413*e4b17023SJohn Marino rcode, gimple_assign_rhs1 (def2), 1414*e4b17023SJohn Marino gimple_assign_rhs2 (def2)); 1415*e4b17023SJohn Marino else 1416*e4b17023SJohn Marino t = maybe_fold_and_comparisons (lcode, op1, op2, 1417*e4b17023SJohn Marino rcode, gimple_assign_rhs1 (def2), 1418*e4b17023SJohn Marino gimple_assign_rhs2 (def2)); 1419*e4b17023SJohn Marino if (!t) 1420*e4b17023SJohn Marino continue; 1421*e4b17023SJohn Marino 1422*e4b17023SJohn Marino /* maybe_fold_and_comparisons and maybe_fold_or_comparisons 1423*e4b17023SJohn Marino always give us a boolean_type_node value back. If the original 1424*e4b17023SJohn Marino BIT_AND_EXPR or BIT_IOR_EXPR was of a wider integer type, 1425*e4b17023SJohn Marino we need to convert. */ 1426*e4b17023SJohn Marino if (!useless_type_conversion_p (TREE_TYPE (curr->op), TREE_TYPE (t))) 1427*e4b17023SJohn Marino t = fold_convert (TREE_TYPE (curr->op), t); 1428*e4b17023SJohn Marino 1429*e4b17023SJohn Marino if (TREE_CODE (t) != INTEGER_CST 1430*e4b17023SJohn Marino && !operand_equal_p (t, curr->op, 0)) 1431*e4b17023SJohn Marino { 1432*e4b17023SJohn Marino enum tree_code subcode; 1433*e4b17023SJohn Marino tree newop1, newop2; 1434*e4b17023SJohn Marino if (!COMPARISON_CLASS_P (t)) 1435*e4b17023SJohn Marino continue; 1436*e4b17023SJohn Marino extract_ops_from_tree (t, &subcode, &newop1, &newop2); 1437*e4b17023SJohn Marino STRIP_USELESS_TYPE_CONVERSION (newop1); 1438*e4b17023SJohn Marino STRIP_USELESS_TYPE_CONVERSION (newop2); 1439*e4b17023SJohn Marino if (!is_gimple_val (newop1) || !is_gimple_val (newop2)) 1440*e4b17023SJohn Marino continue; 1441*e4b17023SJohn Marino } 1442*e4b17023SJohn Marino 1443*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1444*e4b17023SJohn Marino { 1445*e4b17023SJohn Marino fprintf (dump_file, "Equivalence: "); 1446*e4b17023SJohn Marino print_generic_expr (dump_file, curr->op, 0); 1447*e4b17023SJohn Marino fprintf (dump_file, " %s ", op_symbol_code (opcode)); 1448*e4b17023SJohn Marino print_generic_expr (dump_file, oe->op, 0); 1449*e4b17023SJohn Marino fprintf (dump_file, " -> "); 1450*e4b17023SJohn Marino print_generic_expr (dump_file, t, 0); 1451*e4b17023SJohn Marino fprintf (dump_file, "\n"); 1452*e4b17023SJohn Marino } 1453*e4b17023SJohn Marino 1454*e4b17023SJohn Marino /* Now we can delete oe, as it has been subsumed by the new combined 1455*e4b17023SJohn Marino expression t. */ 1456*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, i); 1457*e4b17023SJohn Marino reassociate_stats.ops_eliminated ++; 1458*e4b17023SJohn Marino 1459*e4b17023SJohn Marino /* If t is the same as curr->op, we're done. Otherwise we must 1460*e4b17023SJohn Marino replace curr->op with t. Special case is if we got a constant 1461*e4b17023SJohn Marino back, in which case we add it to the end instead of in place of 1462*e4b17023SJohn Marino the current entry. */ 1463*e4b17023SJohn Marino if (TREE_CODE (t) == INTEGER_CST) 1464*e4b17023SJohn Marino { 1465*e4b17023SJohn Marino VEC_ordered_remove (operand_entry_t, *ops, currindex); 1466*e4b17023SJohn Marino add_to_ops_vec (ops, t); 1467*e4b17023SJohn Marino } 1468*e4b17023SJohn Marino else if (!operand_equal_p (t, curr->op, 0)) 1469*e4b17023SJohn Marino { 1470*e4b17023SJohn Marino tree tmpvar; 1471*e4b17023SJohn Marino gimple sum; 1472*e4b17023SJohn Marino enum tree_code subcode; 1473*e4b17023SJohn Marino tree newop1; 1474*e4b17023SJohn Marino tree newop2; 1475*e4b17023SJohn Marino gcc_assert (COMPARISON_CLASS_P (t)); 1476*e4b17023SJohn Marino tmpvar = create_tmp_var (TREE_TYPE (t), NULL); 1477*e4b17023SJohn Marino add_referenced_var (tmpvar); 1478*e4b17023SJohn Marino extract_ops_from_tree (t, &subcode, &newop1, &newop2); 1479*e4b17023SJohn Marino STRIP_USELESS_TYPE_CONVERSION (newop1); 1480*e4b17023SJohn Marino STRIP_USELESS_TYPE_CONVERSION (newop2); 1481*e4b17023SJohn Marino gcc_checking_assert (is_gimple_val (newop1) 1482*e4b17023SJohn Marino && is_gimple_val (newop2)); 1483*e4b17023SJohn Marino sum = build_and_add_sum (tmpvar, newop1, newop2, subcode); 1484*e4b17023SJohn Marino curr->op = gimple_get_lhs (sum); 1485*e4b17023SJohn Marino } 1486*e4b17023SJohn Marino return true; 1487*e4b17023SJohn Marino } 1488*e4b17023SJohn Marino 1489*e4b17023SJohn Marino return false; 1490*e4b17023SJohn Marino } 1491*e4b17023SJohn Marino 1492*e4b17023SJohn Marino /* Perform various identities and other optimizations on the list of 1493*e4b17023SJohn Marino operand entries, stored in OPS. The tree code for the binary 1494*e4b17023SJohn Marino operation between all the operands is OPCODE. */ 1495*e4b17023SJohn Marino 1496*e4b17023SJohn Marino static void 1497*e4b17023SJohn Marino optimize_ops_list (enum tree_code opcode, 1498*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops) 1499*e4b17023SJohn Marino { 1500*e4b17023SJohn Marino unsigned int length = VEC_length (operand_entry_t, *ops); 1501*e4b17023SJohn Marino unsigned int i; 1502*e4b17023SJohn Marino operand_entry_t oe; 1503*e4b17023SJohn Marino operand_entry_t oelast = NULL; 1504*e4b17023SJohn Marino bool iterate = false; 1505*e4b17023SJohn Marino 1506*e4b17023SJohn Marino if (length == 1) 1507*e4b17023SJohn Marino return; 1508*e4b17023SJohn Marino 1509*e4b17023SJohn Marino oelast = VEC_last (operand_entry_t, *ops); 1510*e4b17023SJohn Marino 1511*e4b17023SJohn Marino /* If the last two are constants, pop the constants off, merge them 1512*e4b17023SJohn Marino and try the next two. */ 1513*e4b17023SJohn Marino if (oelast->rank == 0 && is_gimple_min_invariant (oelast->op)) 1514*e4b17023SJohn Marino { 1515*e4b17023SJohn Marino operand_entry_t oelm1 = VEC_index (operand_entry_t, *ops, length - 2); 1516*e4b17023SJohn Marino 1517*e4b17023SJohn Marino if (oelm1->rank == 0 1518*e4b17023SJohn Marino && is_gimple_min_invariant (oelm1->op) 1519*e4b17023SJohn Marino && useless_type_conversion_p (TREE_TYPE (oelm1->op), 1520*e4b17023SJohn Marino TREE_TYPE (oelast->op))) 1521*e4b17023SJohn Marino { 1522*e4b17023SJohn Marino tree folded = fold_binary (opcode, TREE_TYPE (oelm1->op), 1523*e4b17023SJohn Marino oelm1->op, oelast->op); 1524*e4b17023SJohn Marino 1525*e4b17023SJohn Marino if (folded && is_gimple_min_invariant (folded)) 1526*e4b17023SJohn Marino { 1527*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1528*e4b17023SJohn Marino fprintf (dump_file, "Merging constants\n"); 1529*e4b17023SJohn Marino 1530*e4b17023SJohn Marino VEC_pop (operand_entry_t, *ops); 1531*e4b17023SJohn Marino VEC_pop (operand_entry_t, *ops); 1532*e4b17023SJohn Marino 1533*e4b17023SJohn Marino add_to_ops_vec (ops, folded); 1534*e4b17023SJohn Marino reassociate_stats.constants_eliminated++; 1535*e4b17023SJohn Marino 1536*e4b17023SJohn Marino optimize_ops_list (opcode, ops); 1537*e4b17023SJohn Marino return; 1538*e4b17023SJohn Marino } 1539*e4b17023SJohn Marino } 1540*e4b17023SJohn Marino } 1541*e4b17023SJohn Marino 1542*e4b17023SJohn Marino eliminate_using_constants (opcode, ops); 1543*e4b17023SJohn Marino oelast = NULL; 1544*e4b17023SJohn Marino 1545*e4b17023SJohn Marino for (i = 0; VEC_iterate (operand_entry_t, *ops, i, oe);) 1546*e4b17023SJohn Marino { 1547*e4b17023SJohn Marino bool done = false; 1548*e4b17023SJohn Marino 1549*e4b17023SJohn Marino if (eliminate_not_pairs (opcode, ops, i, oe)) 1550*e4b17023SJohn Marino return; 1551*e4b17023SJohn Marino if (eliminate_duplicate_pair (opcode, ops, &done, i, oe, oelast) 1552*e4b17023SJohn Marino || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe)) 1553*e4b17023SJohn Marino || (!done && eliminate_redundant_comparison (opcode, ops, i, oe))) 1554*e4b17023SJohn Marino { 1555*e4b17023SJohn Marino if (done) 1556*e4b17023SJohn Marino return; 1557*e4b17023SJohn Marino iterate = true; 1558*e4b17023SJohn Marino oelast = NULL; 1559*e4b17023SJohn Marino continue; 1560*e4b17023SJohn Marino } 1561*e4b17023SJohn Marino oelast = oe; 1562*e4b17023SJohn Marino i++; 1563*e4b17023SJohn Marino } 1564*e4b17023SJohn Marino 1565*e4b17023SJohn Marino length = VEC_length (operand_entry_t, *ops); 1566*e4b17023SJohn Marino oelast = VEC_last (operand_entry_t, *ops); 1567*e4b17023SJohn Marino 1568*e4b17023SJohn Marino if (iterate) 1569*e4b17023SJohn Marino optimize_ops_list (opcode, ops); 1570*e4b17023SJohn Marino } 1571*e4b17023SJohn Marino 1572*e4b17023SJohn Marino /* The following functions are subroutines to optimize_range_tests and allow 1573*e4b17023SJohn Marino it to try to change a logical combination of comparisons into a range 1574*e4b17023SJohn Marino test. 1575*e4b17023SJohn Marino 1576*e4b17023SJohn Marino For example, both 1577*e4b17023SJohn Marino X == 2 || X == 5 || X == 3 || X == 4 1578*e4b17023SJohn Marino and 1579*e4b17023SJohn Marino X >= 2 && X <= 5 1580*e4b17023SJohn Marino are converted to 1581*e4b17023SJohn Marino (unsigned) (X - 2) <= 3 1582*e4b17023SJohn Marino 1583*e4b17023SJohn Marino For more information see comments above fold_test_range in fold-const.c, 1584*e4b17023SJohn Marino this implementation is for GIMPLE. */ 1585*e4b17023SJohn Marino 1586*e4b17023SJohn Marino struct range_entry 1587*e4b17023SJohn Marino { 1588*e4b17023SJohn Marino tree exp; 1589*e4b17023SJohn Marino tree low; 1590*e4b17023SJohn Marino tree high; 1591*e4b17023SJohn Marino bool in_p; 1592*e4b17023SJohn Marino bool strict_overflow_p; 1593*e4b17023SJohn Marino unsigned int idx, next; 1594*e4b17023SJohn Marino }; 1595*e4b17023SJohn Marino 1596*e4b17023SJohn Marino /* This is similar to make_range in fold-const.c, but on top of 1597*e4b17023SJohn Marino GIMPLE instead of trees. */ 1598*e4b17023SJohn Marino 1599*e4b17023SJohn Marino static void 1600*e4b17023SJohn Marino init_range_entry (struct range_entry *r, tree exp) 1601*e4b17023SJohn Marino { 1602*e4b17023SJohn Marino int in_p; 1603*e4b17023SJohn Marino tree low, high; 1604*e4b17023SJohn Marino bool is_bool, strict_overflow_p; 1605*e4b17023SJohn Marino 1606*e4b17023SJohn Marino r->exp = NULL_TREE; 1607*e4b17023SJohn Marino r->in_p = false; 1608*e4b17023SJohn Marino r->strict_overflow_p = false; 1609*e4b17023SJohn Marino r->low = NULL_TREE; 1610*e4b17023SJohn Marino r->high = NULL_TREE; 1611*e4b17023SJohn Marino if (TREE_CODE (exp) != SSA_NAME || !INTEGRAL_TYPE_P (TREE_TYPE (exp))) 1612*e4b17023SJohn Marino return; 1613*e4b17023SJohn Marino 1614*e4b17023SJohn Marino /* Start with simply saying "EXP != 0" and then look at the code of EXP 1615*e4b17023SJohn Marino and see if we can refine the range. Some of the cases below may not 1616*e4b17023SJohn Marino happen, but it doesn't seem worth worrying about this. We "continue" 1617*e4b17023SJohn Marino the outer loop when we've changed something; otherwise we "break" 1618*e4b17023SJohn Marino the switch, which will "break" the while. */ 1619*e4b17023SJohn Marino low = build_int_cst (TREE_TYPE (exp), 0); 1620*e4b17023SJohn Marino high = low; 1621*e4b17023SJohn Marino in_p = 0; 1622*e4b17023SJohn Marino strict_overflow_p = false; 1623*e4b17023SJohn Marino is_bool = false; 1624*e4b17023SJohn Marino if (TYPE_PRECISION (TREE_TYPE (exp)) == 1) 1625*e4b17023SJohn Marino { 1626*e4b17023SJohn Marino if (TYPE_UNSIGNED (TREE_TYPE (exp))) 1627*e4b17023SJohn Marino is_bool = true; 1628*e4b17023SJohn Marino else 1629*e4b17023SJohn Marino return; 1630*e4b17023SJohn Marino } 1631*e4b17023SJohn Marino else if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE) 1632*e4b17023SJohn Marino is_bool = true; 1633*e4b17023SJohn Marino 1634*e4b17023SJohn Marino while (1) 1635*e4b17023SJohn Marino { 1636*e4b17023SJohn Marino gimple stmt; 1637*e4b17023SJohn Marino enum tree_code code; 1638*e4b17023SJohn Marino tree arg0, arg1, exp_type; 1639*e4b17023SJohn Marino tree nexp; 1640*e4b17023SJohn Marino location_t loc; 1641*e4b17023SJohn Marino 1642*e4b17023SJohn Marino if (TREE_CODE (exp) != SSA_NAME) 1643*e4b17023SJohn Marino break; 1644*e4b17023SJohn Marino 1645*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (exp); 1646*e4b17023SJohn Marino if (!is_gimple_assign (stmt)) 1647*e4b17023SJohn Marino break; 1648*e4b17023SJohn Marino 1649*e4b17023SJohn Marino code = gimple_assign_rhs_code (stmt); 1650*e4b17023SJohn Marino arg0 = gimple_assign_rhs1 (stmt); 1651*e4b17023SJohn Marino if (TREE_CODE (arg0) != SSA_NAME) 1652*e4b17023SJohn Marino break; 1653*e4b17023SJohn Marino arg1 = gimple_assign_rhs2 (stmt); 1654*e4b17023SJohn Marino exp_type = TREE_TYPE (exp); 1655*e4b17023SJohn Marino loc = gimple_location (stmt); 1656*e4b17023SJohn Marino switch (code) 1657*e4b17023SJohn Marino { 1658*e4b17023SJohn Marino case BIT_NOT_EXPR: 1659*e4b17023SJohn Marino if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE) 1660*e4b17023SJohn Marino { 1661*e4b17023SJohn Marino in_p = !in_p; 1662*e4b17023SJohn Marino exp = arg0; 1663*e4b17023SJohn Marino continue; 1664*e4b17023SJohn Marino } 1665*e4b17023SJohn Marino break; 1666*e4b17023SJohn Marino case SSA_NAME: 1667*e4b17023SJohn Marino exp = arg0; 1668*e4b17023SJohn Marino continue; 1669*e4b17023SJohn Marino CASE_CONVERT: 1670*e4b17023SJohn Marino if (is_bool) 1671*e4b17023SJohn Marino goto do_default; 1672*e4b17023SJohn Marino if (TYPE_PRECISION (TREE_TYPE (arg0)) == 1) 1673*e4b17023SJohn Marino { 1674*e4b17023SJohn Marino if (TYPE_UNSIGNED (TREE_TYPE (arg0))) 1675*e4b17023SJohn Marino is_bool = true; 1676*e4b17023SJohn Marino else 1677*e4b17023SJohn Marino return; 1678*e4b17023SJohn Marino } 1679*e4b17023SJohn Marino else if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE) 1680*e4b17023SJohn Marino is_bool = true; 1681*e4b17023SJohn Marino goto do_default; 1682*e4b17023SJohn Marino case EQ_EXPR: 1683*e4b17023SJohn Marino case NE_EXPR: 1684*e4b17023SJohn Marino case LT_EXPR: 1685*e4b17023SJohn Marino case LE_EXPR: 1686*e4b17023SJohn Marino case GE_EXPR: 1687*e4b17023SJohn Marino case GT_EXPR: 1688*e4b17023SJohn Marino is_bool = true; 1689*e4b17023SJohn Marino /* FALLTHRU */ 1690*e4b17023SJohn Marino default: 1691*e4b17023SJohn Marino if (!is_bool) 1692*e4b17023SJohn Marino return; 1693*e4b17023SJohn Marino do_default: 1694*e4b17023SJohn Marino nexp = make_range_step (loc, code, arg0, arg1, exp_type, 1695*e4b17023SJohn Marino &low, &high, &in_p, 1696*e4b17023SJohn Marino &strict_overflow_p); 1697*e4b17023SJohn Marino if (nexp != NULL_TREE) 1698*e4b17023SJohn Marino { 1699*e4b17023SJohn Marino exp = nexp; 1700*e4b17023SJohn Marino gcc_assert (TREE_CODE (exp) == SSA_NAME); 1701*e4b17023SJohn Marino continue; 1702*e4b17023SJohn Marino } 1703*e4b17023SJohn Marino break; 1704*e4b17023SJohn Marino } 1705*e4b17023SJohn Marino break; 1706*e4b17023SJohn Marino } 1707*e4b17023SJohn Marino if (is_bool) 1708*e4b17023SJohn Marino { 1709*e4b17023SJohn Marino r->exp = exp; 1710*e4b17023SJohn Marino r->in_p = in_p; 1711*e4b17023SJohn Marino r->low = low; 1712*e4b17023SJohn Marino r->high = high; 1713*e4b17023SJohn Marino r->strict_overflow_p = strict_overflow_p; 1714*e4b17023SJohn Marino } 1715*e4b17023SJohn Marino } 1716*e4b17023SJohn Marino 1717*e4b17023SJohn Marino /* Comparison function for qsort. Sort entries 1718*e4b17023SJohn Marino without SSA_NAME exp first, then with SSA_NAMEs sorted 1719*e4b17023SJohn Marino by increasing SSA_NAME_VERSION, and for the same SSA_NAMEs 1720*e4b17023SJohn Marino by increasing ->low and if ->low is the same, by increasing 1721*e4b17023SJohn Marino ->high. ->low == NULL_TREE means minimum, ->high == NULL_TREE 1722*e4b17023SJohn Marino maximum. */ 1723*e4b17023SJohn Marino 1724*e4b17023SJohn Marino static int 1725*e4b17023SJohn Marino range_entry_cmp (const void *a, const void *b) 1726*e4b17023SJohn Marino { 1727*e4b17023SJohn Marino const struct range_entry *p = (const struct range_entry *) a; 1728*e4b17023SJohn Marino const struct range_entry *q = (const struct range_entry *) b; 1729*e4b17023SJohn Marino 1730*e4b17023SJohn Marino if (p->exp != NULL_TREE && TREE_CODE (p->exp) == SSA_NAME) 1731*e4b17023SJohn Marino { 1732*e4b17023SJohn Marino if (q->exp != NULL_TREE && TREE_CODE (q->exp) == SSA_NAME) 1733*e4b17023SJohn Marino { 1734*e4b17023SJohn Marino /* Group range_entries for the same SSA_NAME together. */ 1735*e4b17023SJohn Marino if (SSA_NAME_VERSION (p->exp) < SSA_NAME_VERSION (q->exp)) 1736*e4b17023SJohn Marino return -1; 1737*e4b17023SJohn Marino else if (SSA_NAME_VERSION (p->exp) > SSA_NAME_VERSION (q->exp)) 1738*e4b17023SJohn Marino return 1; 1739*e4b17023SJohn Marino /* If ->low is different, NULL low goes first, then by 1740*e4b17023SJohn Marino ascending low. */ 1741*e4b17023SJohn Marino if (p->low != NULL_TREE) 1742*e4b17023SJohn Marino { 1743*e4b17023SJohn Marino if (q->low != NULL_TREE) 1744*e4b17023SJohn Marino { 1745*e4b17023SJohn Marino tree tem = fold_binary (LT_EXPR, boolean_type_node, 1746*e4b17023SJohn Marino p->low, q->low); 1747*e4b17023SJohn Marino if (tem && integer_onep (tem)) 1748*e4b17023SJohn Marino return -1; 1749*e4b17023SJohn Marino tem = fold_binary (GT_EXPR, boolean_type_node, 1750*e4b17023SJohn Marino p->low, q->low); 1751*e4b17023SJohn Marino if (tem && integer_onep (tem)) 1752*e4b17023SJohn Marino return 1; 1753*e4b17023SJohn Marino } 1754*e4b17023SJohn Marino else 1755*e4b17023SJohn Marino return 1; 1756*e4b17023SJohn Marino } 1757*e4b17023SJohn Marino else if (q->low != NULL_TREE) 1758*e4b17023SJohn Marino return -1; 1759*e4b17023SJohn Marino /* If ->high is different, NULL high goes last, before that by 1760*e4b17023SJohn Marino ascending high. */ 1761*e4b17023SJohn Marino if (p->high != NULL_TREE) 1762*e4b17023SJohn Marino { 1763*e4b17023SJohn Marino if (q->high != NULL_TREE) 1764*e4b17023SJohn Marino { 1765*e4b17023SJohn Marino tree tem = fold_binary (LT_EXPR, boolean_type_node, 1766*e4b17023SJohn Marino p->high, q->high); 1767*e4b17023SJohn Marino if (tem && integer_onep (tem)) 1768*e4b17023SJohn Marino return -1; 1769*e4b17023SJohn Marino tem = fold_binary (GT_EXPR, boolean_type_node, 1770*e4b17023SJohn Marino p->high, q->high); 1771*e4b17023SJohn Marino if (tem && integer_onep (tem)) 1772*e4b17023SJohn Marino return 1; 1773*e4b17023SJohn Marino } 1774*e4b17023SJohn Marino else 1775*e4b17023SJohn Marino return -1; 1776*e4b17023SJohn Marino } 1777*e4b17023SJohn Marino else if (p->high != NULL_TREE) 1778*e4b17023SJohn Marino return 1; 1779*e4b17023SJohn Marino /* If both ranges are the same, sort below by ascending idx. */ 1780*e4b17023SJohn Marino } 1781*e4b17023SJohn Marino else 1782*e4b17023SJohn Marino return 1; 1783*e4b17023SJohn Marino } 1784*e4b17023SJohn Marino else if (q->exp != NULL_TREE && TREE_CODE (q->exp) == SSA_NAME) 1785*e4b17023SJohn Marino return -1; 1786*e4b17023SJohn Marino 1787*e4b17023SJohn Marino if (p->idx < q->idx) 1788*e4b17023SJohn Marino return -1; 1789*e4b17023SJohn Marino else 1790*e4b17023SJohn Marino { 1791*e4b17023SJohn Marino gcc_checking_assert (p->idx > q->idx); 1792*e4b17023SJohn Marino return 1; 1793*e4b17023SJohn Marino } 1794*e4b17023SJohn Marino } 1795*e4b17023SJohn Marino 1796*e4b17023SJohn Marino /* Helper routine of optimize_range_test. 1797*e4b17023SJohn Marino [EXP, IN_P, LOW, HIGH, STRICT_OVERFLOW_P] is a merged range for 1798*e4b17023SJohn Marino RANGE and OTHERRANGE through OTHERRANGE + COUNT - 1 ranges, 1799*e4b17023SJohn Marino OPCODE and OPS are arguments of optimize_range_tests. Return 1800*e4b17023SJohn Marino true if the range merge has been successful. */ 1801*e4b17023SJohn Marino 1802*e4b17023SJohn Marino static bool 1803*e4b17023SJohn Marino update_range_test (struct range_entry *range, struct range_entry *otherrange, 1804*e4b17023SJohn Marino unsigned int count, enum tree_code opcode, 1805*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops, tree exp, bool in_p, 1806*e4b17023SJohn Marino tree low, tree high, bool strict_overflow_p) 1807*e4b17023SJohn Marino { 1808*e4b17023SJohn Marino tree op = VEC_index (operand_entry_t, *ops, range->idx)->op; 1809*e4b17023SJohn Marino location_t loc = gimple_location (SSA_NAME_DEF_STMT (op)); 1810*e4b17023SJohn Marino tree tem = build_range_check (loc, TREE_TYPE (op), exp, in_p, low, high); 1811*e4b17023SJohn Marino enum warn_strict_overflow_code wc = WARN_STRICT_OVERFLOW_COMPARISON; 1812*e4b17023SJohn Marino gimple_stmt_iterator gsi; 1813*e4b17023SJohn Marino 1814*e4b17023SJohn Marino if (tem == NULL_TREE) 1815*e4b17023SJohn Marino return false; 1816*e4b17023SJohn Marino 1817*e4b17023SJohn Marino if (strict_overflow_p && issue_strict_overflow_warning (wc)) 1818*e4b17023SJohn Marino warning_at (loc, OPT_Wstrict_overflow, 1819*e4b17023SJohn Marino "assuming signed overflow does not occur " 1820*e4b17023SJohn Marino "when simplifying range test"); 1821*e4b17023SJohn Marino 1822*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 1823*e4b17023SJohn Marino { 1824*e4b17023SJohn Marino struct range_entry *r; 1825*e4b17023SJohn Marino fprintf (dump_file, "Optimizing range tests "); 1826*e4b17023SJohn Marino print_generic_expr (dump_file, range->exp, 0); 1827*e4b17023SJohn Marino fprintf (dump_file, " %c[", range->in_p ? '+' : '-'); 1828*e4b17023SJohn Marino print_generic_expr (dump_file, range->low, 0); 1829*e4b17023SJohn Marino fprintf (dump_file, ", "); 1830*e4b17023SJohn Marino print_generic_expr (dump_file, range->high, 0); 1831*e4b17023SJohn Marino fprintf (dump_file, "]"); 1832*e4b17023SJohn Marino for (r = otherrange; r < otherrange + count; r++) 1833*e4b17023SJohn Marino { 1834*e4b17023SJohn Marino fprintf (dump_file, " and %c[", r->in_p ? '+' : '-'); 1835*e4b17023SJohn Marino print_generic_expr (dump_file, r->low, 0); 1836*e4b17023SJohn Marino fprintf (dump_file, ", "); 1837*e4b17023SJohn Marino print_generic_expr (dump_file, r->high, 0); 1838*e4b17023SJohn Marino fprintf (dump_file, "]"); 1839*e4b17023SJohn Marino } 1840*e4b17023SJohn Marino fprintf (dump_file, "\n into "); 1841*e4b17023SJohn Marino print_generic_expr (dump_file, tem, 0); 1842*e4b17023SJohn Marino fprintf (dump_file, "\n"); 1843*e4b17023SJohn Marino } 1844*e4b17023SJohn Marino 1845*e4b17023SJohn Marino if (opcode == BIT_IOR_EXPR) 1846*e4b17023SJohn Marino tem = invert_truthvalue_loc (loc, tem); 1847*e4b17023SJohn Marino 1848*e4b17023SJohn Marino tem = fold_convert_loc (loc, TREE_TYPE (op), tem); 1849*e4b17023SJohn Marino gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (op)); 1850*e4b17023SJohn Marino tem = force_gimple_operand_gsi (&gsi, tem, true, NULL_TREE, true, 1851*e4b17023SJohn Marino GSI_SAME_STMT); 1852*e4b17023SJohn Marino 1853*e4b17023SJohn Marino VEC_index (operand_entry_t, *ops, range->idx)->op = tem; 1854*e4b17023SJohn Marino range->exp = exp; 1855*e4b17023SJohn Marino range->low = low; 1856*e4b17023SJohn Marino range->high = high; 1857*e4b17023SJohn Marino range->in_p = in_p; 1858*e4b17023SJohn Marino range->strict_overflow_p = false; 1859*e4b17023SJohn Marino 1860*e4b17023SJohn Marino for (range = otherrange; range < otherrange + count; range++) 1861*e4b17023SJohn Marino { 1862*e4b17023SJohn Marino VEC_index (operand_entry_t, *ops, range->idx)->op = error_mark_node; 1863*e4b17023SJohn Marino range->exp = NULL_TREE; 1864*e4b17023SJohn Marino } 1865*e4b17023SJohn Marino return true; 1866*e4b17023SJohn Marino } 1867*e4b17023SJohn Marino 1868*e4b17023SJohn Marino /* Optimize range tests, similarly how fold_range_test optimizes 1869*e4b17023SJohn Marino it on trees. The tree code for the binary 1870*e4b17023SJohn Marino operation between all the operands is OPCODE. */ 1871*e4b17023SJohn Marino 1872*e4b17023SJohn Marino static void 1873*e4b17023SJohn Marino optimize_range_tests (enum tree_code opcode, 1874*e4b17023SJohn Marino VEC (operand_entry_t, heap) **ops) 1875*e4b17023SJohn Marino { 1876*e4b17023SJohn Marino unsigned int length = VEC_length (operand_entry_t, *ops), i, j, first; 1877*e4b17023SJohn Marino operand_entry_t oe; 1878*e4b17023SJohn Marino struct range_entry *ranges; 1879*e4b17023SJohn Marino bool any_changes = false; 1880*e4b17023SJohn Marino 1881*e4b17023SJohn Marino if (length == 1) 1882*e4b17023SJohn Marino return; 1883*e4b17023SJohn Marino 1884*e4b17023SJohn Marino ranges = XNEWVEC (struct range_entry, length); 1885*e4b17023SJohn Marino for (i = 0; i < length; i++) 1886*e4b17023SJohn Marino { 1887*e4b17023SJohn Marino ranges[i].idx = i; 1888*e4b17023SJohn Marino init_range_entry (ranges + i, VEC_index (operand_entry_t, *ops, i)->op); 1889*e4b17023SJohn Marino /* For | invert it now, we will invert it again before emitting 1890*e4b17023SJohn Marino the optimized expression. */ 1891*e4b17023SJohn Marino if (opcode == BIT_IOR_EXPR) 1892*e4b17023SJohn Marino ranges[i].in_p = !ranges[i].in_p; 1893*e4b17023SJohn Marino } 1894*e4b17023SJohn Marino 1895*e4b17023SJohn Marino qsort (ranges, length, sizeof (*ranges), range_entry_cmp); 1896*e4b17023SJohn Marino for (i = 0; i < length; i++) 1897*e4b17023SJohn Marino if (ranges[i].exp != NULL_TREE && TREE_CODE (ranges[i].exp) == SSA_NAME) 1898*e4b17023SJohn Marino break; 1899*e4b17023SJohn Marino 1900*e4b17023SJohn Marino /* Try to merge ranges. */ 1901*e4b17023SJohn Marino for (first = i; i < length; i++) 1902*e4b17023SJohn Marino { 1903*e4b17023SJohn Marino tree low = ranges[i].low; 1904*e4b17023SJohn Marino tree high = ranges[i].high; 1905*e4b17023SJohn Marino int in_p = ranges[i].in_p; 1906*e4b17023SJohn Marino bool strict_overflow_p = ranges[i].strict_overflow_p; 1907*e4b17023SJohn Marino int update_fail_count = 0; 1908*e4b17023SJohn Marino 1909*e4b17023SJohn Marino for (j = i + 1; j < length; j++) 1910*e4b17023SJohn Marino { 1911*e4b17023SJohn Marino if (ranges[i].exp != ranges[j].exp) 1912*e4b17023SJohn Marino break; 1913*e4b17023SJohn Marino if (!merge_ranges (&in_p, &low, &high, in_p, low, high, 1914*e4b17023SJohn Marino ranges[j].in_p, ranges[j].low, ranges[j].high)) 1915*e4b17023SJohn Marino break; 1916*e4b17023SJohn Marino strict_overflow_p |= ranges[j].strict_overflow_p; 1917*e4b17023SJohn Marino } 1918*e4b17023SJohn Marino 1919*e4b17023SJohn Marino if (j == i + 1) 1920*e4b17023SJohn Marino continue; 1921*e4b17023SJohn Marino 1922*e4b17023SJohn Marino if (update_range_test (ranges + i, ranges + i + 1, j - i - 1, opcode, 1923*e4b17023SJohn Marino ops, ranges[i].exp, in_p, low, high, 1924*e4b17023SJohn Marino strict_overflow_p)) 1925*e4b17023SJohn Marino { 1926*e4b17023SJohn Marino i = j - 1; 1927*e4b17023SJohn Marino any_changes = true; 1928*e4b17023SJohn Marino } 1929*e4b17023SJohn Marino /* Avoid quadratic complexity if all merge_ranges calls would succeed, 1930*e4b17023SJohn Marino while update_range_test would fail. */ 1931*e4b17023SJohn Marino else if (update_fail_count == 64) 1932*e4b17023SJohn Marino i = j - 1; 1933*e4b17023SJohn Marino else 1934*e4b17023SJohn Marino ++update_fail_count; 1935*e4b17023SJohn Marino } 1936*e4b17023SJohn Marino 1937*e4b17023SJohn Marino /* Optimize X == CST1 || X == CST2 1938*e4b17023SJohn Marino if popcount (CST1 ^ CST2) == 1 into 1939*e4b17023SJohn Marino (X & ~(CST1 ^ CST2)) == (CST1 & ~(CST1 ^ CST2)). 1940*e4b17023SJohn Marino Similarly for ranges. E.g. 1941*e4b17023SJohn Marino X != 2 && X != 3 && X != 10 && X != 11 1942*e4b17023SJohn Marino will be transformed by the above loop into 1943*e4b17023SJohn Marino (X - 2U) <= 1U && (X - 10U) <= 1U 1944*e4b17023SJohn Marino and this loop can transform that into 1945*e4b17023SJohn Marino ((X & ~8) - 2U) <= 1U. */ 1946*e4b17023SJohn Marino for (i = first; i < length; i++) 1947*e4b17023SJohn Marino { 1948*e4b17023SJohn Marino tree lowi, highi, lowj, highj, type, lowxor, highxor, tem, exp; 1949*e4b17023SJohn Marino 1950*e4b17023SJohn Marino if (ranges[i].exp == NULL_TREE || ranges[i].in_p) 1951*e4b17023SJohn Marino continue; 1952*e4b17023SJohn Marino type = TREE_TYPE (ranges[i].exp); 1953*e4b17023SJohn Marino if (!INTEGRAL_TYPE_P (type)) 1954*e4b17023SJohn Marino continue; 1955*e4b17023SJohn Marino lowi = ranges[i].low; 1956*e4b17023SJohn Marino if (lowi == NULL_TREE) 1957*e4b17023SJohn Marino lowi = TYPE_MIN_VALUE (type); 1958*e4b17023SJohn Marino highi = ranges[i].high; 1959*e4b17023SJohn Marino if (highi == NULL_TREE) 1960*e4b17023SJohn Marino continue; 1961*e4b17023SJohn Marino for (j = i + 1; j < length && j < i + 64; j++) 1962*e4b17023SJohn Marino { 1963*e4b17023SJohn Marino if (ranges[j].exp == NULL_TREE) 1964*e4b17023SJohn Marino continue; 1965*e4b17023SJohn Marino if (ranges[i].exp != ranges[j].exp) 1966*e4b17023SJohn Marino break; 1967*e4b17023SJohn Marino if (ranges[j].in_p) 1968*e4b17023SJohn Marino continue; 1969*e4b17023SJohn Marino lowj = ranges[j].low; 1970*e4b17023SJohn Marino if (lowj == NULL_TREE) 1971*e4b17023SJohn Marino continue; 1972*e4b17023SJohn Marino highj = ranges[j].high; 1973*e4b17023SJohn Marino if (highj == NULL_TREE) 1974*e4b17023SJohn Marino highj = TYPE_MAX_VALUE (type); 1975*e4b17023SJohn Marino tem = fold_binary (GT_EXPR, boolean_type_node, 1976*e4b17023SJohn Marino lowj, highi); 1977*e4b17023SJohn Marino if (tem == NULL_TREE || !integer_onep (tem)) 1978*e4b17023SJohn Marino continue; 1979*e4b17023SJohn Marino lowxor = fold_binary (BIT_XOR_EXPR, type, lowi, lowj); 1980*e4b17023SJohn Marino if (lowxor == NULL_TREE || TREE_CODE (lowxor) != INTEGER_CST) 1981*e4b17023SJohn Marino continue; 1982*e4b17023SJohn Marino gcc_checking_assert (!integer_zerop (lowxor)); 1983*e4b17023SJohn Marino tem = fold_binary (MINUS_EXPR, type, lowxor, 1984*e4b17023SJohn Marino build_int_cst (type, 1)); 1985*e4b17023SJohn Marino if (tem == NULL_TREE) 1986*e4b17023SJohn Marino continue; 1987*e4b17023SJohn Marino tem = fold_binary (BIT_AND_EXPR, type, lowxor, tem); 1988*e4b17023SJohn Marino if (tem == NULL_TREE || !integer_zerop (tem)) 1989*e4b17023SJohn Marino continue; 1990*e4b17023SJohn Marino highxor = fold_binary (BIT_XOR_EXPR, type, highi, highj); 1991*e4b17023SJohn Marino if (!tree_int_cst_equal (lowxor, highxor)) 1992*e4b17023SJohn Marino continue; 1993*e4b17023SJohn Marino tem = fold_build1 (BIT_NOT_EXPR, type, lowxor); 1994*e4b17023SJohn Marino exp = fold_build2 (BIT_AND_EXPR, type, ranges[i].exp, tem); 1995*e4b17023SJohn Marino lowj = fold_build2 (BIT_AND_EXPR, type, lowi, tem); 1996*e4b17023SJohn Marino highj = fold_build2 (BIT_AND_EXPR, type, highi, tem); 1997*e4b17023SJohn Marino if (update_range_test (ranges + i, ranges + j, 1, opcode, ops, exp, 1998*e4b17023SJohn Marino ranges[i].in_p, lowj, highj, 1999*e4b17023SJohn Marino ranges[i].strict_overflow_p 2000*e4b17023SJohn Marino || ranges[j].strict_overflow_p)) 2001*e4b17023SJohn Marino { 2002*e4b17023SJohn Marino any_changes = true; 2003*e4b17023SJohn Marino break; 2004*e4b17023SJohn Marino } 2005*e4b17023SJohn Marino } 2006*e4b17023SJohn Marino } 2007*e4b17023SJohn Marino 2008*e4b17023SJohn Marino if (any_changes) 2009*e4b17023SJohn Marino { 2010*e4b17023SJohn Marino j = 0; 2011*e4b17023SJohn Marino FOR_EACH_VEC_ELT (operand_entry_t, *ops, i, oe) 2012*e4b17023SJohn Marino { 2013*e4b17023SJohn Marino if (oe->op == error_mark_node) 2014*e4b17023SJohn Marino continue; 2015*e4b17023SJohn Marino else if (i != j) 2016*e4b17023SJohn Marino VEC_replace (operand_entry_t, *ops, j, oe); 2017*e4b17023SJohn Marino j++; 2018*e4b17023SJohn Marino } 2019*e4b17023SJohn Marino VEC_truncate (operand_entry_t, *ops, j); 2020*e4b17023SJohn Marino } 2021*e4b17023SJohn Marino 2022*e4b17023SJohn Marino XDELETEVEC (ranges); 2023*e4b17023SJohn Marino } 2024*e4b17023SJohn Marino 2025*e4b17023SJohn Marino /* Return true if OPERAND is defined by a PHI node which uses the LHS 2026*e4b17023SJohn Marino of STMT in it's operands. This is also known as a "destructive 2027*e4b17023SJohn Marino update" operation. */ 2028*e4b17023SJohn Marino 2029*e4b17023SJohn Marino static bool 2030*e4b17023SJohn Marino is_phi_for_stmt (gimple stmt, tree operand) 2031*e4b17023SJohn Marino { 2032*e4b17023SJohn Marino gimple def_stmt; 2033*e4b17023SJohn Marino tree lhs; 2034*e4b17023SJohn Marino use_operand_p arg_p; 2035*e4b17023SJohn Marino ssa_op_iter i; 2036*e4b17023SJohn Marino 2037*e4b17023SJohn Marino if (TREE_CODE (operand) != SSA_NAME) 2038*e4b17023SJohn Marino return false; 2039*e4b17023SJohn Marino 2040*e4b17023SJohn Marino lhs = gimple_assign_lhs (stmt); 2041*e4b17023SJohn Marino 2042*e4b17023SJohn Marino def_stmt = SSA_NAME_DEF_STMT (operand); 2043*e4b17023SJohn Marino if (gimple_code (def_stmt) != GIMPLE_PHI) 2044*e4b17023SJohn Marino return false; 2045*e4b17023SJohn Marino 2046*e4b17023SJohn Marino FOR_EACH_PHI_ARG (arg_p, def_stmt, i, SSA_OP_USE) 2047*e4b17023SJohn Marino if (lhs == USE_FROM_PTR (arg_p)) 2048*e4b17023SJohn Marino return true; 2049*e4b17023SJohn Marino return false; 2050*e4b17023SJohn Marino } 2051*e4b17023SJohn Marino 2052*e4b17023SJohn Marino /* Remove def stmt of VAR if VAR has zero uses and recurse 2053*e4b17023SJohn Marino on rhs1 operand if so. */ 2054*e4b17023SJohn Marino 2055*e4b17023SJohn Marino static void 2056*e4b17023SJohn Marino remove_visited_stmt_chain (tree var) 2057*e4b17023SJohn Marino { 2058*e4b17023SJohn Marino gimple stmt; 2059*e4b17023SJohn Marino gimple_stmt_iterator gsi; 2060*e4b17023SJohn Marino 2061*e4b17023SJohn Marino while (1) 2062*e4b17023SJohn Marino { 2063*e4b17023SJohn Marino if (TREE_CODE (var) != SSA_NAME || !has_zero_uses (var)) 2064*e4b17023SJohn Marino return; 2065*e4b17023SJohn Marino stmt = SSA_NAME_DEF_STMT (var); 2066*e4b17023SJohn Marino if (!is_gimple_assign (stmt) 2067*e4b17023SJohn Marino || !gimple_visited_p (stmt)) 2068*e4b17023SJohn Marino return; 2069*e4b17023SJohn Marino var = gimple_assign_rhs1 (stmt); 2070*e4b17023SJohn Marino gsi = gsi_for_stmt (stmt); 2071*e4b17023SJohn Marino gsi_remove (&gsi, true); 2072*e4b17023SJohn Marino release_defs (stmt); 2073*e4b17023SJohn Marino } 2074*e4b17023SJohn Marino } 2075*e4b17023SJohn Marino 2076*e4b17023SJohn Marino /* This function checks three consequtive operands in 2077*e4b17023SJohn Marino passed operands vector OPS starting from OPINDEX and 2078*e4b17023SJohn Marino swaps two operands if it is profitable for binary operation 2079*e4b17023SJohn Marino consuming OPINDEX + 1 abnd OPINDEX + 2 operands. 2080*e4b17023SJohn Marino 2081*e4b17023SJohn Marino We pair ops with the same rank if possible. 2082*e4b17023SJohn Marino 2083*e4b17023SJohn Marino The alternative we try is to see if STMT is a destructive 2084*e4b17023SJohn Marino update style statement, which is like: 2085*e4b17023SJohn Marino b = phi (a, ...) 2086*e4b17023SJohn Marino a = c + b; 2087*e4b17023SJohn Marino In that case, we want to use the destructive update form to 2088*e4b17023SJohn Marino expose the possible vectorizer sum reduction opportunity. 2089*e4b17023SJohn Marino In that case, the third operand will be the phi node. This 2090*e4b17023SJohn Marino check is not performed if STMT is null. 2091*e4b17023SJohn Marino 2092*e4b17023SJohn Marino We could, of course, try to be better as noted above, and do a 2093*e4b17023SJohn Marino lot of work to try to find these opportunities in >3 operand 2094*e4b17023SJohn Marino cases, but it is unlikely to be worth it. */ 2095*e4b17023SJohn Marino 2096*e4b17023SJohn Marino static void 2097*e4b17023SJohn Marino swap_ops_for_binary_stmt (VEC(operand_entry_t, heap) * ops, 2098*e4b17023SJohn Marino unsigned int opindex, gimple stmt) 2099*e4b17023SJohn Marino { 2100*e4b17023SJohn Marino operand_entry_t oe1, oe2, oe3; 2101*e4b17023SJohn Marino 2102*e4b17023SJohn Marino oe1 = VEC_index (operand_entry_t, ops, opindex); 2103*e4b17023SJohn Marino oe2 = VEC_index (operand_entry_t, ops, opindex + 1); 2104*e4b17023SJohn Marino oe3 = VEC_index (operand_entry_t, ops, opindex + 2); 2105*e4b17023SJohn Marino 2106*e4b17023SJohn Marino if ((oe1->rank == oe2->rank 2107*e4b17023SJohn Marino && oe2->rank != oe3->rank) 2108*e4b17023SJohn Marino || (stmt && is_phi_for_stmt (stmt, oe3->op) 2109*e4b17023SJohn Marino && !is_phi_for_stmt (stmt, oe1->op) 2110*e4b17023SJohn Marino && !is_phi_for_stmt (stmt, oe2->op))) 2111*e4b17023SJohn Marino { 2112*e4b17023SJohn Marino struct operand_entry temp = *oe3; 2113*e4b17023SJohn Marino oe3->op = oe1->op; 2114*e4b17023SJohn Marino oe3->rank = oe1->rank; 2115*e4b17023SJohn Marino oe1->op = temp.op; 2116*e4b17023SJohn Marino oe1->rank= temp.rank; 2117*e4b17023SJohn Marino } 2118*e4b17023SJohn Marino else if ((oe1->rank == oe3->rank 2119*e4b17023SJohn Marino && oe2->rank != oe3->rank) 2120*e4b17023SJohn Marino || (stmt && is_phi_for_stmt (stmt, oe2->op) 2121*e4b17023SJohn Marino && !is_phi_for_stmt (stmt, oe1->op) 2122*e4b17023SJohn Marino && !is_phi_for_stmt (stmt, oe3->op))) 2123*e4b17023SJohn Marino { 2124*e4b17023SJohn Marino struct operand_entry temp = *oe2; 2125*e4b17023SJohn Marino oe2->op = oe1->op; 2126*e4b17023SJohn Marino oe2->rank = oe1->rank; 2127*e4b17023SJohn Marino oe1->op = temp.op; 2128*e4b17023SJohn Marino oe1->rank= temp.rank; 2129*e4b17023SJohn Marino } 2130*e4b17023SJohn Marino } 2131*e4b17023SJohn Marino 2132*e4b17023SJohn Marino /* Recursively rewrite our linearized statements so that the operators 2133*e4b17023SJohn Marino match those in OPS[OPINDEX], putting the computation in rank 2134*e4b17023SJohn Marino order. */ 2135*e4b17023SJohn Marino 2136*e4b17023SJohn Marino static void 2137*e4b17023SJohn Marino rewrite_expr_tree (gimple stmt, unsigned int opindex, 2138*e4b17023SJohn Marino VEC(operand_entry_t, heap) * ops, bool moved) 2139*e4b17023SJohn Marino { 2140*e4b17023SJohn Marino tree rhs1 = gimple_assign_rhs1 (stmt); 2141*e4b17023SJohn Marino tree rhs2 = gimple_assign_rhs2 (stmt); 2142*e4b17023SJohn Marino operand_entry_t oe; 2143*e4b17023SJohn Marino 2144*e4b17023SJohn Marino /* If we have three operands left, then we want to make sure the ones 2145*e4b17023SJohn Marino that get the double binary op are chosen wisely. */ 2146*e4b17023SJohn Marino if (opindex + 3 == VEC_length (operand_entry_t, ops)) 2147*e4b17023SJohn Marino swap_ops_for_binary_stmt (ops, opindex, stmt); 2148*e4b17023SJohn Marino 2149*e4b17023SJohn Marino /* The final recursion case for this function is that you have 2150*e4b17023SJohn Marino exactly two operations left. 2151*e4b17023SJohn Marino If we had one exactly one op in the entire list to start with, we 2152*e4b17023SJohn Marino would have never called this function, and the tail recursion 2153*e4b17023SJohn Marino rewrites them one at a time. */ 2154*e4b17023SJohn Marino if (opindex + 2 == VEC_length (operand_entry_t, ops)) 2155*e4b17023SJohn Marino { 2156*e4b17023SJohn Marino operand_entry_t oe1, oe2; 2157*e4b17023SJohn Marino 2158*e4b17023SJohn Marino oe1 = VEC_index (operand_entry_t, ops, opindex); 2159*e4b17023SJohn Marino oe2 = VEC_index (operand_entry_t, ops, opindex + 1); 2160*e4b17023SJohn Marino 2161*e4b17023SJohn Marino if (rhs1 != oe1->op || rhs2 != oe2->op) 2162*e4b17023SJohn Marino { 2163*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2164*e4b17023SJohn Marino { 2165*e4b17023SJohn Marino fprintf (dump_file, "Transforming "); 2166*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2167*e4b17023SJohn Marino } 2168*e4b17023SJohn Marino 2169*e4b17023SJohn Marino gimple_assign_set_rhs1 (stmt, oe1->op); 2170*e4b17023SJohn Marino gimple_assign_set_rhs2 (stmt, oe2->op); 2171*e4b17023SJohn Marino update_stmt (stmt); 2172*e4b17023SJohn Marino if (rhs1 != oe1->op && rhs1 != oe2->op) 2173*e4b17023SJohn Marino remove_visited_stmt_chain (rhs1); 2174*e4b17023SJohn Marino 2175*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2176*e4b17023SJohn Marino { 2177*e4b17023SJohn Marino fprintf (dump_file, " into "); 2178*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2179*e4b17023SJohn Marino } 2180*e4b17023SJohn Marino 2181*e4b17023SJohn Marino } 2182*e4b17023SJohn Marino return; 2183*e4b17023SJohn Marino } 2184*e4b17023SJohn Marino 2185*e4b17023SJohn Marino /* If we hit here, we should have 3 or more ops left. */ 2186*e4b17023SJohn Marino gcc_assert (opindex + 2 < VEC_length (operand_entry_t, ops)); 2187*e4b17023SJohn Marino 2188*e4b17023SJohn Marino /* Rewrite the next operator. */ 2189*e4b17023SJohn Marino oe = VEC_index (operand_entry_t, ops, opindex); 2190*e4b17023SJohn Marino 2191*e4b17023SJohn Marino if (oe->op != rhs2) 2192*e4b17023SJohn Marino { 2193*e4b17023SJohn Marino if (!moved) 2194*e4b17023SJohn Marino { 2195*e4b17023SJohn Marino gimple_stmt_iterator gsinow, gsirhs1; 2196*e4b17023SJohn Marino gimple stmt1 = stmt, stmt2; 2197*e4b17023SJohn Marino unsigned int count; 2198*e4b17023SJohn Marino 2199*e4b17023SJohn Marino gsinow = gsi_for_stmt (stmt); 2200*e4b17023SJohn Marino count = VEC_length (operand_entry_t, ops) - opindex - 2; 2201*e4b17023SJohn Marino while (count-- != 0) 2202*e4b17023SJohn Marino { 2203*e4b17023SJohn Marino stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt1)); 2204*e4b17023SJohn Marino gsirhs1 = gsi_for_stmt (stmt2); 2205*e4b17023SJohn Marino gsi_move_before (&gsirhs1, &gsinow); 2206*e4b17023SJohn Marino gsi_prev (&gsinow); 2207*e4b17023SJohn Marino stmt1 = stmt2; 2208*e4b17023SJohn Marino } 2209*e4b17023SJohn Marino moved = true; 2210*e4b17023SJohn Marino } 2211*e4b17023SJohn Marino 2212*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2213*e4b17023SJohn Marino { 2214*e4b17023SJohn Marino fprintf (dump_file, "Transforming "); 2215*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2216*e4b17023SJohn Marino } 2217*e4b17023SJohn Marino 2218*e4b17023SJohn Marino gimple_assign_set_rhs2 (stmt, oe->op); 2219*e4b17023SJohn Marino update_stmt (stmt); 2220*e4b17023SJohn Marino 2221*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2222*e4b17023SJohn Marino { 2223*e4b17023SJohn Marino fprintf (dump_file, " into "); 2224*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2225*e4b17023SJohn Marino } 2226*e4b17023SJohn Marino } 2227*e4b17023SJohn Marino /* Recurse on the LHS of the binary operator, which is guaranteed to 2228*e4b17023SJohn Marino be the non-leaf side. */ 2229*e4b17023SJohn Marino rewrite_expr_tree (SSA_NAME_DEF_STMT (rhs1), opindex + 1, ops, moved); 2230*e4b17023SJohn Marino } 2231*e4b17023SJohn Marino 2232*e4b17023SJohn Marino /* Find out how many cycles we need to compute statements chain. 2233*e4b17023SJohn Marino OPS_NUM holds number os statements in a chain. CPU_WIDTH is a 2234*e4b17023SJohn Marino maximum number of independent statements we may execute per cycle. */ 2235*e4b17023SJohn Marino 2236*e4b17023SJohn Marino static int 2237*e4b17023SJohn Marino get_required_cycles (int ops_num, int cpu_width) 2238*e4b17023SJohn Marino { 2239*e4b17023SJohn Marino int res; 2240*e4b17023SJohn Marino int elog; 2241*e4b17023SJohn Marino unsigned int rest; 2242*e4b17023SJohn Marino 2243*e4b17023SJohn Marino /* While we have more than 2 * cpu_width operands 2244*e4b17023SJohn Marino we may reduce number of operands by cpu_width 2245*e4b17023SJohn Marino per cycle. */ 2246*e4b17023SJohn Marino res = ops_num / (2 * cpu_width); 2247*e4b17023SJohn Marino 2248*e4b17023SJohn Marino /* Remained operands count may be reduced twice per cycle 2249*e4b17023SJohn Marino until we have only one operand. */ 2250*e4b17023SJohn Marino rest = (unsigned)(ops_num - res * cpu_width); 2251*e4b17023SJohn Marino elog = exact_log2 (rest); 2252*e4b17023SJohn Marino if (elog >= 0) 2253*e4b17023SJohn Marino res += elog; 2254*e4b17023SJohn Marino else 2255*e4b17023SJohn Marino res += floor_log2 (rest) + 1; 2256*e4b17023SJohn Marino 2257*e4b17023SJohn Marino return res; 2258*e4b17023SJohn Marino } 2259*e4b17023SJohn Marino 2260*e4b17023SJohn Marino /* Returns an optimal number of registers to use for computation of 2261*e4b17023SJohn Marino given statements. */ 2262*e4b17023SJohn Marino 2263*e4b17023SJohn Marino static int 2264*e4b17023SJohn Marino get_reassociation_width (int ops_num, enum tree_code opc, 2265*e4b17023SJohn Marino enum machine_mode mode) 2266*e4b17023SJohn Marino { 2267*e4b17023SJohn Marino int param_width = PARAM_VALUE (PARAM_TREE_REASSOC_WIDTH); 2268*e4b17023SJohn Marino int width; 2269*e4b17023SJohn Marino int width_min; 2270*e4b17023SJohn Marino int cycles_best; 2271*e4b17023SJohn Marino 2272*e4b17023SJohn Marino if (param_width > 0) 2273*e4b17023SJohn Marino width = param_width; 2274*e4b17023SJohn Marino else 2275*e4b17023SJohn Marino width = targetm.sched.reassociation_width (opc, mode); 2276*e4b17023SJohn Marino 2277*e4b17023SJohn Marino if (width == 1) 2278*e4b17023SJohn Marino return width; 2279*e4b17023SJohn Marino 2280*e4b17023SJohn Marino /* Get the minimal time required for sequence computation. */ 2281*e4b17023SJohn Marino cycles_best = get_required_cycles (ops_num, width); 2282*e4b17023SJohn Marino 2283*e4b17023SJohn Marino /* Check if we may use less width and still compute sequence for 2284*e4b17023SJohn Marino the same time. It will allow us to reduce registers usage. 2285*e4b17023SJohn Marino get_required_cycles is monotonically increasing with lower width 2286*e4b17023SJohn Marino so we can perform a binary search for the minimal width that still 2287*e4b17023SJohn Marino results in the optimal cycle count. */ 2288*e4b17023SJohn Marino width_min = 1; 2289*e4b17023SJohn Marino while (width > width_min) 2290*e4b17023SJohn Marino { 2291*e4b17023SJohn Marino int width_mid = (width + width_min) / 2; 2292*e4b17023SJohn Marino 2293*e4b17023SJohn Marino if (get_required_cycles (ops_num, width_mid) == cycles_best) 2294*e4b17023SJohn Marino width = width_mid; 2295*e4b17023SJohn Marino else if (width_min < width_mid) 2296*e4b17023SJohn Marino width_min = width_mid; 2297*e4b17023SJohn Marino else 2298*e4b17023SJohn Marino break; 2299*e4b17023SJohn Marino } 2300*e4b17023SJohn Marino 2301*e4b17023SJohn Marino return width; 2302*e4b17023SJohn Marino } 2303*e4b17023SJohn Marino 2304*e4b17023SJohn Marino /* Recursively rewrite our linearized statements so that the operators 2305*e4b17023SJohn Marino match those in OPS[OPINDEX], putting the computation in rank 2306*e4b17023SJohn Marino order and trying to allow operations to be executed in 2307*e4b17023SJohn Marino parallel. */ 2308*e4b17023SJohn Marino 2309*e4b17023SJohn Marino static void 2310*e4b17023SJohn Marino rewrite_expr_tree_parallel (gimple stmt, int width, 2311*e4b17023SJohn Marino VEC(operand_entry_t, heap) * ops) 2312*e4b17023SJohn Marino { 2313*e4b17023SJohn Marino enum tree_code opcode = gimple_assign_rhs_code (stmt); 2314*e4b17023SJohn Marino int op_num = VEC_length (operand_entry_t, ops); 2315*e4b17023SJohn Marino int stmt_num = op_num - 1; 2316*e4b17023SJohn Marino gimple *stmts = XALLOCAVEC (gimple, stmt_num); 2317*e4b17023SJohn Marino int op_index = op_num - 1; 2318*e4b17023SJohn Marino int stmt_index = 0; 2319*e4b17023SJohn Marino int ready_stmts_end = 0; 2320*e4b17023SJohn Marino int i = 0; 2321*e4b17023SJohn Marino tree last_rhs1 = gimple_assign_rhs1 (stmt); 2322*e4b17023SJohn Marino tree lhs_var; 2323*e4b17023SJohn Marino 2324*e4b17023SJohn Marino /* We start expression rewriting from the top statements. 2325*e4b17023SJohn Marino So, in this loop we create a full list of statements 2326*e4b17023SJohn Marino we will work with. */ 2327*e4b17023SJohn Marino stmts[stmt_num - 1] = stmt; 2328*e4b17023SJohn Marino for (i = stmt_num - 2; i >= 0; i--) 2329*e4b17023SJohn Marino stmts[i] = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmts[i+1])); 2330*e4b17023SJohn Marino 2331*e4b17023SJohn Marino lhs_var = create_tmp_reg (TREE_TYPE (last_rhs1), NULL); 2332*e4b17023SJohn Marino add_referenced_var (lhs_var); 2333*e4b17023SJohn Marino 2334*e4b17023SJohn Marino for (i = 0; i < stmt_num; i++) 2335*e4b17023SJohn Marino { 2336*e4b17023SJohn Marino tree op1, op2; 2337*e4b17023SJohn Marino 2338*e4b17023SJohn Marino /* Determine whether we should use results of 2339*e4b17023SJohn Marino already handled statements or not. */ 2340*e4b17023SJohn Marino if (ready_stmts_end == 0 2341*e4b17023SJohn Marino && (i - stmt_index >= width || op_index < 1)) 2342*e4b17023SJohn Marino ready_stmts_end = i; 2343*e4b17023SJohn Marino 2344*e4b17023SJohn Marino /* Now we choose operands for the next statement. Non zero 2345*e4b17023SJohn Marino value in ready_stmts_end means here that we should use 2346*e4b17023SJohn Marino the result of already generated statements as new operand. */ 2347*e4b17023SJohn Marino if (ready_stmts_end > 0) 2348*e4b17023SJohn Marino { 2349*e4b17023SJohn Marino op1 = gimple_assign_lhs (stmts[stmt_index++]); 2350*e4b17023SJohn Marino if (ready_stmts_end > stmt_index) 2351*e4b17023SJohn Marino op2 = gimple_assign_lhs (stmts[stmt_index++]); 2352*e4b17023SJohn Marino else if (op_index >= 0) 2353*e4b17023SJohn Marino op2 = VEC_index (operand_entry_t, ops, op_index--)->op; 2354*e4b17023SJohn Marino else 2355*e4b17023SJohn Marino { 2356*e4b17023SJohn Marino gcc_assert (stmt_index < i); 2357*e4b17023SJohn Marino op2 = gimple_assign_lhs (stmts[stmt_index++]); 2358*e4b17023SJohn Marino } 2359*e4b17023SJohn Marino 2360*e4b17023SJohn Marino if (stmt_index >= ready_stmts_end) 2361*e4b17023SJohn Marino ready_stmts_end = 0; 2362*e4b17023SJohn Marino } 2363*e4b17023SJohn Marino else 2364*e4b17023SJohn Marino { 2365*e4b17023SJohn Marino if (op_index > 1) 2366*e4b17023SJohn Marino swap_ops_for_binary_stmt (ops, op_index - 2, NULL); 2367*e4b17023SJohn Marino op2 = VEC_index (operand_entry_t, ops, op_index--)->op; 2368*e4b17023SJohn Marino op1 = VEC_index (operand_entry_t, ops, op_index--)->op; 2369*e4b17023SJohn Marino } 2370*e4b17023SJohn Marino 2371*e4b17023SJohn Marino /* If we emit the last statement then we should put 2372*e4b17023SJohn Marino operands into the last statement. It will also 2373*e4b17023SJohn Marino break the loop. */ 2374*e4b17023SJohn Marino if (op_index < 0 && stmt_index == i) 2375*e4b17023SJohn Marino i = stmt_num - 1; 2376*e4b17023SJohn Marino 2377*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2378*e4b17023SJohn Marino { 2379*e4b17023SJohn Marino fprintf (dump_file, "Transforming "); 2380*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmts[i], 0, 0); 2381*e4b17023SJohn Marino } 2382*e4b17023SJohn Marino 2383*e4b17023SJohn Marino /* We keep original statement only for the last one. All 2384*e4b17023SJohn Marino others are recreated. */ 2385*e4b17023SJohn Marino if (i == stmt_num - 1) 2386*e4b17023SJohn Marino { 2387*e4b17023SJohn Marino gimple_assign_set_rhs1 (stmts[i], op1); 2388*e4b17023SJohn Marino gimple_assign_set_rhs2 (stmts[i], op2); 2389*e4b17023SJohn Marino update_stmt (stmts[i]); 2390*e4b17023SJohn Marino } 2391*e4b17023SJohn Marino else 2392*e4b17023SJohn Marino stmts[i] = build_and_add_sum (lhs_var, op1, op2, opcode); 2393*e4b17023SJohn Marino 2394*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2395*e4b17023SJohn Marino { 2396*e4b17023SJohn Marino fprintf (dump_file, " into "); 2397*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmts[i], 0, 0); 2398*e4b17023SJohn Marino } 2399*e4b17023SJohn Marino } 2400*e4b17023SJohn Marino 2401*e4b17023SJohn Marino remove_visited_stmt_chain (last_rhs1); 2402*e4b17023SJohn Marino } 2403*e4b17023SJohn Marino 2404*e4b17023SJohn Marino /* Transform STMT, which is really (A +B) + (C + D) into the left 2405*e4b17023SJohn Marino linear form, ((A+B)+C)+D. 2406*e4b17023SJohn Marino Recurse on D if necessary. */ 2407*e4b17023SJohn Marino 2408*e4b17023SJohn Marino static void 2409*e4b17023SJohn Marino linearize_expr (gimple stmt) 2410*e4b17023SJohn Marino { 2411*e4b17023SJohn Marino gimple_stmt_iterator gsinow, gsirhs; 2412*e4b17023SJohn Marino gimple binlhs = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)); 2413*e4b17023SJohn Marino gimple binrhs = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt)); 2414*e4b17023SJohn Marino enum tree_code rhscode = gimple_assign_rhs_code (stmt); 2415*e4b17023SJohn Marino gimple newbinrhs = NULL; 2416*e4b17023SJohn Marino struct loop *loop = loop_containing_stmt (stmt); 2417*e4b17023SJohn Marino 2418*e4b17023SJohn Marino gcc_assert (is_reassociable_op (binlhs, rhscode, loop) 2419*e4b17023SJohn Marino && is_reassociable_op (binrhs, rhscode, loop)); 2420*e4b17023SJohn Marino 2421*e4b17023SJohn Marino gsinow = gsi_for_stmt (stmt); 2422*e4b17023SJohn Marino gsirhs = gsi_for_stmt (binrhs); 2423*e4b17023SJohn Marino gsi_move_before (&gsirhs, &gsinow); 2424*e4b17023SJohn Marino 2425*e4b17023SJohn Marino gimple_assign_set_rhs2 (stmt, gimple_assign_rhs1 (binrhs)); 2426*e4b17023SJohn Marino gimple_assign_set_rhs1 (binrhs, gimple_assign_lhs (binlhs)); 2427*e4b17023SJohn Marino gimple_assign_set_rhs1 (stmt, gimple_assign_lhs (binrhs)); 2428*e4b17023SJohn Marino 2429*e4b17023SJohn Marino if (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME) 2430*e4b17023SJohn Marino newbinrhs = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt)); 2431*e4b17023SJohn Marino 2432*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2433*e4b17023SJohn Marino { 2434*e4b17023SJohn Marino fprintf (dump_file, "Linearized: "); 2435*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2436*e4b17023SJohn Marino } 2437*e4b17023SJohn Marino 2438*e4b17023SJohn Marino reassociate_stats.linearized++; 2439*e4b17023SJohn Marino update_stmt (binrhs); 2440*e4b17023SJohn Marino update_stmt (binlhs); 2441*e4b17023SJohn Marino update_stmt (stmt); 2442*e4b17023SJohn Marino 2443*e4b17023SJohn Marino gimple_set_visited (stmt, true); 2444*e4b17023SJohn Marino gimple_set_visited (binlhs, true); 2445*e4b17023SJohn Marino gimple_set_visited (binrhs, true); 2446*e4b17023SJohn Marino 2447*e4b17023SJohn Marino /* Tail recurse on the new rhs if it still needs reassociation. */ 2448*e4b17023SJohn Marino if (newbinrhs && is_reassociable_op (newbinrhs, rhscode, loop)) 2449*e4b17023SJohn Marino /* ??? This should probably be linearize_expr (newbinrhs) but I don't 2450*e4b17023SJohn Marino want to change the algorithm while converting to tuples. */ 2451*e4b17023SJohn Marino linearize_expr (stmt); 2452*e4b17023SJohn Marino } 2453*e4b17023SJohn Marino 2454*e4b17023SJohn Marino /* If LHS has a single immediate use that is a GIMPLE_ASSIGN statement, return 2455*e4b17023SJohn Marino it. Otherwise, return NULL. */ 2456*e4b17023SJohn Marino 2457*e4b17023SJohn Marino static gimple 2458*e4b17023SJohn Marino get_single_immediate_use (tree lhs) 2459*e4b17023SJohn Marino { 2460*e4b17023SJohn Marino use_operand_p immuse; 2461*e4b17023SJohn Marino gimple immusestmt; 2462*e4b17023SJohn Marino 2463*e4b17023SJohn Marino if (TREE_CODE (lhs) == SSA_NAME 2464*e4b17023SJohn Marino && single_imm_use (lhs, &immuse, &immusestmt) 2465*e4b17023SJohn Marino && is_gimple_assign (immusestmt)) 2466*e4b17023SJohn Marino return immusestmt; 2467*e4b17023SJohn Marino 2468*e4b17023SJohn Marino return NULL; 2469*e4b17023SJohn Marino } 2470*e4b17023SJohn Marino 2471*e4b17023SJohn Marino /* Recursively negate the value of TONEGATE, and return the SSA_NAME 2472*e4b17023SJohn Marino representing the negated value. Insertions of any necessary 2473*e4b17023SJohn Marino instructions go before GSI. 2474*e4b17023SJohn Marino This function is recursive in that, if you hand it "a_5" as the 2475*e4b17023SJohn Marino value to negate, and a_5 is defined by "a_5 = b_3 + b_4", it will 2476*e4b17023SJohn Marino transform b_3 + b_4 into a_5 = -b_3 + -b_4. */ 2477*e4b17023SJohn Marino 2478*e4b17023SJohn Marino static tree 2479*e4b17023SJohn Marino negate_value (tree tonegate, gimple_stmt_iterator *gsi) 2480*e4b17023SJohn Marino { 2481*e4b17023SJohn Marino gimple negatedefstmt= NULL; 2482*e4b17023SJohn Marino tree resultofnegate; 2483*e4b17023SJohn Marino 2484*e4b17023SJohn Marino /* If we are trying to negate a name, defined by an add, negate the 2485*e4b17023SJohn Marino add operands instead. */ 2486*e4b17023SJohn Marino if (TREE_CODE (tonegate) == SSA_NAME) 2487*e4b17023SJohn Marino negatedefstmt = SSA_NAME_DEF_STMT (tonegate); 2488*e4b17023SJohn Marino if (TREE_CODE (tonegate) == SSA_NAME 2489*e4b17023SJohn Marino && is_gimple_assign (negatedefstmt) 2490*e4b17023SJohn Marino && TREE_CODE (gimple_assign_lhs (negatedefstmt)) == SSA_NAME 2491*e4b17023SJohn Marino && has_single_use (gimple_assign_lhs (negatedefstmt)) 2492*e4b17023SJohn Marino && gimple_assign_rhs_code (negatedefstmt) == PLUS_EXPR) 2493*e4b17023SJohn Marino { 2494*e4b17023SJohn Marino gimple_stmt_iterator gsi; 2495*e4b17023SJohn Marino tree rhs1 = gimple_assign_rhs1 (negatedefstmt); 2496*e4b17023SJohn Marino tree rhs2 = gimple_assign_rhs2 (negatedefstmt); 2497*e4b17023SJohn Marino 2498*e4b17023SJohn Marino gsi = gsi_for_stmt (negatedefstmt); 2499*e4b17023SJohn Marino rhs1 = negate_value (rhs1, &gsi); 2500*e4b17023SJohn Marino gimple_assign_set_rhs1 (negatedefstmt, rhs1); 2501*e4b17023SJohn Marino 2502*e4b17023SJohn Marino gsi = gsi_for_stmt (negatedefstmt); 2503*e4b17023SJohn Marino rhs2 = negate_value (rhs2, &gsi); 2504*e4b17023SJohn Marino gimple_assign_set_rhs2 (negatedefstmt, rhs2); 2505*e4b17023SJohn Marino 2506*e4b17023SJohn Marino update_stmt (negatedefstmt); 2507*e4b17023SJohn Marino return gimple_assign_lhs (negatedefstmt); 2508*e4b17023SJohn Marino } 2509*e4b17023SJohn Marino 2510*e4b17023SJohn Marino tonegate = fold_build1 (NEGATE_EXPR, TREE_TYPE (tonegate), tonegate); 2511*e4b17023SJohn Marino resultofnegate = force_gimple_operand_gsi (gsi, tonegate, true, 2512*e4b17023SJohn Marino NULL_TREE, true, GSI_SAME_STMT); 2513*e4b17023SJohn Marino return resultofnegate; 2514*e4b17023SJohn Marino } 2515*e4b17023SJohn Marino 2516*e4b17023SJohn Marino /* Return true if we should break up the subtract in STMT into an add 2517*e4b17023SJohn Marino with negate. This is true when we the subtract operands are really 2518*e4b17023SJohn Marino adds, or the subtract itself is used in an add expression. In 2519*e4b17023SJohn Marino either case, breaking up the subtract into an add with negate 2520*e4b17023SJohn Marino exposes the adds to reassociation. */ 2521*e4b17023SJohn Marino 2522*e4b17023SJohn Marino static bool 2523*e4b17023SJohn Marino should_break_up_subtract (gimple stmt) 2524*e4b17023SJohn Marino { 2525*e4b17023SJohn Marino tree lhs = gimple_assign_lhs (stmt); 2526*e4b17023SJohn Marino tree binlhs = gimple_assign_rhs1 (stmt); 2527*e4b17023SJohn Marino tree binrhs = gimple_assign_rhs2 (stmt); 2528*e4b17023SJohn Marino gimple immusestmt; 2529*e4b17023SJohn Marino struct loop *loop = loop_containing_stmt (stmt); 2530*e4b17023SJohn Marino 2531*e4b17023SJohn Marino if (TREE_CODE (binlhs) == SSA_NAME 2532*e4b17023SJohn Marino && is_reassociable_op (SSA_NAME_DEF_STMT (binlhs), PLUS_EXPR, loop)) 2533*e4b17023SJohn Marino return true; 2534*e4b17023SJohn Marino 2535*e4b17023SJohn Marino if (TREE_CODE (binrhs) == SSA_NAME 2536*e4b17023SJohn Marino && is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), PLUS_EXPR, loop)) 2537*e4b17023SJohn Marino return true; 2538*e4b17023SJohn Marino 2539*e4b17023SJohn Marino if (TREE_CODE (lhs) == SSA_NAME 2540*e4b17023SJohn Marino && (immusestmt = get_single_immediate_use (lhs)) 2541*e4b17023SJohn Marino && is_gimple_assign (immusestmt) 2542*e4b17023SJohn Marino && (gimple_assign_rhs_code (immusestmt) == PLUS_EXPR 2543*e4b17023SJohn Marino || gimple_assign_rhs_code (immusestmt) == MULT_EXPR)) 2544*e4b17023SJohn Marino return true; 2545*e4b17023SJohn Marino return false; 2546*e4b17023SJohn Marino } 2547*e4b17023SJohn Marino 2548*e4b17023SJohn Marino /* Transform STMT from A - B into A + -B. */ 2549*e4b17023SJohn Marino 2550*e4b17023SJohn Marino static void 2551*e4b17023SJohn Marino break_up_subtract (gimple stmt, gimple_stmt_iterator *gsip) 2552*e4b17023SJohn Marino { 2553*e4b17023SJohn Marino tree rhs1 = gimple_assign_rhs1 (stmt); 2554*e4b17023SJohn Marino tree rhs2 = gimple_assign_rhs2 (stmt); 2555*e4b17023SJohn Marino 2556*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2557*e4b17023SJohn Marino { 2558*e4b17023SJohn Marino fprintf (dump_file, "Breaking up subtract "); 2559*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2560*e4b17023SJohn Marino } 2561*e4b17023SJohn Marino 2562*e4b17023SJohn Marino rhs2 = negate_value (rhs2, gsip); 2563*e4b17023SJohn Marino gimple_assign_set_rhs_with_ops (gsip, PLUS_EXPR, rhs1, rhs2); 2564*e4b17023SJohn Marino update_stmt (stmt); 2565*e4b17023SJohn Marino } 2566*e4b17023SJohn Marino 2567*e4b17023SJohn Marino /* Recursively linearize a binary expression that is the RHS of STMT. 2568*e4b17023SJohn Marino Place the operands of the expression tree in the vector named OPS. */ 2569*e4b17023SJohn Marino 2570*e4b17023SJohn Marino static void 2571*e4b17023SJohn Marino linearize_expr_tree (VEC(operand_entry_t, heap) **ops, gimple stmt, 2572*e4b17023SJohn Marino bool is_associative, bool set_visited) 2573*e4b17023SJohn Marino { 2574*e4b17023SJohn Marino tree binlhs = gimple_assign_rhs1 (stmt); 2575*e4b17023SJohn Marino tree binrhs = gimple_assign_rhs2 (stmt); 2576*e4b17023SJohn Marino gimple binlhsdef, binrhsdef; 2577*e4b17023SJohn Marino bool binlhsisreassoc = false; 2578*e4b17023SJohn Marino bool binrhsisreassoc = false; 2579*e4b17023SJohn Marino enum tree_code rhscode = gimple_assign_rhs_code (stmt); 2580*e4b17023SJohn Marino struct loop *loop = loop_containing_stmt (stmt); 2581*e4b17023SJohn Marino 2582*e4b17023SJohn Marino if (set_visited) 2583*e4b17023SJohn Marino gimple_set_visited (stmt, true); 2584*e4b17023SJohn Marino 2585*e4b17023SJohn Marino if (TREE_CODE (binlhs) == SSA_NAME) 2586*e4b17023SJohn Marino { 2587*e4b17023SJohn Marino binlhsdef = SSA_NAME_DEF_STMT (binlhs); 2588*e4b17023SJohn Marino binlhsisreassoc = (is_reassociable_op (binlhsdef, rhscode, loop) 2589*e4b17023SJohn Marino && !stmt_could_throw_p (binlhsdef)); 2590*e4b17023SJohn Marino } 2591*e4b17023SJohn Marino 2592*e4b17023SJohn Marino if (TREE_CODE (binrhs) == SSA_NAME) 2593*e4b17023SJohn Marino { 2594*e4b17023SJohn Marino binrhsdef = SSA_NAME_DEF_STMT (binrhs); 2595*e4b17023SJohn Marino binrhsisreassoc = (is_reassociable_op (binrhsdef, rhscode, loop) 2596*e4b17023SJohn Marino && !stmt_could_throw_p (binrhsdef)); 2597*e4b17023SJohn Marino } 2598*e4b17023SJohn Marino 2599*e4b17023SJohn Marino /* If the LHS is not reassociable, but the RHS is, we need to swap 2600*e4b17023SJohn Marino them. If neither is reassociable, there is nothing we can do, so 2601*e4b17023SJohn Marino just put them in the ops vector. If the LHS is reassociable, 2602*e4b17023SJohn Marino linearize it. If both are reassociable, then linearize the RHS 2603*e4b17023SJohn Marino and the LHS. */ 2604*e4b17023SJohn Marino 2605*e4b17023SJohn Marino if (!binlhsisreassoc) 2606*e4b17023SJohn Marino { 2607*e4b17023SJohn Marino tree temp; 2608*e4b17023SJohn Marino 2609*e4b17023SJohn Marino /* If this is not a associative operation like division, give up. */ 2610*e4b17023SJohn Marino if (!is_associative) 2611*e4b17023SJohn Marino { 2612*e4b17023SJohn Marino add_to_ops_vec (ops, binrhs); 2613*e4b17023SJohn Marino return; 2614*e4b17023SJohn Marino } 2615*e4b17023SJohn Marino 2616*e4b17023SJohn Marino if (!binrhsisreassoc) 2617*e4b17023SJohn Marino { 2618*e4b17023SJohn Marino add_to_ops_vec (ops, binrhs); 2619*e4b17023SJohn Marino add_to_ops_vec (ops, binlhs); 2620*e4b17023SJohn Marino return; 2621*e4b17023SJohn Marino } 2622*e4b17023SJohn Marino 2623*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2624*e4b17023SJohn Marino { 2625*e4b17023SJohn Marino fprintf (dump_file, "swapping operands of "); 2626*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2627*e4b17023SJohn Marino } 2628*e4b17023SJohn Marino 2629*e4b17023SJohn Marino swap_tree_operands (stmt, 2630*e4b17023SJohn Marino gimple_assign_rhs1_ptr (stmt), 2631*e4b17023SJohn Marino gimple_assign_rhs2_ptr (stmt)); 2632*e4b17023SJohn Marino update_stmt (stmt); 2633*e4b17023SJohn Marino 2634*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2635*e4b17023SJohn Marino { 2636*e4b17023SJohn Marino fprintf (dump_file, " is now "); 2637*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2638*e4b17023SJohn Marino } 2639*e4b17023SJohn Marino 2640*e4b17023SJohn Marino /* We want to make it so the lhs is always the reassociative op, 2641*e4b17023SJohn Marino so swap. */ 2642*e4b17023SJohn Marino temp = binlhs; 2643*e4b17023SJohn Marino binlhs = binrhs; 2644*e4b17023SJohn Marino binrhs = temp; 2645*e4b17023SJohn Marino } 2646*e4b17023SJohn Marino else if (binrhsisreassoc) 2647*e4b17023SJohn Marino { 2648*e4b17023SJohn Marino linearize_expr (stmt); 2649*e4b17023SJohn Marino binlhs = gimple_assign_rhs1 (stmt); 2650*e4b17023SJohn Marino binrhs = gimple_assign_rhs2 (stmt); 2651*e4b17023SJohn Marino } 2652*e4b17023SJohn Marino 2653*e4b17023SJohn Marino gcc_assert (TREE_CODE (binrhs) != SSA_NAME 2654*e4b17023SJohn Marino || !is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), 2655*e4b17023SJohn Marino rhscode, loop)); 2656*e4b17023SJohn Marino linearize_expr_tree (ops, SSA_NAME_DEF_STMT (binlhs), 2657*e4b17023SJohn Marino is_associative, set_visited); 2658*e4b17023SJohn Marino add_to_ops_vec (ops, binrhs); 2659*e4b17023SJohn Marino } 2660*e4b17023SJohn Marino 2661*e4b17023SJohn Marino /* Repropagate the negates back into subtracts, since no other pass 2662*e4b17023SJohn Marino currently does it. */ 2663*e4b17023SJohn Marino 2664*e4b17023SJohn Marino static void 2665*e4b17023SJohn Marino repropagate_negates (void) 2666*e4b17023SJohn Marino { 2667*e4b17023SJohn Marino unsigned int i = 0; 2668*e4b17023SJohn Marino tree negate; 2669*e4b17023SJohn Marino 2670*e4b17023SJohn Marino FOR_EACH_VEC_ELT (tree, plus_negates, i, negate) 2671*e4b17023SJohn Marino { 2672*e4b17023SJohn Marino gimple user = get_single_immediate_use (negate); 2673*e4b17023SJohn Marino 2674*e4b17023SJohn Marino if (!user || !is_gimple_assign (user)) 2675*e4b17023SJohn Marino continue; 2676*e4b17023SJohn Marino 2677*e4b17023SJohn Marino /* The negate operand can be either operand of a PLUS_EXPR 2678*e4b17023SJohn Marino (it can be the LHS if the RHS is a constant for example). 2679*e4b17023SJohn Marino 2680*e4b17023SJohn Marino Force the negate operand to the RHS of the PLUS_EXPR, then 2681*e4b17023SJohn Marino transform the PLUS_EXPR into a MINUS_EXPR. */ 2682*e4b17023SJohn Marino if (gimple_assign_rhs_code (user) == PLUS_EXPR) 2683*e4b17023SJohn Marino { 2684*e4b17023SJohn Marino /* If the negated operand appears on the LHS of the 2685*e4b17023SJohn Marino PLUS_EXPR, exchange the operands of the PLUS_EXPR 2686*e4b17023SJohn Marino to force the negated operand to the RHS of the PLUS_EXPR. */ 2687*e4b17023SJohn Marino if (gimple_assign_rhs1 (user) == negate) 2688*e4b17023SJohn Marino { 2689*e4b17023SJohn Marino swap_tree_operands (user, 2690*e4b17023SJohn Marino gimple_assign_rhs1_ptr (user), 2691*e4b17023SJohn Marino gimple_assign_rhs2_ptr (user)); 2692*e4b17023SJohn Marino } 2693*e4b17023SJohn Marino 2694*e4b17023SJohn Marino /* Now transform the PLUS_EXPR into a MINUS_EXPR and replace 2695*e4b17023SJohn Marino the RHS of the PLUS_EXPR with the operand of the NEGATE_EXPR. */ 2696*e4b17023SJohn Marino if (gimple_assign_rhs2 (user) == negate) 2697*e4b17023SJohn Marino { 2698*e4b17023SJohn Marino tree rhs1 = gimple_assign_rhs1 (user); 2699*e4b17023SJohn Marino tree rhs2 = get_unary_op (negate, NEGATE_EXPR); 2700*e4b17023SJohn Marino gimple_stmt_iterator gsi = gsi_for_stmt (user); 2701*e4b17023SJohn Marino gimple_assign_set_rhs_with_ops (&gsi, MINUS_EXPR, rhs1, rhs2); 2702*e4b17023SJohn Marino update_stmt (user); 2703*e4b17023SJohn Marino } 2704*e4b17023SJohn Marino } 2705*e4b17023SJohn Marino else if (gimple_assign_rhs_code (user) == MINUS_EXPR) 2706*e4b17023SJohn Marino { 2707*e4b17023SJohn Marino if (gimple_assign_rhs1 (user) == negate) 2708*e4b17023SJohn Marino { 2709*e4b17023SJohn Marino /* We have 2710*e4b17023SJohn Marino x = -a 2711*e4b17023SJohn Marino y = x - b 2712*e4b17023SJohn Marino which we transform into 2713*e4b17023SJohn Marino x = a + b 2714*e4b17023SJohn Marino y = -x . 2715*e4b17023SJohn Marino This pushes down the negate which we possibly can merge 2716*e4b17023SJohn Marino into some other operation, hence insert it into the 2717*e4b17023SJohn Marino plus_negates vector. */ 2718*e4b17023SJohn Marino gimple feed = SSA_NAME_DEF_STMT (negate); 2719*e4b17023SJohn Marino tree a = gimple_assign_rhs1 (feed); 2720*e4b17023SJohn Marino tree rhs2 = gimple_assign_rhs2 (user); 2721*e4b17023SJohn Marino gimple_stmt_iterator gsi = gsi_for_stmt (feed), gsi2; 2722*e4b17023SJohn Marino gimple_replace_lhs (feed, negate); 2723*e4b17023SJohn Marino gimple_assign_set_rhs_with_ops (&gsi, PLUS_EXPR, a, rhs2); 2724*e4b17023SJohn Marino update_stmt (gsi_stmt (gsi)); 2725*e4b17023SJohn Marino gsi2 = gsi_for_stmt (user); 2726*e4b17023SJohn Marino gimple_assign_set_rhs_with_ops (&gsi2, NEGATE_EXPR, negate, NULL); 2727*e4b17023SJohn Marino update_stmt (gsi_stmt (gsi2)); 2728*e4b17023SJohn Marino gsi_move_before (&gsi, &gsi2); 2729*e4b17023SJohn Marino VEC_safe_push (tree, heap, plus_negates, 2730*e4b17023SJohn Marino gimple_assign_lhs (gsi_stmt (gsi2))); 2731*e4b17023SJohn Marino } 2732*e4b17023SJohn Marino else 2733*e4b17023SJohn Marino { 2734*e4b17023SJohn Marino /* Transform "x = -a; y = b - x" into "y = b + a", getting 2735*e4b17023SJohn Marino rid of one operation. */ 2736*e4b17023SJohn Marino gimple feed = SSA_NAME_DEF_STMT (negate); 2737*e4b17023SJohn Marino tree a = gimple_assign_rhs1 (feed); 2738*e4b17023SJohn Marino tree rhs1 = gimple_assign_rhs1 (user); 2739*e4b17023SJohn Marino gimple_stmt_iterator gsi = gsi_for_stmt (user); 2740*e4b17023SJohn Marino gimple_assign_set_rhs_with_ops (&gsi, PLUS_EXPR, rhs1, a); 2741*e4b17023SJohn Marino update_stmt (gsi_stmt (gsi)); 2742*e4b17023SJohn Marino } 2743*e4b17023SJohn Marino } 2744*e4b17023SJohn Marino } 2745*e4b17023SJohn Marino } 2746*e4b17023SJohn Marino 2747*e4b17023SJohn Marino /* Returns true if OP is of a type for which we can do reassociation. 2748*e4b17023SJohn Marino That is for integral or non-saturating fixed-point types, and for 2749*e4b17023SJohn Marino floating point type when associative-math is enabled. */ 2750*e4b17023SJohn Marino 2751*e4b17023SJohn Marino static bool 2752*e4b17023SJohn Marino can_reassociate_p (tree op) 2753*e4b17023SJohn Marino { 2754*e4b17023SJohn Marino tree type = TREE_TYPE (op); 2755*e4b17023SJohn Marino if ((INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)) 2756*e4b17023SJohn Marino || NON_SAT_FIXED_POINT_TYPE_P (type) 2757*e4b17023SJohn Marino || (flag_associative_math && FLOAT_TYPE_P (type))) 2758*e4b17023SJohn Marino return true; 2759*e4b17023SJohn Marino return false; 2760*e4b17023SJohn Marino } 2761*e4b17023SJohn Marino 2762*e4b17023SJohn Marino /* Break up subtract operations in block BB. 2763*e4b17023SJohn Marino 2764*e4b17023SJohn Marino We do this top down because we don't know whether the subtract is 2765*e4b17023SJohn Marino part of a possible chain of reassociation except at the top. 2766*e4b17023SJohn Marino 2767*e4b17023SJohn Marino IE given 2768*e4b17023SJohn Marino d = f + g 2769*e4b17023SJohn Marino c = a + e 2770*e4b17023SJohn Marino b = c - d 2771*e4b17023SJohn Marino q = b - r 2772*e4b17023SJohn Marino k = t - q 2773*e4b17023SJohn Marino 2774*e4b17023SJohn Marino we want to break up k = t - q, but we won't until we've transformed q 2775*e4b17023SJohn Marino = b - r, which won't be broken up until we transform b = c - d. 2776*e4b17023SJohn Marino 2777*e4b17023SJohn Marino En passant, clear the GIMPLE visited flag on every statement. */ 2778*e4b17023SJohn Marino 2779*e4b17023SJohn Marino static void 2780*e4b17023SJohn Marino break_up_subtract_bb (basic_block bb) 2781*e4b17023SJohn Marino { 2782*e4b17023SJohn Marino gimple_stmt_iterator gsi; 2783*e4b17023SJohn Marino basic_block son; 2784*e4b17023SJohn Marino 2785*e4b17023SJohn Marino for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 2786*e4b17023SJohn Marino { 2787*e4b17023SJohn Marino gimple stmt = gsi_stmt (gsi); 2788*e4b17023SJohn Marino gimple_set_visited (stmt, false); 2789*e4b17023SJohn Marino 2790*e4b17023SJohn Marino if (!is_gimple_assign (stmt) 2791*e4b17023SJohn Marino || !can_reassociate_p (gimple_assign_lhs (stmt))) 2792*e4b17023SJohn Marino continue; 2793*e4b17023SJohn Marino 2794*e4b17023SJohn Marino /* Look for simple gimple subtract operations. */ 2795*e4b17023SJohn Marino if (gimple_assign_rhs_code (stmt) == MINUS_EXPR) 2796*e4b17023SJohn Marino { 2797*e4b17023SJohn Marino if (!can_reassociate_p (gimple_assign_rhs1 (stmt)) 2798*e4b17023SJohn Marino || !can_reassociate_p (gimple_assign_rhs2 (stmt))) 2799*e4b17023SJohn Marino continue; 2800*e4b17023SJohn Marino 2801*e4b17023SJohn Marino /* Check for a subtract used only in an addition. If this 2802*e4b17023SJohn Marino is the case, transform it into add of a negate for better 2803*e4b17023SJohn Marino reassociation. IE transform C = A-B into C = A + -B if C 2804*e4b17023SJohn Marino is only used in an addition. */ 2805*e4b17023SJohn Marino if (should_break_up_subtract (stmt)) 2806*e4b17023SJohn Marino break_up_subtract (stmt, &gsi); 2807*e4b17023SJohn Marino } 2808*e4b17023SJohn Marino else if (gimple_assign_rhs_code (stmt) == NEGATE_EXPR 2809*e4b17023SJohn Marino && can_reassociate_p (gimple_assign_rhs1 (stmt))) 2810*e4b17023SJohn Marino VEC_safe_push (tree, heap, plus_negates, gimple_assign_lhs (stmt)); 2811*e4b17023SJohn Marino } 2812*e4b17023SJohn Marino for (son = first_dom_son (CDI_DOMINATORS, bb); 2813*e4b17023SJohn Marino son; 2814*e4b17023SJohn Marino son = next_dom_son (CDI_DOMINATORS, son)) 2815*e4b17023SJohn Marino break_up_subtract_bb (son); 2816*e4b17023SJohn Marino } 2817*e4b17023SJohn Marino 2818*e4b17023SJohn Marino /* Reassociate expressions in basic block BB and its post-dominator as 2819*e4b17023SJohn Marino children. */ 2820*e4b17023SJohn Marino 2821*e4b17023SJohn Marino static void 2822*e4b17023SJohn Marino reassociate_bb (basic_block bb) 2823*e4b17023SJohn Marino { 2824*e4b17023SJohn Marino gimple_stmt_iterator gsi; 2825*e4b17023SJohn Marino basic_block son; 2826*e4b17023SJohn Marino 2827*e4b17023SJohn Marino for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) 2828*e4b17023SJohn Marino { 2829*e4b17023SJohn Marino gimple stmt = gsi_stmt (gsi); 2830*e4b17023SJohn Marino 2831*e4b17023SJohn Marino if (is_gimple_assign (stmt) 2832*e4b17023SJohn Marino && !stmt_could_throw_p (stmt)) 2833*e4b17023SJohn Marino { 2834*e4b17023SJohn Marino tree lhs, rhs1, rhs2; 2835*e4b17023SJohn Marino enum tree_code rhs_code = gimple_assign_rhs_code (stmt); 2836*e4b17023SJohn Marino 2837*e4b17023SJohn Marino /* If this is not a gimple binary expression, there is 2838*e4b17023SJohn Marino nothing for us to do with it. */ 2839*e4b17023SJohn Marino if (get_gimple_rhs_class (rhs_code) != GIMPLE_BINARY_RHS) 2840*e4b17023SJohn Marino continue; 2841*e4b17023SJohn Marino 2842*e4b17023SJohn Marino /* If this was part of an already processed statement, 2843*e4b17023SJohn Marino we don't need to touch it again. */ 2844*e4b17023SJohn Marino if (gimple_visited_p (stmt)) 2845*e4b17023SJohn Marino { 2846*e4b17023SJohn Marino /* This statement might have become dead because of previous 2847*e4b17023SJohn Marino reassociations. */ 2848*e4b17023SJohn Marino if (has_zero_uses (gimple_get_lhs (stmt))) 2849*e4b17023SJohn Marino { 2850*e4b17023SJohn Marino gsi_remove (&gsi, true); 2851*e4b17023SJohn Marino release_defs (stmt); 2852*e4b17023SJohn Marino /* We might end up removing the last stmt above which 2853*e4b17023SJohn Marino places the iterator to the end of the sequence. 2854*e4b17023SJohn Marino Reset it to the last stmt in this case which might 2855*e4b17023SJohn Marino be the end of the sequence as well if we removed 2856*e4b17023SJohn Marino the last statement of the sequence. In which case 2857*e4b17023SJohn Marino we need to bail out. */ 2858*e4b17023SJohn Marino if (gsi_end_p (gsi)) 2859*e4b17023SJohn Marino { 2860*e4b17023SJohn Marino gsi = gsi_last_bb (bb); 2861*e4b17023SJohn Marino if (gsi_end_p (gsi)) 2862*e4b17023SJohn Marino break; 2863*e4b17023SJohn Marino } 2864*e4b17023SJohn Marino } 2865*e4b17023SJohn Marino continue; 2866*e4b17023SJohn Marino } 2867*e4b17023SJohn Marino 2868*e4b17023SJohn Marino lhs = gimple_assign_lhs (stmt); 2869*e4b17023SJohn Marino rhs1 = gimple_assign_rhs1 (stmt); 2870*e4b17023SJohn Marino rhs2 = gimple_assign_rhs2 (stmt); 2871*e4b17023SJohn Marino 2872*e4b17023SJohn Marino /* For non-bit or min/max operations we can't associate 2873*e4b17023SJohn Marino all types. Verify that here. */ 2874*e4b17023SJohn Marino if (rhs_code != BIT_IOR_EXPR 2875*e4b17023SJohn Marino && rhs_code != BIT_AND_EXPR 2876*e4b17023SJohn Marino && rhs_code != BIT_XOR_EXPR 2877*e4b17023SJohn Marino && rhs_code != MIN_EXPR 2878*e4b17023SJohn Marino && rhs_code != MAX_EXPR 2879*e4b17023SJohn Marino && (!can_reassociate_p (lhs) 2880*e4b17023SJohn Marino || !can_reassociate_p (rhs1) 2881*e4b17023SJohn Marino || !can_reassociate_p (rhs2))) 2882*e4b17023SJohn Marino continue; 2883*e4b17023SJohn Marino 2884*e4b17023SJohn Marino if (associative_tree_code (rhs_code)) 2885*e4b17023SJohn Marino { 2886*e4b17023SJohn Marino VEC(operand_entry_t, heap) *ops = NULL; 2887*e4b17023SJohn Marino 2888*e4b17023SJohn Marino /* There may be no immediate uses left by the time we 2889*e4b17023SJohn Marino get here because we may have eliminated them all. */ 2890*e4b17023SJohn Marino if (TREE_CODE (lhs) == SSA_NAME && has_zero_uses (lhs)) 2891*e4b17023SJohn Marino continue; 2892*e4b17023SJohn Marino 2893*e4b17023SJohn Marino gimple_set_visited (stmt, true); 2894*e4b17023SJohn Marino linearize_expr_tree (&ops, stmt, true, true); 2895*e4b17023SJohn Marino VEC_qsort (operand_entry_t, ops, sort_by_operand_rank); 2896*e4b17023SJohn Marino optimize_ops_list (rhs_code, &ops); 2897*e4b17023SJohn Marino if (undistribute_ops_list (rhs_code, &ops, 2898*e4b17023SJohn Marino loop_containing_stmt (stmt))) 2899*e4b17023SJohn Marino { 2900*e4b17023SJohn Marino VEC_qsort (operand_entry_t, ops, sort_by_operand_rank); 2901*e4b17023SJohn Marino optimize_ops_list (rhs_code, &ops); 2902*e4b17023SJohn Marino } 2903*e4b17023SJohn Marino 2904*e4b17023SJohn Marino if (rhs_code == BIT_IOR_EXPR || rhs_code == BIT_AND_EXPR) 2905*e4b17023SJohn Marino optimize_range_tests (rhs_code, &ops); 2906*e4b17023SJohn Marino 2907*e4b17023SJohn Marino if (VEC_length (operand_entry_t, ops) == 1) 2908*e4b17023SJohn Marino { 2909*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2910*e4b17023SJohn Marino { 2911*e4b17023SJohn Marino fprintf (dump_file, "Transforming "); 2912*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2913*e4b17023SJohn Marino } 2914*e4b17023SJohn Marino 2915*e4b17023SJohn Marino rhs1 = gimple_assign_rhs1 (stmt); 2916*e4b17023SJohn Marino gimple_assign_set_rhs_from_tree (&gsi, 2917*e4b17023SJohn Marino VEC_last (operand_entry_t, 2918*e4b17023SJohn Marino ops)->op); 2919*e4b17023SJohn Marino update_stmt (stmt); 2920*e4b17023SJohn Marino remove_visited_stmt_chain (rhs1); 2921*e4b17023SJohn Marino 2922*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2923*e4b17023SJohn Marino { 2924*e4b17023SJohn Marino fprintf (dump_file, " into "); 2925*e4b17023SJohn Marino print_gimple_stmt (dump_file, stmt, 0, 0); 2926*e4b17023SJohn Marino } 2927*e4b17023SJohn Marino } 2928*e4b17023SJohn Marino else 2929*e4b17023SJohn Marino { 2930*e4b17023SJohn Marino enum machine_mode mode = TYPE_MODE (TREE_TYPE (lhs)); 2931*e4b17023SJohn Marino int ops_num = VEC_length (operand_entry_t, ops); 2932*e4b17023SJohn Marino int width = get_reassociation_width (ops_num, rhs_code, mode); 2933*e4b17023SJohn Marino 2934*e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS)) 2935*e4b17023SJohn Marino fprintf (dump_file, 2936*e4b17023SJohn Marino "Width = %d was chosen for reassociation\n", width); 2937*e4b17023SJohn Marino 2938*e4b17023SJohn Marino if (width > 1 2939*e4b17023SJohn Marino && VEC_length (operand_entry_t, ops) > 3) 2940*e4b17023SJohn Marino rewrite_expr_tree_parallel (stmt, width, ops); 2941*e4b17023SJohn Marino else 2942*e4b17023SJohn Marino rewrite_expr_tree (stmt, 0, ops, false); 2943*e4b17023SJohn Marino } 2944*e4b17023SJohn Marino 2945*e4b17023SJohn Marino VEC_free (operand_entry_t, heap, ops); 2946*e4b17023SJohn Marino } 2947*e4b17023SJohn Marino } 2948*e4b17023SJohn Marino } 2949*e4b17023SJohn Marino for (son = first_dom_son (CDI_POST_DOMINATORS, bb); 2950*e4b17023SJohn Marino son; 2951*e4b17023SJohn Marino son = next_dom_son (CDI_POST_DOMINATORS, son)) 2952*e4b17023SJohn Marino reassociate_bb (son); 2953*e4b17023SJohn Marino } 2954*e4b17023SJohn Marino 2955*e4b17023SJohn Marino void dump_ops_vector (FILE *file, VEC (operand_entry_t, heap) *ops); 2956*e4b17023SJohn Marino void debug_ops_vector (VEC (operand_entry_t, heap) *ops); 2957*e4b17023SJohn Marino 2958*e4b17023SJohn Marino /* Dump the operand entry vector OPS to FILE. */ 2959*e4b17023SJohn Marino 2960*e4b17023SJohn Marino void 2961*e4b17023SJohn Marino dump_ops_vector (FILE *file, VEC (operand_entry_t, heap) *ops) 2962*e4b17023SJohn Marino { 2963*e4b17023SJohn Marino operand_entry_t oe; 2964*e4b17023SJohn Marino unsigned int i; 2965*e4b17023SJohn Marino 2966*e4b17023SJohn Marino FOR_EACH_VEC_ELT (operand_entry_t, ops, i, oe) 2967*e4b17023SJohn Marino { 2968*e4b17023SJohn Marino fprintf (file, "Op %d -> rank: %d, tree: ", i, oe->rank); 2969*e4b17023SJohn Marino print_generic_expr (file, oe->op, 0); 2970*e4b17023SJohn Marino } 2971*e4b17023SJohn Marino } 2972*e4b17023SJohn Marino 2973*e4b17023SJohn Marino /* Dump the operand entry vector OPS to STDERR. */ 2974*e4b17023SJohn Marino 2975*e4b17023SJohn Marino DEBUG_FUNCTION void 2976*e4b17023SJohn Marino debug_ops_vector (VEC (operand_entry_t, heap) *ops) 2977*e4b17023SJohn Marino { 2978*e4b17023SJohn Marino dump_ops_vector (stderr, ops); 2979*e4b17023SJohn Marino } 2980*e4b17023SJohn Marino 2981*e4b17023SJohn Marino static void 2982*e4b17023SJohn Marino do_reassoc (void) 2983*e4b17023SJohn Marino { 2984*e4b17023SJohn Marino break_up_subtract_bb (ENTRY_BLOCK_PTR); 2985*e4b17023SJohn Marino reassociate_bb (EXIT_BLOCK_PTR); 2986*e4b17023SJohn Marino } 2987*e4b17023SJohn Marino 2988*e4b17023SJohn Marino /* Initialize the reassociation pass. */ 2989*e4b17023SJohn Marino 2990*e4b17023SJohn Marino static void 2991*e4b17023SJohn Marino init_reassoc (void) 2992*e4b17023SJohn Marino { 2993*e4b17023SJohn Marino int i; 2994*e4b17023SJohn Marino long rank = 2; 2995*e4b17023SJohn Marino tree param; 2996*e4b17023SJohn Marino int *bbs = XNEWVEC (int, last_basic_block + 1); 2997*e4b17023SJohn Marino 2998*e4b17023SJohn Marino /* Find the loops, so that we can prevent moving calculations in 2999*e4b17023SJohn Marino them. */ 3000*e4b17023SJohn Marino loop_optimizer_init (AVOID_CFG_MODIFICATIONS); 3001*e4b17023SJohn Marino 3002*e4b17023SJohn Marino memset (&reassociate_stats, 0, sizeof (reassociate_stats)); 3003*e4b17023SJohn Marino 3004*e4b17023SJohn Marino operand_entry_pool = create_alloc_pool ("operand entry pool", 3005*e4b17023SJohn Marino sizeof (struct operand_entry), 30); 3006*e4b17023SJohn Marino next_operand_entry_id = 0; 3007*e4b17023SJohn Marino 3008*e4b17023SJohn Marino /* Reverse RPO (Reverse Post Order) will give us something where 3009*e4b17023SJohn Marino deeper loops come later. */ 3010*e4b17023SJohn Marino pre_and_rev_post_order_compute (NULL, bbs, false); 3011*e4b17023SJohn Marino bb_rank = XCNEWVEC (long, last_basic_block + 1); 3012*e4b17023SJohn Marino operand_rank = pointer_map_create (); 3013*e4b17023SJohn Marino 3014*e4b17023SJohn Marino /* Give each argument a distinct rank. */ 3015*e4b17023SJohn Marino for (param = DECL_ARGUMENTS (current_function_decl); 3016*e4b17023SJohn Marino param; 3017*e4b17023SJohn Marino param = DECL_CHAIN (param)) 3018*e4b17023SJohn Marino { 3019*e4b17023SJohn Marino if (gimple_default_def (cfun, param) != NULL) 3020*e4b17023SJohn Marino { 3021*e4b17023SJohn Marino tree def = gimple_default_def (cfun, param); 3022*e4b17023SJohn Marino insert_operand_rank (def, ++rank); 3023*e4b17023SJohn Marino } 3024*e4b17023SJohn Marino } 3025*e4b17023SJohn Marino 3026*e4b17023SJohn Marino /* Give the chain decl a distinct rank. */ 3027*e4b17023SJohn Marino if (cfun->static_chain_decl != NULL) 3028*e4b17023SJohn Marino { 3029*e4b17023SJohn Marino tree def = gimple_default_def (cfun, cfun->static_chain_decl); 3030*e4b17023SJohn Marino if (def != NULL) 3031*e4b17023SJohn Marino insert_operand_rank (def, ++rank); 3032*e4b17023SJohn Marino } 3033*e4b17023SJohn Marino 3034*e4b17023SJohn Marino /* Set up rank for each BB */ 3035*e4b17023SJohn Marino for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++) 3036*e4b17023SJohn Marino bb_rank[bbs[i]] = ++rank << 16; 3037*e4b17023SJohn Marino 3038*e4b17023SJohn Marino free (bbs); 3039*e4b17023SJohn Marino calculate_dominance_info (CDI_POST_DOMINATORS); 3040*e4b17023SJohn Marino plus_negates = NULL; 3041*e4b17023SJohn Marino } 3042*e4b17023SJohn Marino 3043*e4b17023SJohn Marino /* Cleanup after the reassociation pass, and print stats if 3044*e4b17023SJohn Marino requested. */ 3045*e4b17023SJohn Marino 3046*e4b17023SJohn Marino static void 3047*e4b17023SJohn Marino fini_reassoc (void) 3048*e4b17023SJohn Marino { 3049*e4b17023SJohn Marino statistics_counter_event (cfun, "Linearized", 3050*e4b17023SJohn Marino reassociate_stats.linearized); 3051*e4b17023SJohn Marino statistics_counter_event (cfun, "Constants eliminated", 3052*e4b17023SJohn Marino reassociate_stats.constants_eliminated); 3053*e4b17023SJohn Marino statistics_counter_event (cfun, "Ops eliminated", 3054*e4b17023SJohn Marino reassociate_stats.ops_eliminated); 3055*e4b17023SJohn Marino statistics_counter_event (cfun, "Statements rewritten", 3056*e4b17023SJohn Marino reassociate_stats.rewritten); 3057*e4b17023SJohn Marino 3058*e4b17023SJohn Marino pointer_map_destroy (operand_rank); 3059*e4b17023SJohn Marino free_alloc_pool (operand_entry_pool); 3060*e4b17023SJohn Marino free (bb_rank); 3061*e4b17023SJohn Marino VEC_free (tree, heap, plus_negates); 3062*e4b17023SJohn Marino free_dominance_info (CDI_POST_DOMINATORS); 3063*e4b17023SJohn Marino loop_optimizer_finalize (); 3064*e4b17023SJohn Marino } 3065*e4b17023SJohn Marino 3066*e4b17023SJohn Marino /* Gate and execute functions for Reassociation. */ 3067*e4b17023SJohn Marino 3068*e4b17023SJohn Marino static unsigned int 3069*e4b17023SJohn Marino execute_reassoc (void) 3070*e4b17023SJohn Marino { 3071*e4b17023SJohn Marino init_reassoc (); 3072*e4b17023SJohn Marino 3073*e4b17023SJohn Marino do_reassoc (); 3074*e4b17023SJohn Marino repropagate_negates (); 3075*e4b17023SJohn Marino 3076*e4b17023SJohn Marino fini_reassoc (); 3077*e4b17023SJohn Marino return 0; 3078*e4b17023SJohn Marino } 3079*e4b17023SJohn Marino 3080*e4b17023SJohn Marino static bool 3081*e4b17023SJohn Marino gate_tree_ssa_reassoc (void) 3082*e4b17023SJohn Marino { 3083*e4b17023SJohn Marino return flag_tree_reassoc != 0; 3084*e4b17023SJohn Marino } 3085*e4b17023SJohn Marino 3086*e4b17023SJohn Marino struct gimple_opt_pass pass_reassoc = 3087*e4b17023SJohn Marino { 3088*e4b17023SJohn Marino { 3089*e4b17023SJohn Marino GIMPLE_PASS, 3090*e4b17023SJohn Marino "reassoc", /* name */ 3091*e4b17023SJohn Marino gate_tree_ssa_reassoc, /* gate */ 3092*e4b17023SJohn Marino execute_reassoc, /* execute */ 3093*e4b17023SJohn Marino NULL, /* sub */ 3094*e4b17023SJohn Marino NULL, /* next */ 3095*e4b17023SJohn Marino 0, /* static_pass_number */ 3096*e4b17023SJohn Marino TV_TREE_REASSOC, /* tv_id */ 3097*e4b17023SJohn Marino PROP_cfg | PROP_ssa, /* properties_required */ 3098*e4b17023SJohn Marino 0, /* properties_provided */ 3099*e4b17023SJohn Marino 0, /* properties_destroyed */ 3100*e4b17023SJohn Marino 0, /* todo_flags_start */ 3101*e4b17023SJohn Marino TODO_verify_ssa 3102*e4b17023SJohn Marino | TODO_verify_flow 3103*e4b17023SJohn Marino | TODO_ggc_collect /* todo_flags_finish */ 3104*e4b17023SJohn Marino } 3105*e4b17023SJohn Marino }; 3106